Compare commits

..

107 Commits

Author SHA1 Message Date
Simon Ogorodnik
70d275e8a4 Suppress kotlin.reflect.jvm.internal 2017-11-25 01:51:06 +03:00
Simon Ogorodnik
61426063de Suppress docs for org.junit.Test header in kotlin.test 2017-11-23 16:12:08 +03:00
Simon Ogorodnik
7adc1abb2e Add module docs for kotlin.test 2017-11-22 16:13:46 +03:00
Simon Ogorodnik
7c9a1694ac Add stdlib to kotlin.test docs classpath 2017-11-21 21:40:10 +03:00
Simon Ogorodnik
0ecb78eba8 Use correct task to build builtins.jar 2017-11-21 21:01:35 +03:00
Simon Ogorodnik
f55601a84d Compile stdlib builtins ant pass it to Dokka
We need builtins to allow linking to type-aliased classes
such as Exception
2017-11-21 20:46:19 +03:00
Simon Ogorodnik
f6e291e642 Make local dokka run easier 2017-11-21 20:43:34 +03:00
Simon Ogorodnik
a0f995827c makeurl just before use, to prevent file not found 2017-11-21 20:42:02 +03:00
Simon Ogorodnik
ea9868bd4c Suppress whole org.w3c 2017-11-21 01:07:41 +03:00
Simon Ogorodnik
c9e884edd5 Suppress undocumented warnings for third-party js packages 2017-11-21 00:58:18 +03:00
Simon Ogorodnik
e0e5656f12 Change source path for jre7/jre8 2017-11-21 00:43:46 +03:00
Simon Ogorodnik
7971a396f0 Use makeurl to create package-list URL in ant 2017-11-21 00:30:33 +03:00
Ilya Gorbunov
12c0d3b45a List all source folders instead of project folder
(cherry picked from commit 824ec40)
2017-11-20 18:48:21 +03:00
Ilya Gorbunov
33ab5fe64a Docs: run gradle project and wrapper from the root dir
Build docs for kotlin-stdlib-jdk7/8 instead of jre7/8.

(cherry picked from commit 32e748e)
2017-11-20 18:48:11 +03:00
Simon Ogorodnik
f0521a5bd4 Minor: prepare for documentation generation
(cherry picked from commit df61908)
2017-11-20 18:48:02 +03:00
Alexey Tsvetkov
3638611bf6 Avoid deserializing .kotlin_module as class proto
#KT-20184 fixed
2017-11-20 11:06:21 +03:00
Ilya Chernikov
148d4e459f Add kotlin-annotation-processing-embeddable, publish base kapt3 as kotlion-annotation-processing 2017-11-17 17:50:33 +01:00
Ilya Gorbunov
0110bff083 Introduce deployRepo parameter to override deploy-repo set by teamcity
Currently it isn't possible to do that from command line.
2017-11-09 20:52:53 +03:00
Sergey Igushkin
84d71446f2 Fix missing sourcesJar & javadocJar in kotlin-annotations-android 2017-11-09 20:20:58 +03:00
Ilya Gorbunov
235f60e56f Fix intellij-community revision JFlex is downloaded from
Because it was removed in master

(cherry picked from commit e801390)
2017-11-09 18:09:53 +03:00
Sergey Igushkin
962cc51c2e Update ChangeLog.md 2017-11-09 14:52:27 +03:00
Ilya Gorbunov
25483ca286 Write deployVersion into build.txt (for 1.1.60) 2017-11-08 17:17:35 +03:00
Simon Ogorodnik
d63b7ade7e Improve diagnosticMissingPackageFragment reporting
Single execution path to report missing package fragment problems

Split failures on PluginDeclarationProviderFactory site by
known reasons to improve exception analysis

(cherry picked from commit 339d06d)
2017-11-07 16:29:05 +03:00
Nikolay Krasko
1a898e1f46 Increase stub version because of change in overload sorting
See commit f197f36e23
2017-11-07 15:57:08 +03:00
Nikolay Krasko
9674dc6279 Don't resort deserialized descriptors based on renderer, preserve proto order
Use only names and types for sorting. Otherwise if deserialized descriptor
is rendered different from origin we might get Psi-Stub mismatch error.

Use the original proto order for declarations with same name and kind.

 #KT-20782 Fixed
 #EA-109887 Fixed
2017-11-07 15:57:07 +03:00
Mikhail Glukhikh
f7906ed7ee Fix problem with mutable map in "simplifiable call chain"
So #KT-20315 Fixed

(cherry picked from commit 45c9be2)
2017-11-01 19:48:13 +03:00
Nikolay Krasko
461ebbc4cd Fix accessing nullable location() method 2017-10-30 20:49:15 +03:00
Dmitry Petrov
c4ceb5653a Fix issues with enum entry self-reference
Given a singleton class 'S' with possibly uninitialized static instance
(enum entry, interface companion object).
Such singleton can be referenced by name, or as an explicit or implicit
'this'.
For a given singleton class 'S' we
either use 'this@S' from context (local or captured),
or 'S' as a static instance.

Local or captured 'this@S' should be used if:
  - we are in the constructor for 'S',
    and corresponding instance is initialized
        by super or delegating constructor call;
  - we are in any other member of 'S' or any of its inner classes.

Otherwise, a static instance should be used.

(cherry picked from commit 28535a5)
2017-10-27 09:40:17 +03:00
Denis Zharkov
a9f3940e47 Fix incorrect UNINITIALIZED_ENUM_COMPANION diagnostic
#KT-20959 Fixed
2017-10-27 09:38:47 +03:00
Alexander Udalov
c12be9b54b Use ServiceLoader instead of IntelliJ extensions for DefaultErrorMessages
#KT-10473 Fixed

(cherry picked from commit 1a8be635b9)
2017-10-26 18:38:51 +02:00
Alexander Udalov
2472d1c1fd Do not use DefaultErrorMessages.Extension as IntelliJ extension in plugins
(cherry picked from commit 1c6dce3674)
2017-10-26 18:38:48 +02:00
Vyacheslav Gerasimov
47fe7aefcb Remove GradleProjectImportProvider and GradleProjectOpenProcessor 2017-10-26 19:11:42 +03:00
Sergey Igushkin
ad975b517e Update 1.1.60 changelog 2017-10-26 17:24:33 +03:00
Ilya Chernikov
31189f8270 Fix "base" jar and "public" jar tasks archive name conflict
fixes KT-20877

(cherry picked from commit caca7c6)
2017-10-25 14:20:46 +02:00
Alexey Tsvetkov
c8c4835d17 Perform non-IC build when JS lib is changed 2017-10-24 16:36:35 +03:00
Mikhail Zarechenskiy
c43fe9b9ff Provide no-arg constructors for common expected annotations in stdlib
This is needed because we treat `expect` classes as not having implicit default constructors (see more in KT-15522, f3344ec)

(cherry picked from commit 1845a87)
2017-10-24 16:35:00 +03:00
Dmitry Petrov
88c952902d Mark operands of POP2 as don't touch in unused expression elimination
Fixes KT-20879.

(cherry picked from commit f23dfdc)
2017-10-24 15:41:00 +03:00
Anton Bannykh
1b6f495014 JPS JS: fix friend path detection in projects imported from Gradle (KT-18963 fixed)
(cherry-picked from commit b2e53644a5)
2017-10-24 15:26:19 +03:00
Sergey Igushkin
3f9a068e5c Advance bootstrap to 1.1.60-eap-30 2017-10-24 15:17:09 +03:00
Alexey Andreev
bdd5310dce JS: several bugfixes in incremental compilation
1. Fix exported packages sometimes being mixed up
2. Fix metadata losing package fragments sometimes
3. Don't serialize empty packages to .meta.js
4. Preserve order of package fragments in .meta.js
5. In IC tests, compare textual representation of metadata rather
   than binary representation
2017-10-24 11:58:50 +03:00
Alexey Andreev
61e570279a Support generation of relative path in JS source maps in JPS builder
See KT-20820
2017-10-24 11:53:23 +03:00
Alexey Andreev
c61034191e JS: fix copying functions with default arguments across interfaces
Copy function to super interface first, then copy from interface
to class. Add interface set to JsClassModel for this purpose.

See KT-20625
2017-10-24 11:53:03 +03:00
Simon Ogorodnik
0bf6a37384 EA-105522, KT-20256: Fix TextRange.<init> "Invalid range specified"
Check when caret inside template, and don't try to create invalid
range then

 EA-105522 fixed
 #KT-20256 fixed

(cherry picked from commit cace662)
2017-10-23 21:39:19 +03:00
Nikolay Krasko
3e1482a869 Use CompilerPathsEx.getOutputPaths for getting the full list of output dirs (KT-20789)
CompilerPathsEx.getOutputPaths isn't using OrderEnumerationHandler extension
so far and works badly when delegating runnners to gradle is enabled.

 #KT-20789 Fixed
2017-10-20 21:24:17 +03:00
Nikolay Krasko
6757212e0f TypeDeclarationProvider should return null for irrelevant symbols
Otherwise other providers won't be checked.
2017-10-20 21:23:57 +03:00
Nikolay Krasko
70f3e1a53e Request path from URI before construction file 2017-10-20 21:23:36 +03:00
Denis Zharkov
cba7c848c2 Fix wrong nullability enhancement for annotated java.lang.Object type
Effectively, this commit drops cached value for j.l.Object type
This cache was introduced when types were immutable, but they
became mutable after starting reading top-level TYPE_USE annotations,
that lead to changing shared JAVA_LANG_OBJECT_CLASSIFIER_TYPE instance

 #KT-20826 Fixed
2017-10-20 19:11:39 +03:00
Anton Bannykh
63fbab77dd JS: add kotlin-test testCompile dependency to JS module generated by multiplatform wizard (KT-20346, KT-20831, KT-20832 fixed)
(cherry-picked from commit e90c914)
2017-10-20 18:46:24 +03:00
Sergey Igushkin
74567aaa43 Add 1.1.60 changelog 2017-10-19 21:12:51 +03:00
Alexey Tsvetkov
caa010f0ff Compile kotlin-android-extensions-runtime for JDK 1.6
(cherry picked from commit 8a3a4df)
2017-10-19 16:24:51 +03:00
Stanislav Erokhin
5f0b6a5fb6 Disable annotation processor for javac by default in whole project
(cherry picked from commit 0a2421d)

(cherry picked from commit 7a50511)
2017-10-19 16:24:04 +03:00
Sergey Igushkin
0341227552 Use runtimeJar configuration instead of default for plugin markers.
(cherry picked from commit d453a2f)

(cherry picked from commit fa2d276)
2017-10-19 16:23:28 +03:00
Ilya Chernikov
14099e8a66 Add compiler proguard rule for keeping ProgressManager used in webdemo
(cherry picked from commit 5284db8)
2017-10-19 14:16:28 +02:00
Sergey Igushkin
480768c841 Fix missing ReflectUtil, call the ctor through reflection manually.
(cherry picked from commit 0a80852)
2017-10-19 14:08:28 +02:00
Sergey Igushkin
82b033b85d Add android-extensions-compiler content to kotlin-android-extensions
(cherry picked from commit e94e62b)
2017-10-19 14:07:22 +02:00
Ilya Chernikov
6c73373f64 Fix dependencies rewriting and gradle integration tests after applying rewriting
(cherry picked from commit 431d47a)
2017-10-19 14:07:05 +02:00
Ilya Chernikov
1596622f60 Use rewriteDeps task on the projects with runtime dependency on embeddable compiler...
which are using shaded dependencies

(cherry picked from commit 050403d)
2017-10-19 14:05:22 +02:00
Ilya Chernikov
49d040886f Move embeddable compiler shading logic to buildSrc, implement rewriteDeps task
the task takes a jar an a shading task (like the one that creates embeddable
compiler) and rewrites jar's dependencies to the shaded ones according the
the shade task.

(cherry picked from commit fb70227)
2017-10-19 14:03:02 +02:00
Ilya Chernikov
8a41561b36 Remove original jar artifact from archives when adding a new one by runtimeJar tasks
(cherry picked from commit 5babf89)
2017-10-19 14:01:48 +02:00
Anton Bannykh
ea33a0aa6c JS: publish to NPM sourcemaps and *.kjsm files
(cherry-picked from commit 6d6ce7c)
2017-10-18 21:18:11 +03:00
Anton Bannykh
1729f175c1 JS: add ant tasks for publishing kotlin-test-js to NPM (KT-19682)
(cherry-picked from commit 2d3929e)
2017-10-18 21:16:42 +03:00
Ilya Gorbunov
83eb6dd000 Enable publishing for kotlin-annotations-android
(cherry picked from commit eaa3b3ccf0)
2017-10-17 21:03:38 +03:00
Ilya Gorbunov
fe60fb4a44 Do not pack build.txt into jars, leave it only in artifact zip bundles
(cherry picked from commit 13d6e96c2f)
2017-10-17 21:02:39 +03:00
Ilya Gorbunov
0c95783829 Remove maven poms that are no longer submodules of the main project
(cherry picked from commit 3bea095618)
2017-10-17 21:02:39 +03:00
Ilya Gorbunov
5b04b84e71 Fork java compiler to ensure forkOptions are used
(cherry picked from commit 341edc3f86)
2017-10-17 21:02:39 +03:00
Ilya Gorbunov
15f9fa7b03 Fix the obsolete form of -Xdump-declarations-to argument
(cherry picked from commit 93efc51)
2017-10-17 21:02:39 +03:00
Alexey Tsvetkov
52093f3fad Fix android extensions maven dependencies
`kotlin-android-extensions-runtime` and `kotlin-android-extensions-compiler`
had `com.google.android:android` as a provided dependency, but
during transition to Kotlin Gradle build the dependency was declared
as `runtime` instead of `compileOnly`.
2017-10-17 18:36:19 +03:00
Denis Zharkov
c3a6cb3ab4 Refine ClassDescriptor::isCommonFinalClass definition
Do not treat annotations as final classes as they are not final in Java

 #KT-20776 Fixed
2017-10-16 16:14:12 +03:00
Yan Zhulanow
ee36a19db5 Disable uninitialized object copying checks for Parcelable writeToParcel() to createFromParcel() 2017-10-13 16:37:57 +03:00
Yan Zhulanow
8e5026e6b1 Minor: Add dependency to android-extensions-runtime to get rid of compile errors in IDE 2017-10-13 16:37:51 +03:00
Yan Zhulanow
31f08c6ba5 Tests: Do not search for android-extensions-runtime in KOTLIN_PATH 2017-10-13 16:37:44 +03:00
Pavel V. Talanov
0a3f4b5be3 Scripts: Accept objects as DependenciesResolver implementations
Fixes DependenciesResolver.NoDependencies causing "missing constructor without parameters" warning
2017-10-12 19:25:07 +03:00
Ilya Chernikov
4e51e04e3c Add stdlib to gradle scripts classpath, since it is not included into compiler anymore
(cherry picked from commit 279126a)
2017-10-12 15:36:39 +02:00
Paul Merlin
5740163c92 Script template provider for settings.gradle.kts files
This commit introduces GradleSettingsKotlinDSLTemplateProvider and
registers it as Kotlin IntelliJ plugin extension.

(cherry picked from commit e911a1e)
2017-10-12 15:36:30 +02:00
Dmitry Petrov
0331627757 Build compiler, plugin & stdlib with constructor call normalization
Required as a workaround for Proguard bug
https://sourceforge.net/p/proguard/bugs/664/

When processing bytecode generated by Kotlin compiler for constructor
call with stack spilling during arguments evaluation, ProGuard performs
an equivalent transformation for the bytecode, but emits invalid stack
frame information.
In JVM 1.6, such invalid stack frames are ignored and re-evaluated by
JVM during bytecode verification.
In JVM 1.8, such invalid stack frames cause VerifyError.
2017-10-12 16:10:55 +03:00
Alexey Andreev
ac85c9d728 Fix Kotlin/JS compiler under JRE9
See KT-20653, KT-20650
2017-10-12 15:02:54 +03:00
Nikolay Krasko
95e8aa6c41 Revert old id for run configurations (KT-20621)
Currently there's no way for smooth IDs migration.

 #KT-20621 Fixed
2017-10-12 14:00:24 +03:00
Leonid Stashevsky
0132a54d22 Rename android-annotations -> kotlin-annotations-android
also rewrite it's buildscript in kts and add to compiler tests dependencies
2017-10-12 11:10:10 +03:00
Alexey Andreev
512c2da560 Enable test that now passes in JS 2017-10-12 11:02:37 +03:00
Alexey Andreev
0eb713920b Fix JS DCE removing reachable functions 2017-10-11 17:42:33 +03:00
Denis Zharkov
67c25aa6ab Add cache for declaration names in StubBasedPackageMemberDeclarationProvider
#KT-20683 Fixed
2017-10-10 18:37:40 +03:00
Denis Zharkov
ca0c2690a9 Optimize ConstraintSystemBuilderImpl::generateNewBound
Do not process the bound if it's just the same
This situation can actually happen in case of adding bound
containing type variable itself
2017-10-10 18:33:39 +03:00
Denis Zharkov
ac8ce070e8 Introduce cache for KotlinBuiltins::builtInClassesByName
There are a lot of places requesting nothing/any/.. instances
and just asking the scopes isn't very effecient:
see org.jetbrains.kotlin.builtins.KotlinBuiltIns#createPackage
having ChainedMemberScope and a `map` call
2017-10-10 18:33:39 +03:00
Denis Zharkov
0eeb47d8ff Do not create redundant temporary trace
It will be commited after use in any case
2017-10-10 18:33:39 +03:00
Denis Zharkov
2ddea32b37 Optimize subtyping for simple cases 2017-10-10 18:33:39 +03:00
Denis Zharkov
e5ae916fe5 Drop effectively unused parameter with default value 2017-10-10 18:33:39 +03:00
Denis Zharkov
f6be73cb3d Get rid of a couple of usages of simpleTypeWithNonTrivialMemberScope
The simple versions of KotlinTypeFactory::simpleType may lead
to smaller number of KotlinType instances
(defaultType from descriptor are used if there are no arguments)
2017-10-10 18:33:39 +03:00
Denis Zharkov
ea142d884f Rename KotlinTypeFactory::simpleType to simpleTypeWithNonTrivialMemberScope
To state it must be used only for limited number of cases
2017-10-10 18:33:39 +03:00
Denis Zharkov
080b4dccc9 Cache virtualFilePath for KtFile
Because of com.intellij.openapi.vfs.local.CoreLocalVirtualFile#getPath
that has a rather slow implementation calling String::replace on each call

At the same time this method gets called very frequently when
recording lookups
2017-10-10 18:33:39 +03:00
Denis Zharkov
dc40c34152 Optimize subtyping for case of objects identity
It may be rather frequent (e.g. in case of types without arguments or
for dispatch receiver parameters)
2017-10-10 18:33:39 +03:00
Denis Zharkov
97d648731a Add explicit fast path in TypeCheckerContext::anySupertype 2017-10-10 18:33:39 +03:00
Denis Zharkov
97b9e1c444 Optimize CandidateResolver::checkReceiver
- Do not calculate smart cast variants unless they're not necessary
- Avoid calling subtyping twice just to know if smart cast is necessary
  (now the needed info is contained in ReceiverSmartCastResult)
2017-10-10 18:33:39 +03:00
Denis Zharkov
71020fb690 Minor. Drop unused method 2017-10-10 18:33:39 +03:00
Denis Zharkov
83bdf55dda Inline TypeCheckerContext::anySupertype
This method is a hot spot, since it's may be called
several times during one isSubtypeOf call and it contains
two lambdas, so it's worth inlining it
2017-10-10 18:33:39 +03:00
Denis Zharkov
6528ced4b5 Use smaller default deque size for BFS over supertypes
The default value (16) seems to be rather big
2017-10-10 18:33:39 +03:00
Denis Zharkov
264107081f Minor. Get rid of redundant var
The lazyness here is redundant since SmartList doesn't make a lot of
harm, but at the same time `var` here leads to another
kotlin/jvm/internal/Ref$ObjectRef instance
2017-10-10 18:33:39 +03:00
Denis Zharkov
0f2ed5e570 Optimize type checking for common cases
- Type equality for simple constructors (no arguments)
- Subtyping on final classes
2017-10-10 18:33:39 +03:00
Denis Zharkov
8a664a0ac2 Minor. Move local functions as a private to class 2017-10-10 18:33:39 +03:00
Denis Zharkov
7cfc3ea46f Fix obviously wrong !is check in type checker 2017-10-10 18:33:39 +03:00
Mikhael Bogdanov
a30d946351 Write script descriptor type to ASM_TYPE slice
#KT-20707 Fixed

(cherry picked from commit a79c2bf)
2017-10-10 17:05:35 +02:00
Vyacheslav Gerasimov
0425afb061 Add name for GradleProjectImportProvider
#KT-20648 Fixed

(cherry picked from commit 62d0e4a)
2017-10-10 14:44:19 +03:00
Alexey Andreev
9ceb9e729a Fix compilation of JS stdlib
1. Don't import intrinsics when compiling stdlib, use declarations
   from current module instead
2. Add constructor with one argument to SourceFilePathResolver,
   to fix bootstrapping issues.
3. Pass correct source roots to compiler when building
   stdlib, since now we pass module root by default,
   while stdlib source roots are outside of module root.
2017-10-10 14:21:32 +03:00
Dmitry Petrov
5cf9937423 Provide configurable constructor call normalization
Three modes:

- 'disable' (default): normalize constructor calls in coroutines only
  (required because uninitialized objects can't be stored in fields),
  don't insert additional code for forced class initialization;

- 'enable': normalize constructor calls,
  don't insert additional code for forced class initialization;

- 'preserve-class-initialization': normalize constructor calls,
  insert additional code for forced class initialization.
2017-10-10 08:52:48 +03:00
Dmitry Petrov
40dfee6d81 Fix self-reference to singleton in initializer
Singleton instance is "initialized" by delegating constructor call,
which is superclass constructor call in case of singletons (because
singletons can't have more than one constructor).

Singleton constructor is effectively split into two stages:
- before a super constructor call;
- after a super constructor call.

Before super constructor call, singleton instance can't be used directly
(see KT-20662), because neither 'this' nor static instance is
initialized yet. However, it can be used in closures, in which case a
static instance should be used (escaping uninitialized this is
prohibited by JVM). Actually using this static instance before it is
initialized (e.g., invoking a method that uses this singleton) will
cause a correct ExceptionInInitializerError.

After a super constructor call, static instance of a singleton may be
not initialized yet (in case of enum entries and interface companion
objects). However, we already have an initialized 'this', which we
should use for singleton references.

 #KT-20651 Fixed
2017-10-10 08:52:43 +03:00
Anton Bannykh
c4d2e0f519 JS: temporarily remove @Before @After annotations from 1.1.50
(cherry-picked from commit 0976a78f6a)
2017-10-09 18:31:59 +03:00
Mikhael Bogdanov
8bef2ec503 Update stdlib jre8 test jvm-target
(cherry picked from commit bd9ac65)
2017-10-09 16:51:12 +02:00
Mikhael Bogdanov
fc0d0f2c48 Update cli module jvm-target
#KT-20671 Fixed

(cherry picked from commit 3c81430)
2017-10-09 16:51:09 +02:00
2013 changed files with 10372 additions and 55856 deletions

View File

@@ -227,6 +227,7 @@
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
<option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />

1
.idea/misc.xml generated
View File

@@ -6,7 +6,6 @@
</properties>
</component>
<component name="EntryPointsManager">
<entry_points version="2.0" />
<list size="1">
<item index="0" class="java.lang.String" itemvalue="javax.inject.Inject" />
</list>

19
.idea/modules/kotlin.iml generated Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="kotlin" external.linked.project.path="$MODULE_DIR$/../.." external.root.project.path="$MODULE_DIR$/../.." external.system.id="GRADLE" external.system.module.group="org.jetbrains.kotlin" external.system.module.version="1.1-SNAPSHOT" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/../..">
<excludeFolder url="file://$MODULE_DIR$/../../.gradle" />
<excludeFolder url="file://$MODULE_DIR$/../../build" />
<excludeFolder url="file://$MODULE_DIR$/../../dependencies" />
<excludeFolder url="file://$MODULE_DIR$/../../dist" />
<excludeFolder url="file://$MODULE_DIR$/../../ideaSDK/androidSDK" />
<excludeFolder url="file://$MODULE_DIR$/../../ideaSDK/config" />
<excludeFolder url="file://$MODULE_DIR$/../../ideaSDK/config-idea" />
<excludeFolder url="file://$MODULE_DIR$/../../ideaSDK/system" />
<excludeFolder url="file://$MODULE_DIR$/../../ideaSDK/system-idea" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

2
.idea/scopes/IDE.xml generated
View File

@@ -1,3 +1,3 @@
<component name="DependencyValidationManager">
<scope name="IDE" pattern="file[idea_main]:*/||file[idea]:testData/*/||file[idea-formatter_main]:*/||file[ide-common_main]:*/||file[idea-android_main]:*/||file[idea-android-output-parser_main]:*/||file[idea]:idea-completion/testData/*/||file[idea-core_main]:*/||file[idea-gradle_main]:*/||file[idea-jps-common_main]:*/||file[idea-jvm_main]:*/||file[idea]:idea-live-templates/src/*/||file[idea]:idea-live-templates/testData/*/||file[idea-maven_main]:*/||file[idea-repl]:*/||file[idea-test-framework_main]:*/||file[kotlin-gradle-tooling_main]:*/" />
<scope name="IDE" pattern="file[idea]:src/*/||file[idea]:testData/*/||file[ide-common]:src/*/||file[idea-analysis]:src/*/||file[idea-android]:src/*/||file[idea-completion]:src/*/||file[idea-completion]:testData/*/||file[idea-core]:src/*/||file[idea-jps-common]:/*/||file[idea-live-templates]:/*/||file[idea-live-templates]:testData/*/||file[idea-repl]:/*/||src[idea-android-output-parser]:*..*" />
</component>

View File

@@ -3,6 +3,213 @@
<!-- Find: ([^\`/\[])(KT-\d+) -->
<!-- Replace: $1[`$2`](https://youtrack.jetbrains.com/issue/$2) -->
## 1.1.60
### Android
#### New Features
- [`KT-20051`](https://youtrack.jetbrains.com/issue/KT-20051) Quickfixes to support @Parcelize
#### Fixes
- [`KT-19747`](https://youtrack.jetbrains.com/issue/KT-19747) Android extensions + Parcelable: VerifyError in case of RawValue annotation on a type when it's unknown how to parcel it
- [`KT-19899`](https://youtrack.jetbrains.com/issue/KT-19899) Parcelize: Building with ProGuard enabled
- [`KT-19988`](https://youtrack.jetbrains.com/issue/KT-19988) [Android Extensions] inner class LayoutContainer causes NoSuchMethodError
- [`KT-20002`](https://youtrack.jetbrains.com/issue/KT-20002) Parcelize explodes on LongArray
- [`KT-20019`](https://youtrack.jetbrains.com/issue/KT-20019) Parcelize does not propogate flags argument when writing nested Parcelable
- [`KT-20020`](https://youtrack.jetbrains.com/issue/KT-20020) Parcelize does not use primitive array read/write methods on Parcel
- [`KT-20021`](https://youtrack.jetbrains.com/issue/KT-20021) Parcelize does not serialize Parcelable enum as Parcelable
- [`KT-20022`](https://youtrack.jetbrains.com/issue/KT-20022) Parcelize should dispatch directly to java.lang.Enum when writing an enum.
- [`KT-20034`](https://youtrack.jetbrains.com/issue/KT-20034) Application installation failed (INSTALL_FAILED_DEXOPT) in Android 4.3 devices if I use Parcelize
- [`KT-20057`](https://youtrack.jetbrains.com/issue/KT-20057) Parcelize should use specialized write/create methods where available.
- [`KT-20062`](https://youtrack.jetbrains.com/issue/KT-20062) Parceler should allow otherwise un-parcelable property types in enclosing class.
### Compiler
#### Performance Improvements
- [`KT-20462`](https://youtrack.jetbrains.com/issue/KT-20462) Don't create an array copy for '*<array-constructor-fun>(...)'
#### Fixes
- [`KT-14697`](https://youtrack.jetbrains.com/issue/KT-14697) Use-site targeted annotation is not correctly loaded from class file
- [`KT-17680`](https://youtrack.jetbrains.com/issue/KT-17680) Android Studio and multiple tests in single file
- [`KT-19251`](https://youtrack.jetbrains.com/issue/KT-19251) Stack spilling in constructor arguments breaks Quasar
- [`KT-19592`](https://youtrack.jetbrains.com/issue/KT-19592) Apply JSR 305 default nullability qualifiers with to generic type arguments if they're applicable for TYPE_USE
- [`KT-20016`](https://youtrack.jetbrains.com/issue/KT-20016) JSR 305: default nullability qualifiers are ignored in TYPE_USE and PARAMETER positions
- [`KT-20131`](https://youtrack.jetbrains.com/issue/KT-20131) Support @NonNull(when = NEVER) nullability annotation
- [`KT-20158`](https://youtrack.jetbrains.com/issue/KT-20158) Preserve flexibility for Java types annotated with @NonNull(when = UNKNOWN)
- [`KT-20337`](https://youtrack.jetbrains.com/issue/KT-20337) No multifile class facade is generated for files with type aliases only
- [`KT-20387`](https://youtrack.jetbrains.com/issue/KT-20387) Wrong argument generated for accessor call of a protected generic 'operator fun get/set' from base class with primitive type as type parameter
- [`KT-20418`](https://youtrack.jetbrains.com/issue/KT-20418) Wrong code generated for literal long range with mixed integer literal ends
- [`KT-20491`](https://youtrack.jetbrains.com/issue/KT-20491) Incorrect synthetic accessor generated for a generic base class function specialized with primitive type
- [`KT-20651`](https://youtrack.jetbrains.com/issue/KT-20651) "Don't know how to generate outer expression" for enum-values with non-trivial self-closures
- [`KT-20707`](https://youtrack.jetbrains.com/issue/KT-20707) Support when by enum in kotlin scripts
- [`KT-20879`](https://youtrack.jetbrains.com/issue/KT-20879) Compiler problem in when-expressions
### IDE
#### New Features
- [`KT-14175`](https://youtrack.jetbrains.com/issue/KT-14175) Surround with try ... catch (... finally) doesn't work for expressions
- [`KT-15769`](https://youtrack.jetbrains.com/issue/KT-15769) Join lines could "convert to expression body"
- [`KT-19134`](https://youtrack.jetbrains.com/issue/KT-19134) IntelliJ Color Scheme editor - allow changing color of colons and double colons
- [`KT-20308`](https://youtrack.jetbrains.com/issue/KT-20308) New Gradle with Kotlin DSL project wizard
#### Fixes
- [`KT-15932`](https://youtrack.jetbrains.com/issue/KT-15932) Attempt to rename private property finds unrelated usages
- [`KT-18996`](https://youtrack.jetbrains.com/issue/KT-18996) After Kotlin compiler settings change: 'Apply' button doesn't work
- [`KT-19458`](https://youtrack.jetbrains.com/issue/KT-19458) Resolver for 'completion/highlighting in ScriptModuleInfo for build.gradle.kts / JVM' does not know how to resolve LibraryInfo
- [`KT-19474`](https://youtrack.jetbrains.com/issue/KT-19474) Kotlin Gradle Script: highlighting fails on unresolved references
- [`KT-19823`](https://youtrack.jetbrains.com/issue/KT-19823) Kotlin Gradle project import into IntelliJ: import kapt generated classes into classpath
- [`KT-19958`](https://youtrack.jetbrains.com/issue/KT-19958) Android: kotlinOptions from build.gradle are not imported into facet
- [`KT-19972`](https://youtrack.jetbrains.com/issue/KT-19972) AssertionError “Resolver for 'completion/highlighting in ModuleProductionSourceInfo(module=Module: 'kotlin-pure_main') for files dummy.kt for platform JVM' does not know how to resolve SdkInfo“ on copying Kotlin file with kotlin.* imports from other project
- [`KT-20112`](https://youtrack.jetbrains.com/issue/KT-20112) maven dependency type test-jar with scope compile not
- [`KT-20185`](https://youtrack.jetbrains.com/issue/KT-20185) Stub and PSI element type mismatch for "var nullableSuspend: (suspend (P) -> Unit)? = null"
- [`KT-20199`](https://youtrack.jetbrains.com/issue/KT-20199) Cut action is not available during indexing
- [`KT-20331`](https://youtrack.jetbrains.com/issue/KT-20331) Wrong EAP repository
- [`KT-20346`](https://youtrack.jetbrains.com/issue/KT-20346) Can't build tests in common code due to missing org.jetbrains.kotlin:kotlin-test-js testCompile dependency in JS
- [`KT-20419`](https://youtrack.jetbrains.com/issue/KT-20419) Android Studio plugin 1.1.50 show multiple gutter icon for the same item
- [`KT-20519`](https://youtrack.jetbrains.com/issue/KT-20519) Error “Parameter specified as non-null is null: method ModuleGrouperKt.isQualifiedModuleNamesEnabled” on creating Gradle (Kotlin DSL) project from scratch
- [`KT-20550`](https://youtrack.jetbrains.com/issue/KT-20550) Spring: "Navigate to autowired candidates" gutter action is missed (IDEA 2017.3)
- [`KT-20566`](https://youtrack.jetbrains.com/issue/KT-20566) Spring: "Navigate to the spring beans declaration" gutter action for `@ComponentScan` is missed (IDEA 2017.3)
- [`KT-20621`](https://youtrack.jetbrains.com/issue/KT-20621) Provide automatic migration from JetRunConfigurationType to KotlinRunConfigurationType
- [`KT-20648`](https://youtrack.jetbrains.com/issue/KT-20648) Do we need a separate ProjectImportProvider for gradle kotlin dsl projects?
- [`KT-20782`](https://youtrack.jetbrains.com/issue/KT-20782) Non-atomic trees update
- [`KT-20789`](https://youtrack.jetbrains.com/issue/KT-20789) Can't navigate to inline call/inline use site when runner is delegated to Gradle
- [`KT-20843`](https://youtrack.jetbrains.com/issue/KT-20843) Kotlin TypeDeclarationProvider may stop other declarations providers execution
- [`KT-20929`](https://youtrack.jetbrains.com/issue/KT-20929) Import Project from Gradle wizard: the same page is shown twice
### IDE. Completion
- [`KT-16383`](https://youtrack.jetbrains.com/issue/KT-16383) IllegalStateException: Failed to create expression from text: '<init>' on choosing ByteArray from completion list
- [`KT-18458`](https://youtrack.jetbrains.com/issue/KT-18458) Spring: code completion does not suggest bean names inside `@Qualifier` before function parameter
- [`KT-20256`](https://youtrack.jetbrains.com/issue/KT-20256) java.lang.Throwable “Invalid range specified” on editing template inside string literal
### IDE. Inspections and Intentions
#### New Features
- [`KT-14695`](https://youtrack.jetbrains.com/issue/KT-14695) Simplify comparison intention produces meaningless statement for assert()
- [`KT-17204`](https://youtrack.jetbrains.com/issue/KT-17204) Add `Assign to property quickfix`
- [`KT-18220`](https://youtrack.jetbrains.com/issue/KT-18220) Add data modifier to a class quickfix
- [`KT-18742`](https://youtrack.jetbrains.com/issue/KT-18742) Add quick-fix for CANNOT_CHECK_FOR_ERASED
- [`KT-19735`](https://youtrack.jetbrains.com/issue/KT-19735) Add quickfix for type mismatch that converts Sequence/Array/List
- [`KT-20259`](https://youtrack.jetbrains.com/issue/KT-20259) Show warning if arrays are compared by '!='
#### Fixes
- [`KT-10546`](https://youtrack.jetbrains.com/issue/KT-10546) Wrong "Unused property" warning on using inline object syntax
- [`KT-16394`](https://youtrack.jetbrains.com/issue/KT-16394) "Convert reference to lambda" generates wrong code
- [`KT-16808`](https://youtrack.jetbrains.com/issue/KT-16808) Intention "Remove unnecessary parantheses" is erroneously proposed for elvis operator on LHS of `in` operator if RHS of elvis is return with value
- [`KT-17437`](https://youtrack.jetbrains.com/issue/KT-17437) Class highlighted as unused even if Companion methods/fields really used
- [`KT-19377`](https://youtrack.jetbrains.com/issue/KT-19377) Inspections are run for Kotlin Gradle DSL sources
- [`KT-19420`](https://youtrack.jetbrains.com/issue/KT-19420) Kotlin Gradle script editor: suggestion to import required class from stdlib fails with AE: ResolverForProjectImpl.descriptorForModule()
- [`KT-19626`](https://youtrack.jetbrains.com/issue/KT-19626) (Specify type explicitly) Descriptor was not found for VALUE_PARAMETER
- [`KT-19674`](https://youtrack.jetbrains.com/issue/KT-19674) 'Convert property initializer to getter' intention fails on incompilable initializer with AssertionError at SpecifyTypeExplicitlyIntention$Companion.addTypeAnnotationWithTemplate()
- [`KT-19782`](https://youtrack.jetbrains.com/issue/KT-19782) Surround with if else doesn't work for expressions
- [`KT-20010`](https://youtrack.jetbrains.com/issue/KT-20010) 'Replace safe access expression with 'if' expression' IDEA Kotlin plugin intention may failed
- [`KT-20104`](https://youtrack.jetbrains.com/issue/KT-20104) "Recursive property accessor" reports false positive when property reference is used in the assignment
- [`KT-20218`](https://youtrack.jetbrains.com/issue/KT-20218) AE on calling intention “Convert to secondary constructor” for already referred argument
- [`KT-20231`](https://youtrack.jetbrains.com/issue/KT-20231) False positive 'Redundant override' when delegated member hides super type override
- [`KT-20261`](https://youtrack.jetbrains.com/issue/KT-20261) Incorrect "Redundant Unit return type" inspection for Nothing-typed expression
- [`KT-20315`](https://youtrack.jetbrains.com/issue/KT-20315) "call chain on collection type may be simplified" generates code that does not compile
- [`KT-20333`](https://youtrack.jetbrains.com/issue/KT-20333) Assignment can be lifted out of try is applied too broadly
- [`KT-20366`](https://youtrack.jetbrains.com/issue/KT-20366) Code cleanup: some inspections are broken
- [`KT-20369`](https://youtrack.jetbrains.com/issue/KT-20369) Inspection messages with INFORMATION highlight type are shown in Code Inspect
- [`KT-20409`](https://youtrack.jetbrains.com/issue/KT-20409) useless warning "Remove curly braces" for Chinese character
- [`KT-20417`](https://youtrack.jetbrains.com/issue/KT-20417) Converting property getter to block body doesn't insert explicit return type
### IDE. Refactorings
#### Performance Improvements
- [`KT-18823`](https://youtrack.jetbrains.com/issue/KT-18823) Move class to a separate file is very slow in 'kotlin' project
- [`KT-20205`](https://youtrack.jetbrains.com/issue/KT-20205) Invoke MoveKotlinDeclarationsProcessor.findUsages() under progress
#### Fixes
- [`KT-15840`](https://youtrack.jetbrains.com/issue/KT-15840) Introduce type alias: don't change not-nullable type with nullable typealias
- [`KT-17949`](https://youtrack.jetbrains.com/issue/KT-17949) Rename private fun should not search it out of scope
- [`KT-18196`](https://youtrack.jetbrains.com/issue/KT-18196) Refactor / Copy: the copy is formatted
- [`KT-18594`](https://youtrack.jetbrains.com/issue/KT-18594) Refactor / Extract (Functional) Parameter are available for annotation arguments, but fail with AE: "Body element is not found"
- [`KT-19439`](https://youtrack.jetbrains.com/issue/KT-19439) Kotlin introduce parameter causes exception
- [`KT-19909`](https://youtrack.jetbrains.com/issue/KT-19909) copy a kotlin class removes imports and other modifications
- [`KT-19949`](https://youtrack.jetbrains.com/issue/KT-19949) AssertionError „Resolver for 'project source roots and libraries for platform JVM' does not know how to resolve ModuleProductionSourceInfo“ through MoveConflictChecker.getModuleDescriptor() on copying Kotlin file from other project
- [`KT-20092`](https://youtrack.jetbrains.com/issue/KT-20092) Refactor / Copy: copy of .kt file removes all the blank lines and 'hanging' comments
- [`KT-20335`](https://youtrack.jetbrains.com/issue/KT-20335) Refactor → Extract Type Parameter: “AWT events are not allowed inside write action” after processing duplicates
- [`KT-20402`](https://youtrack.jetbrains.com/issue/KT-20402) Throwable “PsiElement(IDENTIFIER) by KotlinInplaceParameterIntroducer” on calling Refactor → Extract Parameter for default values
- [`KT-20403`](https://youtrack.jetbrains.com/issue/KT-20403) AE “Body element is not found” on calling Refactor → Extract Parameter for default values in constructor of class without body
### JavaScript
#### Fixes
- [`KT-8285`](https://youtrack.jetbrains.com/issue/KT-8285) JS: don't generate tmp when only need one component
- [`KT-14549`](https://youtrack.jetbrains.com/issue/KT-14549) JS: Non-local returns from secondary constructors don't work
- [`KT-15294`](https://youtrack.jetbrains.com/issue/KT-15294) JS: parse error in `js()` function
- [`KT-17450`](https://youtrack.jetbrains.com/issue/KT-17450) PlatformDependent members of collections are compiled in JS
- [`KT-18010`](https://youtrack.jetbrains.com/issue/KT-18010) JS: JsName annotation in interfaces can cause runtime exception
- [`KT-18063`](https://youtrack.jetbrains.com/issue/KT-18063) Inlining does not work properly in JS for suspend functions from another module
- [`KT-18548`](https://youtrack.jetbrains.com/issue/KT-18548) JS: wrong string interpolation with generic or Any parameters
- [`KT-19794`](https://youtrack.jetbrains.com/issue/KT-19794) runtime crash with empty object (Javascript)
- [`KT-19818`](https://youtrack.jetbrains.com/issue/KT-19818) JS: generate paths relative to .map file by default (unless "-source-map-prefix" is used)
- [`KT-19906`](https://youtrack.jetbrains.com/issue/KT-19906) JS: rename compiler option "-source-map-source-roots" to avoid misleading since sourcemaps have field called "sourceRoot"
- [`KT-20287`](https://youtrack.jetbrains.com/issue/KT-20287) Functions don't actually return Unit in Kotlin-JS -> unexpected null problems vs JDK version
- [`KT-20451`](https://youtrack.jetbrains.com/issue/KT-20451) KotlinJs - interface function with default parameter, overridden by implementor, can't be found at runtime
- [`KT-20650`](https://youtrack.jetbrains.com/issue/KT-20650) JS: compiler crashes in Java 9 with NoClassDefFoundError
- [`KT-20653`](https://youtrack.jetbrains.com/issue/KT-20653) JS: compiler crashes in Java 9 with TranslationRuntimeException
- [`KT-20820`](https://youtrack.jetbrains.com/issue/KT-20820) JS: IDEA project doesn't generate paths relative to .map
### Libraries
- [`KT-20596`](https://youtrack.jetbrains.com/issue/KT-20596) 'synchronized' does not allow non-local return in Kotlin JS
- [`KT-20600`](https://youtrack.jetbrains.com/issue/KT-20600) Typo in POMs for kotlin-runtime
### Tools
- [`KT-19692`](https://youtrack.jetbrains.com/issue/KT-19692) kotlin-jpa plugin doesn't support @MappedSuperclass annotation
- [`KT-20030`](https://youtrack.jetbrains.com/issue/KT-20030) Parcelize can directly reference writeToParcel and CREATOR for final, non-Parcelize Parcelable types in same compilation unit.
- [`KT-19742`](https://youtrack.jetbrains.com/issue/KT-19742) [Android extensions] Calling clearFindViewByIdCache causes NPE
- [`KT-19749`](https://youtrack.jetbrains.com/issue/KT-19749) Android extensions + Parcelable: NoSuchMethodError on attempt to pack into parcel a serializable object
- [`KT-20026`](https://youtrack.jetbrains.com/issue/KT-20026) Parcelize overrides describeContents despite being already implemented.
- [`KT-20027`](https://youtrack.jetbrains.com/issue/KT-20027) Parcelize uses wrong classloader when reading parcelable type.
- [`KT-20029`](https://youtrack.jetbrains.com/issue/KT-20029) Parcelize should not directly reference parcel methods on types outside compilation unit
- [`KT-20032`](https://youtrack.jetbrains.com/issue/KT-20032) Parcelize does not respect type nullability in case of Parcelize parcelables
### Tools. Gradle
- [`KT-3463`](https://youtrack.jetbrains.com/issue/KT-3463) Gradle plugin ignores kotlin compile options changes
- [`KT-16299`](https://youtrack.jetbrains.com/issue/KT-16299) Gradle build does not recompile annotated classes on changing compiler's plugins configuration
- [`KT-16764`](https://youtrack.jetbrains.com/issue/KT-16764) Kotlin Gradle plugin should replicate task dependencies of Java source directories
- [`KT-17564`](https://youtrack.jetbrains.com/issue/KT-17564) Applying Kotlin's Gradle plugin results in src/main/java being listed twice in sourceSets.main.allSource
- [`KT-17674`](https://youtrack.jetbrains.com/issue/KT-17674) Test code is not compiled incrementally when main is changed
- [`KT-18765`](https://youtrack.jetbrains.com/issue/KT-18765) Move incremental compilation message from Gradle's warning to info logging level
- [`KT-20036`](https://youtrack.jetbrains.com/issue/KT-20036) Gradle tasks up-to-date-ness
### Tools. J2K
- [`KT-19565`](https://youtrack.jetbrains.com/issue/KT-19565) Java code using Iterator#remove converted to red code
- [`KT-19651`](https://youtrack.jetbrains.com/issue/KT-19651) Java class with static-only methods can contain 'protected' members
### Tools. JPS
- [`KT-20082`](https://youtrack.jetbrains.com/issue/KT-20082) Java 9: incremental build reports bogus error for reference to Kotlin source
- [`KT-20671`](https://youtrack.jetbrains.com/issue/KT-20671) Kotlin plugin compiler exception when compiling under JDK9
### Tools. Maven
- [`KT-20064`](https://youtrack.jetbrains.com/issue/KT-20064) Maven + Java 9: compile task warns about module-info in the output path
- [`KT-20400`](https://youtrack.jetbrains.com/issue/KT-20400) Do not output module name, version and related information by default in Maven builds
### Tools. REPL
- [`KT-20167`](https://youtrack.jetbrains.com/issue/KT-20167) JDK 9 `unresolved supertypes: Object` when working with Kotlin Scripting API
### Tools. kapt
- [`KT-17923`](https://youtrack.jetbrains.com/issue/KT-17923) Reference to Dagger generated class is highlighted red
- [`KT-18923`](https://youtrack.jetbrains.com/issue/KT-18923) Kapt: Do not use the Kotlin error message collector to issue errors from kapt
- [`KT-19097`](https://youtrack.jetbrains.com/issue/KT-19097) Request: Decent support of `kapt.kotlin.generated` on Intellij/Android Studio
- [`KT-20877`](https://youtrack.jetbrains.com/issue/KT-20877) Butterknife: UninitializedPropertyAccessException: "lateinit property has not been initialized" for field annotated with `@BindView`.
## 1.1.50
### Android

View File

@@ -2,6 +2,7 @@
<import file="build.xml" optional="false"/>
<property name="build.number" value="snapshot"/>
<property name="jdk16.home" value="${java.home}"/>
<property name="fail.on.plugin.verifier.error" value="true"/>
<property name="version_substitute_dir" value="${basedir}/versions_temp/"/>

View File

@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.shouldWritePreReleaseFlag
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
@@ -59,23 +58,18 @@ data class JvmBuildMetaInfo(
}
}
fun JvmBuildMetaInfo(args: CommonCompilerArguments): JvmBuildMetaInfo {
val languageVersion = args.languageVersion?.let((LanguageVersion)::fromVersionString) ?: LanguageVersion.LATEST_STABLE
return JvmBuildMetaInfo(
isEAP = languageVersion.shouldWritePreReleaseFlag(),
compilerBuildVersion = KotlinCompilerVersion.VERSION,
languageVersionString = languageVersion.versionString,
apiVersionString = args.apiVersion ?: ApiVersion.LATEST_STABLE.versionString,
coroutinesEnable = args.coroutinesState == CommonCompilerArguments.ENABLE,
coroutinesWarn = args.coroutinesState == CommonCompilerArguments.WARN,
coroutinesError = args.coroutinesState == CommonCompilerArguments.ERROR,
multiplatformEnable = args.multiPlatform,
metadataVersionMajor = JvmMetadataVersion.INSTANCE.major,
metadataVersionMinor = JvmMetadataVersion.INSTANCE.minor,
metadataVersionPatch = JvmMetadataVersion.INSTANCE.patch,
bytecodeVersionMajor = JvmBytecodeBinaryVersion.INSTANCE.major,
bytecodeVersionMinor = JvmBytecodeBinaryVersion.INSTANCE.minor,
bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch
)
}
fun JvmBuildMetaInfo(args: CommonCompilerArguments): JvmBuildMetaInfo =
JvmBuildMetaInfo(isEAP = KotlinCompilerVersion.isPreRelease(),
compilerBuildVersion = KotlinCompilerVersion.VERSION,
languageVersionString = args.languageVersion ?: LanguageVersion.LATEST_STABLE.versionString,
apiVersionString = args.apiVersion ?: ApiVersion.LATEST_STABLE.versionString,
coroutinesEnable = args.coroutinesState == CommonCompilerArguments.ENABLE,
coroutinesWarn = args.coroutinesState == CommonCompilerArguments.WARN,
coroutinesError = args.coroutinesState == CommonCompilerArguments.ERROR,
multiplatformEnable = args.multiPlatform,
metadataVersionMajor = JvmMetadataVersion.INSTANCE.major,
metadataVersionMinor = JvmMetadataVersion.INSTANCE.minor,
metadataVersionPatch = JvmMetadataVersion.INSTANCE.patch,
bytecodeVersionMajor = JvmBytecodeBinaryVersion.INSTANCE.major,
bytecodeVersionMinor = JvmBytecodeBinaryVersion.INSTANCE.minor,
bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch)

View File

@@ -287,7 +287,9 @@ open class IncrementalJvmCache(
fun remove(className: JvmClassName, changesCollector: ChangesCollector) {
val key = className.internalName
val oldValue = storage[key] ?: return
changesCollector.collectProtoChanges(oldData = oldValue.toProtoData(className.packageFqName), newData = null)
if (key != MODULE_MAPPING_FILE_NAME) {
changesCollector.collectProtoChanges(oldData = oldValue.toProtoData(className.packageFqName), newData = null)
}
storage.remove(key)
}

View File

@@ -47,9 +47,9 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (!checkEquals(old.typeTable, new.typeTable)) return false
}
if (old.hasVersionRequirementTable() != new.hasVersionRequirementTable()) return false
if (old.hasVersionRequirementTable()) {
if (!checkEquals(old.versionRequirementTable, new.versionRequirementTable)) return false
if (old.hasSinceKotlinInfoTable() != new.hasSinceKotlinInfoTable()) return false
if (old.hasSinceKotlinInfoTable()) {
if (!checkEquals(old.sinceKotlinInfoTable, new.sinceKotlinInfoTable)) return false
}
if (old.hasExtension(JvmProtoBuf.packageModuleName) != new.hasExtension(JvmProtoBuf.packageModuleName)) return false
@@ -78,7 +78,7 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
PROPERTY_LIST,
TYPE_ALIAS_LIST,
TYPE_TABLE,
VERSION_REQUIREMENT_TABLE,
SINCE_KOTLIN_INFO_TABLE,
JVM_EXT_PACKAGE_MODULE_NAME,
JVM_EXT_PACKAGE_LOCAL_VARIABLE_LIST,
JS_EXT_PACKAGE_FQ_NAME
@@ -98,9 +98,9 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (!checkEquals(old.typeTable, new.typeTable)) result.add(ProtoBufPackageKind.TYPE_TABLE)
}
if (old.hasVersionRequirementTable() != new.hasVersionRequirementTable()) result.add(ProtoBufPackageKind.VERSION_REQUIREMENT_TABLE)
if (old.hasVersionRequirementTable()) {
if (!checkEquals(old.versionRequirementTable, new.versionRequirementTable)) result.add(ProtoBufPackageKind.VERSION_REQUIREMENT_TABLE)
if (old.hasSinceKotlinInfoTable() != new.hasSinceKotlinInfoTable()) result.add(ProtoBufPackageKind.SINCE_KOTLIN_INFO_TABLE)
if (old.hasSinceKotlinInfoTable()) {
if (!checkEquals(old.sinceKotlinInfoTable, new.sinceKotlinInfoTable)) result.add(ProtoBufPackageKind.SINCE_KOTLIN_INFO_TABLE)
}
if (old.hasExtension(JvmProtoBuf.packageModuleName) != new.hasExtension(JvmProtoBuf.packageModuleName)) result.add(ProtoBufPackageKind.JVM_EXT_PACKAGE_MODULE_NAME)
@@ -163,14 +163,14 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (!checkEquals(old.typeTable, new.typeTable)) return false
}
if (old.hasVersionRequirement() != new.hasVersionRequirement()) return false
if (old.hasVersionRequirement()) {
if (old.versionRequirement != new.versionRequirement) return false
if (old.hasSinceKotlinInfo() != new.hasSinceKotlinInfo()) return false
if (old.hasSinceKotlinInfo()) {
if (old.sinceKotlinInfo != new.sinceKotlinInfo) return false
}
if (old.hasVersionRequirementTable() != new.hasVersionRequirementTable()) return false
if (old.hasVersionRequirementTable()) {
if (!checkEquals(old.versionRequirementTable, new.versionRequirementTable)) return false
if (old.hasSinceKotlinInfoTable() != new.hasSinceKotlinInfoTable()) return false
if (old.hasSinceKotlinInfoTable()) {
if (!checkEquals(old.sinceKotlinInfoTable, new.sinceKotlinInfoTable)) return false
}
if (old.hasExtension(JvmProtoBuf.classModuleName) != new.hasExtension(JvmProtoBuf.classModuleName)) return false
@@ -218,8 +218,8 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
ENUM_ENTRY_LIST,
SEALED_SUBCLASS_FQ_NAME_LIST,
TYPE_TABLE,
VERSION_REQUIREMENT,
VERSION_REQUIREMENT_TABLE,
SINCE_KOTLIN_INFO,
SINCE_KOTLIN_INFO_TABLE,
JVM_EXT_CLASS_MODULE_NAME,
JVM_EXT_CLASS_LOCAL_VARIABLE_LIST,
JS_EXT_CLASS_ANNOTATION_LIST,
@@ -266,14 +266,14 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (!checkEquals(old.typeTable, new.typeTable)) result.add(ProtoBufClassKind.TYPE_TABLE)
}
if (old.hasVersionRequirement() != new.hasVersionRequirement()) result.add(ProtoBufClassKind.VERSION_REQUIREMENT)
if (old.hasVersionRequirement()) {
if (old.versionRequirement != new.versionRequirement) result.add(ProtoBufClassKind.VERSION_REQUIREMENT)
if (old.hasSinceKotlinInfo() != new.hasSinceKotlinInfo()) result.add(ProtoBufClassKind.SINCE_KOTLIN_INFO)
if (old.hasSinceKotlinInfo()) {
if (old.sinceKotlinInfo != new.sinceKotlinInfo) result.add(ProtoBufClassKind.SINCE_KOTLIN_INFO)
}
if (old.hasVersionRequirementTable() != new.hasVersionRequirementTable()) result.add(ProtoBufClassKind.VERSION_REQUIREMENT_TABLE)
if (old.hasVersionRequirementTable()) {
if (!checkEquals(old.versionRequirementTable, new.versionRequirementTable)) result.add(ProtoBufClassKind.VERSION_REQUIREMENT_TABLE)
if (old.hasSinceKotlinInfoTable() != new.hasSinceKotlinInfoTable()) result.add(ProtoBufClassKind.SINCE_KOTLIN_INFO_TABLE)
if (old.hasSinceKotlinInfoTable()) {
if (!checkEquals(old.sinceKotlinInfoTable, new.sinceKotlinInfoTable)) result.add(ProtoBufClassKind.SINCE_KOTLIN_INFO_TABLE)
}
if (old.hasExtension(JvmProtoBuf.classModuleName) != new.hasExtension(JvmProtoBuf.classModuleName)) result.add(ProtoBufClassKind.JVM_EXT_CLASS_MODULE_NAME)
@@ -349,14 +349,9 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (!checkEquals(old.typeTable, new.typeTable)) return false
}
if (old.hasVersionRequirement() != new.hasVersionRequirement()) return false
if (old.hasVersionRequirement()) {
if (old.versionRequirement != new.versionRequirement) return false
}
if (old.hasContract() != new.hasContract()) return false
if (old.hasContract()) {
if (!checkEquals(old.contract, new.contract)) return false
if (old.hasSinceKotlinInfo() != new.hasSinceKotlinInfo()) return false
if (old.hasSinceKotlinInfo()) {
if (old.sinceKotlinInfo != new.sinceKotlinInfo) return false
}
if (old.hasExtension(JvmProtoBuf.methodSignature) != new.hasExtension(JvmProtoBuf.methodSignature)) return false
@@ -431,9 +426,9 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (old.setterFlags != new.setterFlags) return false
}
if (old.hasVersionRequirement() != new.hasVersionRequirement()) return false
if (old.hasVersionRequirement()) {
if (old.versionRequirement != new.versionRequirement) return false
if (old.hasSinceKotlinInfo() != new.hasSinceKotlinInfo()) return false
if (old.hasSinceKotlinInfo()) {
if (old.sinceKotlinInfo != new.sinceKotlinInfo) return false
}
if (old.hasExtension(JvmProtoBuf.propertySignature) != new.hasExtension(JvmProtoBuf.propertySignature)) return false
@@ -495,9 +490,9 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (!checkEqualsTypeAliasAnnotation(old, new)) return false
if (old.hasVersionRequirement() != new.hasVersionRequirement()) return false
if (old.hasVersionRequirement()) {
if (old.versionRequirement != new.versionRequirement) return false
if (old.hasSinceKotlinInfo() != new.hasSinceKotlinInfo()) return false
if (old.hasSinceKotlinInfo()) {
if (old.sinceKotlinInfo != new.sinceKotlinInfo) return false
}
return true
@@ -514,8 +509,8 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
return true
}
open fun checkEquals(old: ProtoBuf.VersionRequirementTable, new: ProtoBuf.VersionRequirementTable): Boolean {
if (!checkEqualsVersionRequirementTableRequirement(old, new)) return false
open fun checkEquals(old: ProtoBuf.SinceKotlinInfoTable, new: ProtoBuf.SinceKotlinInfoTable): Boolean {
if (!checkEqualsSinceKotlinInfoTableInfo(old, new)) return false
return true
}
@@ -662,9 +657,9 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (!checkEqualsConstructorValueParameter(old, new)) return false
if (old.hasVersionRequirement() != new.hasVersionRequirement()) return false
if (old.hasVersionRequirement()) {
if (old.versionRequirement != new.versionRequirement) return false
if (old.hasSinceKotlinInfo() != new.hasSinceKotlinInfo()) return false
if (old.hasSinceKotlinInfo()) {
if (old.sinceKotlinInfo != new.sinceKotlinInfo) return false
}
if (old.hasExtension(JvmProtoBuf.constructorSignature) != new.hasExtension(JvmProtoBuf.constructorSignature)) return false
@@ -750,12 +745,6 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
return true
}
open fun checkEquals(old: ProtoBuf.Contract, new: ProtoBuf.Contract): Boolean {
if (!checkEqualsContractEffect(old, new)) return false
return true
}
open fun checkEquals(old: JvmProtoBuf.JvmMethodSignature, new: JvmProtoBuf.JvmMethodSignature): Boolean {
if (old.hasName() != new.hasName()) return false
if (old.hasName()) {
@@ -840,7 +829,7 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
return true
}
open fun checkEquals(old: ProtoBuf.VersionRequirement, new: ProtoBuf.VersionRequirement): Boolean {
open fun checkEquals(old: ProtoBuf.SinceKotlinInfo, new: ProtoBuf.SinceKotlinInfo): Boolean {
if (old.hasVersion() != new.hasVersion()) return false
if (old.hasVersion()) {
if (old.version != new.version) return false
@@ -866,11 +855,6 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
if (!checkStringEquals(old.message, new.message)) return false
}
if (old.hasVersionKind() != new.hasVersionKind()) return false
if (old.hasVersionKind()) {
if (old.versionKind != new.versionKind) return false
}
return true
}
@@ -901,27 +885,6 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
return true
}
open fun checkEquals(old: ProtoBuf.Effect, new: ProtoBuf.Effect): Boolean {
if (old.hasEffectType() != new.hasEffectType()) return false
if (old.hasEffectType()) {
if (old.effectType != new.effectType) return false
}
if (!checkEqualsEffectEffectConstructorArgument(old, new)) return false
if (old.hasConclusionOfConditionalEffect() != new.hasConclusionOfConditionalEffect()) return false
if (old.hasConclusionOfConditionalEffect()) {
if (!checkEquals(old.conclusionOfConditionalEffect, new.conclusionOfConditionalEffect)) return false
}
if (old.hasKind() != new.hasKind()) return false
if (old.hasKind()) {
if (old.kind != new.kind) return false
}
return true
}
open fun checkEquals(old: JvmProtoBuf.JvmFieldSignature, new: JvmProtoBuf.JvmFieldSignature): Boolean {
if (old.hasName() != new.hasName()) return false
if (old.hasName()) {
@@ -936,39 +899,6 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
return true
}
open fun checkEquals(old: ProtoBuf.Expression, new: ProtoBuf.Expression): Boolean {
if (old.hasFlags() != new.hasFlags()) return false
if (old.hasFlags()) {
if (old.flags != new.flags) return false
}
if (old.hasValueParameterReference() != new.hasValueParameterReference()) return false
if (old.hasValueParameterReference()) {
if (old.valueParameterReference != new.valueParameterReference) return false
}
if (old.hasConstantValue() != new.hasConstantValue()) return false
if (old.hasConstantValue()) {
if (old.constantValue != new.constantValue) return false
}
if (old.hasIsInstanceType() != new.hasIsInstanceType()) return false
if (old.hasIsInstanceType()) {
if (!checkEquals(old.isInstanceType, new.isInstanceType)) return false
}
if (old.hasIsInstanceTypeId() != new.hasIsInstanceTypeId()) return false
if (old.hasIsInstanceTypeId()) {
if (old.isInstanceTypeId != new.isInstanceTypeId) return false
}
if (!checkEqualsExpressionAndArgument(old, new)) return false
if (!checkEqualsExpressionOrArgument(old, new)) return false
return true
}
open fun checkEqualsPackageFunction(old: ProtoBuf.Package, new: ProtoBuf.Package): Boolean {
if (old.functionCount != new.functionCount) return false
@@ -1159,11 +1089,11 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
return true
}
open fun checkEqualsVersionRequirementTableRequirement(old: ProtoBuf.VersionRequirementTable, new: ProtoBuf.VersionRequirementTable): Boolean {
if (old.requirementCount != new.requirementCount) return false
open fun checkEqualsSinceKotlinInfoTableInfo(old: ProtoBuf.SinceKotlinInfoTable, new: ProtoBuf.SinceKotlinInfoTable): Boolean {
if (old.infoCount != new.infoCount) return false
for(i in 0..old.requirementCount - 1) {
if (!checkEquals(old.getRequirement(i), new.getRequirement(i))) return false
for(i in 0..old.infoCount - 1) {
if (!checkEquals(old.getInfo(i), new.getInfo(i))) return false
}
return true
@@ -1219,16 +1149,6 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
return true
}
open fun checkEqualsContractEffect(old: ProtoBuf.Contract, new: ProtoBuf.Contract): Boolean {
if (old.effectCount != new.effectCount) return false
for(i in 0..old.effectCount - 1) {
if (!checkEquals(old.getEffect(i), new.getEffect(i))) return false
}
return true
}
open fun checkEqualsAnnotationArgumentValueArrayElement(old: ProtoBuf.Annotation.Argument.Value, new: ProtoBuf.Annotation.Argument.Value): Boolean {
if (old.arrayElementCount != new.arrayElementCount) return false
@@ -1239,36 +1159,6 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
return true
}
open fun checkEqualsEffectEffectConstructorArgument(old: ProtoBuf.Effect, new: ProtoBuf.Effect): Boolean {
if (old.effectConstructorArgumentCount != new.effectConstructorArgumentCount) return false
for(i in 0..old.effectConstructorArgumentCount - 1) {
if (!checkEquals(old.getEffectConstructorArgument(i), new.getEffectConstructorArgument(i))) return false
}
return true
}
open fun checkEqualsExpressionAndArgument(old: ProtoBuf.Expression, new: ProtoBuf.Expression): Boolean {
if (old.andArgumentCount != new.andArgumentCount) return false
for(i in 0..old.andArgumentCount - 1) {
if (!checkEquals(old.getAndArgument(i), new.getAndArgument(i))) return false
}
return true
}
open fun checkEqualsExpressionOrArgument(old: ProtoBuf.Expression, new: ProtoBuf.Expression): Boolean {
if (old.orArgumentCount != new.orArgumentCount) return false
for(i in 0..old.orArgumentCount - 1) {
if (!checkEquals(old.getOrArgument(i), new.getOrArgument(i))) return false
}
return true
}
fun oldGetIndexOfString(index: Int): Int = getIndexOfString(index, oldStringIndexesMap, oldNameResolver)
fun newGetIndexOfString(index: Int): Int = getIndexOfString(index, newStringIndexesMap, newNameResolver)
@@ -1319,8 +1209,8 @@ fun ProtoBuf.Package.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int)
hashCode = 31 * hashCode + typeTable.hashCode(stringIndexes, fqNameIndexes)
}
if (hasVersionRequirementTable()) {
hashCode = 31 * hashCode + versionRequirementTable.hashCode(stringIndexes, fqNameIndexes)
if (hasSinceKotlinInfoTable()) {
hashCode = 31 * hashCode + sinceKotlinInfoTable.hashCode(stringIndexes, fqNameIndexes)
}
if (hasExtension(JvmProtoBuf.packageModuleName)) {
@@ -1395,12 +1285,12 @@ fun ProtoBuf.Class.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) ->
hashCode = 31 * hashCode + typeTable.hashCode(stringIndexes, fqNameIndexes)
}
if (hasVersionRequirement()) {
hashCode = 31 * hashCode + versionRequirement
if (hasSinceKotlinInfo()) {
hashCode = 31 * hashCode + sinceKotlinInfo
}
if (hasVersionRequirementTable()) {
hashCode = 31 * hashCode + versionRequirementTable.hashCode(stringIndexes, fqNameIndexes)
if (hasSinceKotlinInfoTable()) {
hashCode = 31 * hashCode + sinceKotlinInfoTable.hashCode(stringIndexes, fqNameIndexes)
}
if (hasExtension(JvmProtoBuf.classModuleName)) {
@@ -1463,12 +1353,8 @@ fun ProtoBuf.Function.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int)
hashCode = 31 * hashCode + typeTable.hashCode(stringIndexes, fqNameIndexes)
}
if (hasVersionRequirement()) {
hashCode = 31 * hashCode + versionRequirement
}
if (hasContract()) {
hashCode = 31 * hashCode + contract.hashCode(stringIndexes, fqNameIndexes)
if (hasSinceKotlinInfo()) {
hashCode = 31 * hashCode + sinceKotlinInfo
}
if (hasExtension(JvmProtoBuf.methodSignature)) {
@@ -1531,8 +1417,8 @@ fun ProtoBuf.Property.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int)
hashCode = 31 * hashCode + setterFlags
}
if (hasVersionRequirement()) {
hashCode = 31 * hashCode + versionRequirement
if (hasSinceKotlinInfo()) {
hashCode = 31 * hashCode + sinceKotlinInfo
}
if (hasExtension(JvmProtoBuf.propertySignature)) {
@@ -1587,8 +1473,8 @@ fun ProtoBuf.TypeAlias.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int
hashCode = 31 * hashCode + getAnnotation(i).hashCode(stringIndexes, fqNameIndexes)
}
if (hasVersionRequirement()) {
hashCode = 31 * hashCode + versionRequirement
if (hasSinceKotlinInfo()) {
hashCode = 31 * hashCode + sinceKotlinInfo
}
return hashCode
@@ -1608,11 +1494,11 @@ fun ProtoBuf.TypeTable.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int
return hashCode
}
fun ProtoBuf.VersionRequirementTable.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
fun ProtoBuf.SinceKotlinInfoTable.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
var hashCode = 1
for(i in 0..requirementCount - 1) {
hashCode = 31 * hashCode + getRequirement(i).hashCode(stringIndexes, fqNameIndexes)
for(i in 0..infoCount - 1) {
hashCode = 31 * hashCode + getInfo(i).hashCode(stringIndexes, fqNameIndexes)
}
return hashCode
@@ -1737,8 +1623,8 @@ fun ProtoBuf.Constructor.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (I
hashCode = 31 * hashCode + getValueParameter(i).hashCode(stringIndexes, fqNameIndexes)
}
if (hasVersionRequirement()) {
hashCode = 31 * hashCode + versionRequirement
if (hasSinceKotlinInfo()) {
hashCode = 31 * hashCode + sinceKotlinInfo
}
if (hasExtension(JvmProtoBuf.constructorSignature)) {
@@ -1810,16 +1696,6 @@ fun ProtoBuf.ValueParameter.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes:
return hashCode
}
fun ProtoBuf.Contract.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
var hashCode = 1
for(i in 0..effectCount - 1) {
hashCode = 31 * hashCode + getEffect(i).hashCode(stringIndexes, fqNameIndexes)
}
return hashCode
}
fun JvmProtoBuf.JvmMethodSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
var hashCode = 1
@@ -1898,7 +1774,7 @@ fun ProtoBuf.Annotation.Argument.Value.hashCode(stringIndexes: (Int) -> Int, fqN
return hashCode
}
fun ProtoBuf.VersionRequirement.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
fun ProtoBuf.SinceKotlinInfo.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
var hashCode = 1
if (hasVersion()) {
@@ -1921,10 +1797,6 @@ fun ProtoBuf.VersionRequirement.hashCode(stringIndexes: (Int) -> Int, fqNameInde
hashCode = 31 * hashCode + stringIndexes(message)
}
if (hasVersionKind()) {
hashCode = 31 * hashCode + versionKind.hashCode()
}
return hashCode
}
@@ -1956,28 +1828,6 @@ fun ProtoBuf.Annotation.Argument.hashCode(stringIndexes: (Int) -> Int, fqNameInd
return hashCode
}
fun ProtoBuf.Effect.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
var hashCode = 1
if (hasEffectType()) {
hashCode = 31 * hashCode + effectType.hashCode()
}
for(i in 0..effectConstructorArgumentCount - 1) {
hashCode = 31 * hashCode + getEffectConstructorArgument(i).hashCode(stringIndexes, fqNameIndexes)
}
if (hasConclusionOfConditionalEffect()) {
hashCode = 31 * hashCode + conclusionOfConditionalEffect.hashCode(stringIndexes, fqNameIndexes)
}
if (hasKind()) {
hashCode = 31 * hashCode + kind.hashCode()
}
return hashCode
}
fun JvmProtoBuf.JvmFieldSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
var hashCode = 1
@@ -1991,37 +1841,3 @@ fun JvmProtoBuf.JvmFieldSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIn
return hashCode
}
fun ProtoBuf.Expression.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
var hashCode = 1
if (hasFlags()) {
hashCode = 31 * hashCode + flags
}
if (hasValueParameterReference()) {
hashCode = 31 * hashCode + valueParameterReference
}
if (hasConstantValue()) {
hashCode = 31 * hashCode + constantValue.hashCode()
}
if (hasIsInstanceType()) {
hashCode = 31 * hashCode + isInstanceType.hashCode(stringIndexes, fqNameIndexes)
}
if (hasIsInstanceTypeId()) {
hashCode = 31 * hashCode + isInstanceTypeId
}
for(i in 0..andArgumentCount - 1) {
hashCode = 31 * hashCode + getAndArgument(i).hashCode(stringIndexes, fqNameIndexes)
}
for(i in 0..orArgumentCount - 1) {
hashCode = 31 * hashCode + getOrArgument(i).hashCode(stringIndexes, fqNameIndexes)
}
return hashCode
}

View File

@@ -224,8 +224,8 @@ class DifferenceCalculatorForClass(
ProtoBufClassKind.TYPE_TABLE -> {
// TODO
}
ProtoCompareGenerated.ProtoBufClassKind.VERSION_REQUIREMENT,
ProtoCompareGenerated.ProtoBufClassKind.VERSION_REQUIREMENT_TABLE -> {
ProtoCompareGenerated.ProtoBufClassKind.SINCE_KOTLIN_INFO,
ProtoCompareGenerated.ProtoBufClassKind.SINCE_KOTLIN_INFO_TABLE -> {
// TODO
}
ProtoBufClassKind.FLAGS,
@@ -281,7 +281,7 @@ class DifferenceCalculatorForPackageFacade(
ProtoBufPackageKind.TYPE_ALIAS_LIST ->
names.addAll(calcDifferenceForNonPrivateMembers(ProtoBuf.Package::getTypeAliasList))
ProtoBufPackageKind.TYPE_TABLE,
ProtoBufPackageKind.VERSION_REQUIREMENT_TABLE,
ProtoBufPackageKind.SINCE_KOTLIN_INFO_TABLE,
ProtoBufPackageKind.JVM_EXT_PACKAGE_MODULE_NAME,
ProtoBufPackageKind.JS_EXT_PACKAGE_FQ_NAME-> {
// TODO

View File

@@ -2,14 +2,13 @@ import org.gradle.api.Project
import java.util.*
import java.io.File
import org.gradle.api.tasks.bundling.Jar
import org.gradle.plugins.ide.idea.model.IdeaModel
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
buildscript {
extra["defaultSnapshotVersion"] = "1.2-SNAPSHOT"
extra["defaultSnapshotVersion"] = "1.1-SNAPSHOT"
kotlinBootstrapFrom(BootstrapOption.TeamCity("1.2.0-dev-92", onlySuccessBootstrap = false))
kotlinBootstrapFrom(BootstrapOption.BintrayDev("1.1.60-eap-30"))
val repos = listOfNotNull(
bootstrapKotlinRepo,
@@ -35,7 +34,6 @@ buildscript {
plugins {
`build-scan`
idea
}
buildScan {
@@ -54,7 +52,7 @@ val defaultSnapshotVersion: String by extra
val buildNumber by extra(findProperty("build.number")?.toString() ?: defaultSnapshotVersion)
val kotlinVersion by extra(findProperty("deployVersion")?.toString() ?: buildNumber)
val kotlinLanguageVersion by extra("1.2")
val kotlinLanguageVersion by extra("1.1")
allprojects {
group = "org.jetbrains.kotlin"
@@ -117,7 +115,7 @@ extra["versions.ant"] = "1.8.2"
extra["versions.android"] = "2.3.1"
extra["ideaCoreSdkJars"] = arrayOf("annotations", "asm-all", "guava", "intellij-core", "jdom", "jna", "log4j", "picocontainer",
"snappy-in-java", "trove4j", "xpp3-1.1.4-min", "xstream")
"snappy-in-java", "streamex", "trove4j", "xpp3-1.1.4-min", "xstream")
extra["compilerModules"] = arrayOf(":compiler:util",
":compiler:container",
@@ -155,8 +153,6 @@ val coreLibProjects = listOf(
":kotlin-stdlib-js",
":kotlin-stdlib-jre7",
":kotlin-stdlib-jre8",
":kotlin-stdlib-jdk7",
":kotlin-stdlib-jdk8",
":kotlin-test:kotlin-test-common",
":kotlin-test:kotlin-test-jvm",
":kotlin-test:kotlin-test-junit",
@@ -217,7 +213,6 @@ fun Task.listConfigurationContents(configName: String) {
val defaultJvmTarget = "1.8"
val defaultJavaHome = jdkPath(defaultJvmTarget!!)
val ignoreTestFailures by extra(project.findProperty("ignoreTestFailures")?.toString()?.toBoolean() ?: project.hasProperty("teamcity"))
allprojects {
@@ -226,7 +221,7 @@ allprojects {
// There are problems with common build dir:
// - some tests (in particular js and binary-compatibility-validator depend on the fixed (default) location
// - idea seems unable to exclude common builddir from indexing
// - idea siims unable to exclude common builddir from indexing
// therefore it is disabled by default
// buildDir = File(commonBuildDir, project.name)
@@ -234,29 +229,19 @@ allprojects {
for (repo in (rootProject.extra["repos"] as List<String>)) {
maven { setUrl(repo) }
}
mavenCentral()
jcenter()
}
configureJvmProject(javaHome!!, jvmTarget!!)
val commonCompilerArgs = listOf("-Xallow-kotlin-package")
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
kotlinOptions {
languageVersion = kotlinLanguageVersion
apiVersion = kotlinLanguageVersion
freeCompilerArgs = commonCompilerArgs
freeCompilerArgs = listOf("-Xallow-kotlin-package", "-Xnormalize-constructor-calls=enable")
}
}
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
kotlinOptions {
freeCompilerArgs = commonCompilerArgs + listOf("-Xnormalize-constructor-calls=enable")
}
}
tasks.withType(VerificationTask::class.java as Class<Task>) {
(this as VerificationTask).ignoreFailures = ignoreTestFailures
}
tasks.withType<Javadoc> {
enabled = false
}
@@ -332,6 +317,11 @@ tasks {
}
}
"gradlePluginsTest" {
// deprecated
dependsOn("gradlePluginTest")
}
"gradlePluginIntegrationTest" {
dependsOn(":kotlin-gradle-plugin-integration-tests:check")
}
@@ -349,6 +339,7 @@ tasks {
}
"jsCompilerTest" {
dependsOn("dist")
dependsOn(":js:js.tests:test")
}
@@ -457,23 +448,6 @@ tasks {
"check" { dependsOn("test") }
}
configure<IdeaModel> {
module {
excludeDirs = files(
project.buildDir,
".gradle",
"dependencies",
"dist",
"ideaSDK/bin",
"ideaSDK/androidSDK",
"ideaSDK/config",
"ideaSDK/config-idea",
"ideaSDK/system",
"ideaSDK/system-idea"
).toSet()
}
}
fun jdkPathIfFound(version: String): String? {
val jdkName = "JDK_${version.replace(".", "")}"
val jdkMajorVersion = JdkMajorVersion.valueOf(jdkName)

View File

@@ -25,7 +25,7 @@
<property environment="env"/>
<property name="tools.jar" value="${env.JDK_18}/lib/tools.jar"/>
<property name="java.target" value="1.6"/>
<property name="java.target" value="1.8"/>
<condition property="bootstrap.or.local.build" value="true" else="false">
<or>
@@ -387,19 +387,20 @@
<zipgroupfileset dir="${basedir}/lib" includes="*.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/annotations.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/asm-all.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/guava-19.0.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/guava-21.0.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/intellij-core.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/jdom.jar" excludes="META-INF/jb/** META-INF/LICENSE"/>
<zipfileset src="${basedir}/ideaSDK/core/jna.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/log4j.jar" excludes="META-INF/jb/** META-INF/LICENSE"/>
<zipfileset src="${basedir}/ideaSDK/core/picocontainer.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/snappy-in-java-0.5.1.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/streamex-0.6.2.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/trove4j.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/xpp3-1.1.4-min.jar"/>
<zipfileset src="${basedir}/ideaSDK/core/xstream-1.4.8.jar"/>
<zipfileset src="${idea.sdk}/lib/jna-platform.jar"/>
<zipfileset src="${idea.sdk}/lib/oromatcher.jar" excludes="META-INF/jb/** META-INF/LICENSE"/>
<zipfileset src="${idea.sdk}/jps/jps-model.jar"/>
<zipfileset src="${idea.sdk}/jps/jps-model.jar" excludes="META-INF/services/**"/>
<zipfileset src="${dependencies}/jline3.jar"/>
<zipfileset src="${dependencies}/jansi.jar"/>
<zipfileset src="${dependencies}/javaslang-2.0.6.jar"/>
@@ -1021,9 +1022,6 @@
<copy file="${basedir}/libraries/stdlib/src/kotlin/jvm/JvmVersion.kt" todir="${output}/mock-runtime-src"/>
<copy file="${basedir}/libraries/stdlib/src/kotlin/util/Standard.kt" todir="${output}/mock-runtime-src"/>
<copy file="${basedir}/libraries/stdlib/src/kotlin/internal/Annotations.kt" todir="${output}/mock-runtime-src"/>
<!-- Contracts -->
<copy file="${basedir}/libraries/stdlib/src/kotlin/internal/contracts/ContractBuilder.kt" todir="${output}/mock-runtime-src"/>
<copy file="${basedir}/libraries/stdlib/src/kotlin/internal/contracts/Effect.kt" todir="${output}/mock-runtime-src"/>
<new-kotlinc output="${output}/classes/mock-runtime" moduleName="kotlin-stdlib">
<src>

View File

@@ -33,14 +33,12 @@ repositories {
extra["buildSrcKotlinRepo"]?.let {
maven { setUrl(it) }
}
maven(url = "https://dl.bintray.com/kotlin/kotlin-dev") // for dex-method-list
// maven { setUrl("https://repo.gradle.org/gradle/libs-releases-local") }
jcenter()
}
dependencies {
compile(files("../dependencies/native-platform-uberjar.jar"))
compile("com.jakewharton.dex:dex-method-list:2.0.0-alpha")
// compile("net.rubygrapefruit:native-platform:0.14")
// TODO: adding the dep to the plugin breaks the build unexpectedly, resolve and uncomment
// compile("org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.extra["bootstrap_kotlin_version"]}")

View File

@@ -12,15 +12,14 @@ var Project.bootstrapKotlinRepo: String?
private set(value) { this.extra["bootstrapKotlinRepo"] = value }
fun Project.kotlinBootstrapFrom(defaultSource: BootstrapOption) {
val customVersion = project.findProperty("bootstrap.kotlin.version") as String?
val customRepo = project.findProperty("bootstrap.kotlin.repo") as String?
val teamCityVersion = project.findProperty("bootstrap.teamcity.kotlin.version") as String?
val teamCityProject = project.findProperty("bootstrap.teamcity.project") as String?
val bootstrapVersion = project.findProperty("bootstrap.kotlin.version") as String?
val bootstrapRepo = project.findProperty("bootstrap.kotlin.repo") as String?
val bootstrapTeamCityVersion = project.findProperty("bootstrap.teamcity.kotlin.version") as String?
val bootstrapSource = when {
project.hasProperty("bootstrap.local") -> BootstrapOption.Local(project.findProperty("bootstrap.local.version") as String?, project.findProperty("bootstrap.local.path") as String?)
teamCityVersion != null -> BootstrapOption.TeamCity(teamCityVersion, projectExtId = teamCityProject, onlySuccessBootstrap = false)
customVersion != null -> BootstrapOption.Custom(kotlinVersion = customVersion, repo = customRepo)
bootstrapTeamCityVersion != null -> BootstrapOption.TeamCity(bootstrapTeamCityVersion, onlySuccessBootstrap = false)
bootstrapVersion != null -> BootstrapOption.Custom(kotlinVersion = bootstrapVersion, repo = bootstrapRepo)
else -> defaultSource
}

View File

@@ -1,13 +1,12 @@
@file:Suppress("unused") // usages in build scripts are not tracked properly
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.*
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.project
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.kotlin.dsl.*
import java.io.File
@@ -30,11 +29,8 @@ fun Project.preloadedDeps(vararg artifactBaseNames: String, baseDir: File = File
throw GradleException("Invalid base directory $dir")
}
val matchingFiles = dir.listFiles { file -> artifactBaseNames.any { file.matchMaybeVersionedArtifact(it) } }
if (matchingFiles == null || matchingFiles.size < artifactBaseNames.size) {
throw GradleException("Not all matching artifacts '${artifactBaseNames.joinToString()}' found in the '$dir' " +
"(missing: ${artifactBaseNames.filterNot { request -> matchingFiles.any { it.matchMaybeVersionedArtifact(request) } }.joinToString()};" +
" found: ${matchingFiles?.joinToString { it.name }})")
}
if (matchingFiles == null || matchingFiles.size < artifactBaseNames.size)
throw GradleException("Not all matching artifacts '${artifactBaseNames.joinToString()}' found in the '$dir' (found: ${matchingFiles?.joinToString { it.name }})")
return files(*matchingFiles.map { it.canonicalPath }.toTypedArray())
}

View File

@@ -1,133 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.jakewharton.dex.*
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.*
import org.gradle.jvm.tasks.Jar
import java.io.File
open class DexMethodCount : DefaultTask() {
data class Counts(
val total: Int,
val totalOwnPackages: Int?,
val totalOtherPackages: Int?,
val byPackage: Map<String, Int>,
val byClass: Map<String, Int>
)
@InputFile
lateinit var jarFile: File
@Input
@Optional
var ownPackages: List<String>? = null
// ##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}' value='62362']
@Input
@Optional
var teamCityStatistics: Boolean? = null
@Input
@Optional
var artifactName: String? = null
private val artifactOrArchiveName get() = artifactName ?: project.name
fun from(jar: Jar) {
jarFile = jar.archivePath
artifactName = jar.baseName
dependsOn(jar)
}
lateinit var counts: Counts
@TaskAction
fun invoke() {
val methods = DexMethods.list(jarFile)
val counts = methods.getCounts().also { this.counts = it }
printTotals(counts)
printTCStats(counts)
outputDetails(counts)
}
private fun List<DexMethod>.getCounts(): Counts {
val byPackage = this.groupingBy { it.`package` }.eachCount()
val byClass = this.groupingBy { it.declaringType }.eachCount()
val ownPackages = ownPackages?.map { it + '.' }
val byOwnPackages = if (ownPackages != null) {
this.partition { method -> ownPackages.any { method.declaringType.startsWith(it) }}.let {
it.first.size to it.second.size
}
} else (null to null)
return Counts(total = this.size,
totalOwnPackages = byOwnPackages.first,
totalOtherPackages = byOwnPackages.second,
byPackage = byPackage,
byClass = byClass)
}
private fun printTotals(counts: Counts) {
logger.lifecycle("Artifact $artifactOrArchiveName, total methods: ${counts.total}")
ownPackages?.let { packages ->
logger.lifecycle("Artifact $artifactOrArchiveName, total methods from packages ${packages.joinToString { "$it.*" }}: ${counts.totalOwnPackages}")
logger.lifecycle("Artifact $artifactOrArchiveName, total methods from other packages: ${counts.totalOtherPackages}")
}
}
private fun printTCStats(counts: Counts) {
if (teamCityStatistics ?: project.hasProperty("teamcity")) {
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}' value='${counts.total}']")
counts.totalOwnPackages?.let { value ->
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}_OwnPackages' value='$value']")
}
counts.totalOtherPackages?.let { value ->
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}_OtherPackages' value='$value']")
}
}
}
private fun outputDetails(counts: Counts) {
val detailFile = project.buildDir.resolve("$artifactOrArchiveName-method-count.txt")
detailFile.printWriter().use { writer ->
writer.println("${counts.total.padRight()}\tTotal methods")
ownPackages?.let { packages ->
writer.println("${counts.totalOwnPackages?.padRight()}\tTotal methods from packages ${packages.joinToString { "$it.*" }}")
writer.println("${counts.totalOtherPackages?.padRight()}\tTotal methods from other packages")
}
writer.println()
writer.println("Method count by package:")
counts.byPackage.forEach { (name, count) ->
writer.println("${count.padRight()}\t$name")
}
writer.println()
writer.println("Method count by class:")
counts.byClass.forEach { (name, count) ->
writer.println("${count.padRight()}\t$name")
}
}
}
}
private val DexMethod.`package`: String get() = declaringType.substringBeforeLast('.')
private fun Int.padRight() = toString().padStart(5, ' ')

View File

@@ -1,15 +1,11 @@
@file:Suppress("unused") // usages in build scripts are not tracked properly
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.*
import org.gradle.api.internal.tasks.testing.filter.DefaultTestFilter
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.kotlin.dsl.*
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.task
import org.gradle.kotlin.dsl.the
import java.lang.Character.isLowerCase
import java.lang.Character.isUpperCase
fun Project.projectTest(taskName: String = "test", body: Test.() -> Unit = {}): Test = getOrCreateTask(taskName) {
doFirst {
@@ -17,29 +13,22 @@ fun Project.projectTest(taskName: String = "test", body: Test.() -> Unit = {}):
if (patterns.isEmpty() || patterns.any { '*' in it }) return@doFirst
patterns.forEach { pattern ->
val maybeMethodName = pattern.substringAfterLast('.')
val maybeClassFqName = if (maybeMethodName.isFirstChar(::isLowerCase))
val className = if (maybeMethodName.isNotEmpty() && maybeMethodName[0].isLowerCase())
pattern.substringBeforeLast('.')
else
pattern
if (!maybeClassFqName.substringAfterLast('.').isFirstChar(::isUpperCase)) {
return@forEach
}
val classFileNameWithoutExtension = maybeClassFqName.replace('.', '/')
val classFileName = classFileNameWithoutExtension + ".class"
val matchPattern = className.replace('.', '/') + ".class"
include {
val path = it.path
if (it.isDirectory) {
classFileNameWithoutExtension.startsWith(path)
matchPattern.startsWith(it.path)
} else {
path == classFileName || (path.endsWith(".class") && path.startsWith(classFileNameWithoutExtension + "$"))
it.path.endsWith(matchPattern)
}
}
}
}
jvmArgs("-ea", "-XX:+HeapDumpOnOutOfMemoryError", "-Xmx1100m", "-XX:+UseCodeCacheFlushing", "-XX:ReservedCodeCacheSize=128m", "-Djna.nosys=true")
maxHeapSize = "1100m"
systemProperty("idea.is.unit.test", "true")
@@ -47,10 +36,9 @@ fun Project.projectTest(taskName: String = "test", body: Test.() -> Unit = {}):
environment("PROJECT_CLASSES_DIRS", the<JavaPluginConvention>().sourceSets.getByName("test").output.classesDirs.asPath)
environment("PROJECT_BUILD_DIR", buildDir)
systemProperty("jps.kotlin.home", rootProject.extra["distKotlinHomeDir"])
ignoreFailures = System.getenv("kotlin_build_ignore_test_failures")?.let { it == "yes" } ?: false
body()
}
private inline fun String.isFirstChar(f: (Char) -> Boolean) = isNotEmpty() && f(first())
inline fun <reified T : Task> Project.getOrCreateTask(taskName: String, body: T.() -> Unit): T =
(tasks.findByName(taskName)?.let { it as T } ?: task<T>(taskName)).apply { body() }

View File

@@ -0,0 +1,175 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.tests;
import com.intellij.util.PlatformUtils;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.android.tests.download.SDKDownloader;
import org.jetbrains.kotlin.android.tests.emulator.Emulator;
import org.jetbrains.kotlin.android.tests.gradle.GradleRunner;
import org.jetbrains.kotlin.android.tests.run.PermissionManager;
import org.junit.Assert;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class CodegenTestsOnAndroidRunner {
private final PathManager pathManager;
public static TestSuite getTestSuite(PathManager pathManager) {
return new CodegenTestsOnAndroidRunner(pathManager).generateTestSuite();
}
private CodegenTestsOnAndroidRunner(PathManager pathManager) {
this.pathManager = pathManager;
}
private TestSuite generateTestSuite() {
TestSuite suite = new TestSuite("MySuite");
String resultOutput = runTests();
String reportFolder = pathManager.getTmpFolder() + "/build/outputs/androidTest-results/connected";
try {
List<TestCase> testCases = parseSingleReportInFolder(reportFolder);
for (TestCase aCase : testCases) {
suite.addTest(aCase);
}
Assert.assertNotEquals("There is no test results in report", 0, testCases.size());
}
catch (Exception e) {
throw new RuntimeException("Can't parse test results in " + reportFolder +"\n" + resultOutput);
}
return suite;
}
@Nullable
public String runTests() {
File rootForAndroidDependencies = new File(pathManager.getDependenciesRoot());
if (!rootForAndroidDependencies.exists()) {
rootForAndroidDependencies.mkdirs();
}
SDKDownloader downloader = new SDKDownloader(pathManager);
downloader.downloadAll();
downloader.unzipAll();
PermissionManager.setPermissions(pathManager);
Emulator emulator = new Emulator(pathManager, Emulator.ARM);
GradleRunner gradleRunner = new GradleRunner(pathManager);
gradleRunner.clean();
gradleRunner.build();
emulator.createEmulator();
String platformPrefixProperty = System.setProperty(PlatformUtils.PLATFORM_PREFIX_KEY, "Idea");
try {
emulator.startEmulator();
try {
emulator.waitEmulatorStart();
//runTestsViaAdb(emulator, gradleRunner);
return gradleRunner.connectedDebugAndroidTest();
}
catch (RuntimeException e) {
e.printStackTrace();
throw e;
}
finally {
emulator.stopEmulator();
}
}
catch (RuntimeException e) {
e.printStackTrace();
throw e;
}
finally {
if (platformPrefixProperty != null) {
System.setProperty(PlatformUtils.PLATFORM_PREFIX_KEY, platformPrefixProperty);
}
else {
System.clearProperty(PlatformUtils.PLATFORM_PREFIX_KEY);
}
emulator.finishEmulatorProcesses();
}
}
private String runTestsViaAdb(Emulator emulator, GradleRunner gradleRunner) {
gradleRunner.installDebugAndroidTest();
String result = emulator.runTestsViaAdb();
System.out.println(result);
gradleRunner.uninstallDebugAndroidTest();
return result;
}
private static List<TestCase> parseSingleReportInFolder(String reportFolder) throws
IOException,
SAXException,
ParserConfigurationException {
File folder = new File(reportFolder);
File[] files = folder.listFiles();
assert files != null;
assert files.length == 1;
File reportFile = files[0];
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(reportFile);
Element root = doc.getDocumentElement();
NodeList testCases = root.getElementsByTagName("testcase");
List<TestCase> result = new ArrayList(testCases.getLength());
for (int i = 0; i < testCases.getLength(); i++) {
Element item = (Element) testCases.item(i);
NodeList failure = item.getElementsByTagName("failure");
String name = item.getAttribute("name");
String clazz = item.getAttribute("classname");
if (failure.getLength() == 0) {
result.add(new TestCase(name) {
@Override
protected void runTest() throws Throwable {
}
});
}
else {
result.add(new TestCase(name) {
@Override
protected void runTest() throws Throwable {
Assert.fail(failure.item(0).getTextContent());
}
});
}
}
return result;
}
}

View File

@@ -1,189 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.tests
import com.intellij.util.PlatformUtils
import junit.framework.TestCase
import junit.framework.TestSuite
import org.jetbrains.kotlin.android.tests.download.SDKDownloader
import org.jetbrains.kotlin.android.tests.emulator.Emulator
import org.jetbrains.kotlin.android.tests.gradle.GradleRunner
import org.jetbrains.kotlin.android.tests.run.PermissionManager
import org.junit.Assert
import org.w3c.dom.Element
import org.xml.sax.SAXException
import java.io.File
import java.io.IOException
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.parsers.ParserConfigurationException
class CodegenTestsOnAndroidRunner private constructor(private val pathManager: PathManager) {
private fun runTestsInEmulator(): TestSuite {
val rootSuite = TestSuite("Root")
downloadDependencies()
val emulator = Emulator(pathManager, Emulator.ARM)
emulator.createEmulator()
val gradleRunner = GradleRunner(pathManager)
//old dex
cleanAndBuildProject(gradleRunner)
try {
emulator.startEmulator()
try {
emulator.waitEmulatorStart()
runTestsOnEmulator(gradleRunner, TestSuite("Dex")).apply {
rootSuite.addTest(this)
}
enableD8(true)
runTestsOnEmulator(gradleRunner, TestSuite("D8")).apply {
(0 until this.countTestCases()).forEach {
val testCase = testAt(it) as TestCase
testCase.name += "_D8"
}
rootSuite.addTest(this)
}
}
catch (e: RuntimeException) {
e.printStackTrace()
throw e
}
finally {
emulator.stopEmulator()
}
}
catch (e: RuntimeException) {
e.printStackTrace()
throw e
}
finally {
emulator.finishEmulatorProcesses()
}
return rootSuite
}
private fun enableD8(enable: Boolean) {
val file = File(pathManager.androidTmpFolder, "gradle.properties")
val lines = file.readLines().map {
if (it.startsWith("android.enableD8=")) {
"android.enableD8=$enable"
}
else it
}
file.writeText(lines.joinToString("\n"))
}
private fun processReport(suite: TestSuite, resultOutput: String) {
val reportFolder = pathManager.tmpFolder + "/build/outputs/androidTest-results/connected"
try {
val testCases = parseSingleReportInFolder(reportFolder)
testCases.forEach { aCase -> suite.addTest(aCase) }
Assert.assertNotEquals("There is no test results in report", 0, testCases.size.toLong())
}
catch (e: Exception) {
throw RuntimeException("Can't parse test results in " + reportFolder + "\n" + resultOutput)
}
}
private fun runTestsOnEmulator(gradleRunner: GradleRunner, suite: TestSuite): TestSuite {
val platformPrefixProperty = System.setProperty(PlatformUtils.PLATFORM_PREFIX_KEY, "Idea")
try {
val resultOutput = gradleRunner.connectedDebugAndroidTest()
processReport(suite, resultOutput)
return suite
}
finally {
if (platformPrefixProperty != null) {
System.setProperty(PlatformUtils.PLATFORM_PREFIX_KEY, platformPrefixProperty)
}
else {
System.clearProperty(PlatformUtils.PLATFORM_PREFIX_KEY)
}
}
}
private fun downloadDependencies() {
val rootForAndroidDependencies = File(pathManager.dependenciesRoot)
if (!rootForAndroidDependencies.exists()) {
rootForAndroidDependencies.mkdirs()
}
val downloader = SDKDownloader(pathManager)
downloader.downloadAll()
downloader.unzipAll()
PermissionManager.setPermissions(pathManager)
}
companion object {
@JvmStatic
fun runTestsInEmulator(pathManager: PathManager): TestSuite {
return CodegenTestsOnAndroidRunner(pathManager).runTestsInEmulator()
}
private fun cleanAndBuildProject(gradleRunner: GradleRunner) {
gradleRunner.clean()
gradleRunner.build()
}
@Throws(IOException::class, SAXException::class, ParserConfigurationException::class)
private fun parseSingleReportInFolder(reportFolder: String): List<TestCase> {
val folder = File(reportFolder)
val files = folder.listFiles()!!
assert(files.size == 1)
val reportFile = files[0]
val dbFactory = DocumentBuilderFactory.newInstance()
val dBuilder = dbFactory.newDocumentBuilder()
val doc = dBuilder.parse(reportFile)
val root = doc.documentElement
val testCases = root.getElementsByTagName("testcase")
return (0 until testCases.length).map { i ->
val item = testCases.item(i) as Element
val failure = item.getElementsByTagName("failure")
val name = item.getAttribute("name")
val clazz = item.getAttribute("classname")
if (failure.length == 0) {
object : TestCase(name) {
@Throws(Throwable::class)
override fun runTest() {
}
}
}
else {
object : TestCase(name) {
@Throws(Throwable::class)
override fun runTest() {
Assert.fail(failure.item(0).textContent)
}
}
}
}
}
}
}

View File

@@ -68,10 +68,6 @@ public class PathManager {
return tmpFolder + "/src";
}
public String getAndroidTmpFolder() {
return tmpFolder;
}
public String getAndroidSdkRoot() {
return getDependenciesRoot() + "/android-sdk";
}

View File

@@ -17,12 +17,10 @@
package org.jetbrains.kotlin.android.tests;
import org.jetbrains.kotlin.jps.build.BaseKotlinJpsBuildTestCase;
import org.junit.Ignore;
import java.io.File;
import java.io.IOException;
@Ignore
public class AndroidJpsBuildTestCase extends BaseKotlinJpsBuildTestCase {
private static final String PROJECT_NAME = "android-module";
private static final String SDK_NAME = "Android_SDK";
@@ -31,8 +29,8 @@ public class AndroidJpsBuildTestCase extends BaseKotlinJpsBuildTestCase {
public void doTest() {
initProject();
rebuildAll();
makeAll().assertSuccessful();
rebuildAllModules();
buildAllModules().assertSuccessful();
}
@Override

View File

@@ -20,15 +20,12 @@ import com.google.common.io.Files;
import com.intellij.openapi.util.io.FileUtil;
import junit.framework.TestSuite;
import org.jetbrains.annotations.NotNull;
import org.junit.runner.RunWith;
import org.junit.runners.AllTests;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@RunWith(AllTests.class)
public class AndroidRunner {
public class AndroidRunner extends TestSuite {
private static PathManager pathManager;
@@ -52,7 +49,7 @@ public class AndroidRunner {
CodegenTestsOnAndroidGenerator.generate(pathManager);
System.out.println("Run tests on android...");
TestSuite suite = CodegenTestsOnAndroidRunner.runTestsInEmulator(pathManager);
TestSuite suite = CodegenTestsOnAndroidRunner.getTestSuite(pathManager);
//AndroidJpsBuildTestCase indirectly depends on UsefulTestCase which compiled against java 8
//TODO: Need add separate run configuration for AndroidJpsBuildTestCase
//suite.addTest(new AndroidJpsBuildTestCase());

View File

@@ -42,14 +42,12 @@ import org.jetbrains.kotlin.test.*;
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase;
import org.jetbrains.kotlin.utils.Printer;
import org.junit.Assert;
import org.junit.Ignore;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Ignore
public class CodegenTestsOnAndroidGenerator extends KtUsefulTestCase {
private final PathManager pathManager;

View File

@@ -123,13 +123,6 @@ public class SpecialFiles {
excludedFiles.add("closureOfInnerLocalClass.kt");
excludedFiles.add("closureWithSelfInstantiation.kt");
excludedFiles.add("quotedClassName.kt");
//wrong function resolution after package renaming
excludedFiles.add("apiVersionAtLeast1.kt");
//special flags
excludedFiles.add("inlineFunInConstructorCallWithEnabledNormalization.kt");
excludedFiles.add("kt9532_lv10.kt");
}
private SpecialFiles() {

View File

@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil;
@@ -51,7 +52,6 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
import org.jetbrains.kotlin.codegen.when.SwitchCodegenProvider;
import org.jetbrains.kotlin.config.ApiVersion;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
@@ -74,12 +74,12 @@ import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
import org.jetbrains.kotlin.resolve.constants.*;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluatorKt;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.JvmBindingContextSlices;
import org.jetbrains.kotlin.resolve.jvm.JvmConstantsKt;
import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
@@ -308,12 +308,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
RuntimeAssertionInfo runtimeAssertionInfo = null;
if (selector instanceof KtExpression) {
KtExpression expression = (KtExpression) selector;
runtimeAssertionInfo = bindingContext.get(JvmBindingContextSlices.RUNTIME_ASSERTION_INFO, expression);
if (runtimeAssertionInfo == null &&
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.StrictJavaNullabilityAssertions)) {
runtimeAssertionInfo = bindingContext.get(JvmBindingContextSlices.BODY_RUNTIME_ASSERTION_INFO, expression);
}
runtimeAssertionInfo = bindingContext.get(JvmBindingContextSlices.RUNTIME_ASSERTION_INFO, (KtExpression) selector);
}
if (BuiltinSpecialBridgesKt.isValueArgumentForCallToMethodWithTypeCheckBarrier(selector, bindingContext)) return stackValue;
@@ -791,7 +786,49 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
boolean takeUpConstValsAsConst,
boolean shouldInlineConstVals
) {
return JvmConstantsKt.getCompileTimeConstant(expression, bindingContext, takeUpConstValsAsConst, shouldInlineConstVals);
CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, bindingContext);
if (compileTimeValue == null || compileTimeValue.getUsesNonConstValAsConstant()) {
return null;
}
if (!shouldInlineConstVals && !takeUpConstValsAsConst && compileTimeValue.getUsesVariableAsConstant()) {
Ref<Boolean> containsNonInlinedVals = new Ref<>(false);
KtVisitor constantChecker = new KtVisitor() {
@Override
public Object visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, Object data) {
ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
if (resolvedCall != null) {
CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
if (callableDescriptor instanceof PropertyDescriptor &&
!JvmCodegenUtil.isInlinedJavaConstProperty((VariableDescriptor) callableDescriptor)) {
containsNonInlinedVals.set(true);
}
}
return null;
}
@Override
public Object visitKtElement(@NotNull KtElement element, Object data) {
if (!containsNonInlinedVals.get()) {
element.acceptChildren(this);
}
return null;
}
};
expression.accept(constantChecker);
if (containsNonInlinedVals.get()) {
return null;
}
}
KotlinType expectedType = bindingContext.getType(expression);
if (expectedType == null) {
return null;
}
return compileTimeValue.toConstantValue(expectedType);
}
@Override
@@ -1723,12 +1760,22 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
private boolean shouldGenerateSingletonAsThisOrOuterFromContext(ClassDescriptor classDescriptor) {
return isPossiblyUninitializedSingleton(classDescriptor) &&
isInsideSingleton(classDescriptor) &&
isThisInitialized(classDescriptor);
}
if (!isPossiblyUninitializedSingleton(classDescriptor)) return false;
if (!isInsideSingleton(classDescriptor)) return false;
// We are inside a singleton class 'S' with possibly uninitialized static instance
// (enum entry, interface companion object).
// Such singleton can be referenced by name, or as an explicit or implicit 'this'.
// For a given singleton class 'S' we either use 'this@S' from context (local or captured),
// or 'S' as a static instance.
//
// Local or captured 'this@S' should be used if:
// - we are in the constructor for 'S',
// and corresponding instance is initialized by super or delegating constructor call;
// - we are in any other member of 'S' or any of its inner classes.
//
// Otherwise, a static instance should be used.
private boolean isThisInitialized(ClassDescriptor classDescriptor) {
CodegenContext context = this.context;
while (context != null) {
if (context instanceof ConstructorContext) {
@@ -1738,9 +1785,24 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return constructorContext.isThisInitialized();
}
}
else if (context instanceof ClassContext) {
ClassDescriptor contextClass = ((ClassContext) context).getContextDescriptor();
if (isInInnerClassesChainFor(contextClass, classDescriptor)) {
return true;
}
}
context = context.getParentContext();
}
return true;
return false;
}
private static boolean isInInnerClassesChainFor(ClassDescriptor innerClass, ClassDescriptor outerClass) {
if (innerClass == outerClass) return true;
if (!innerClass.isInner()) return false;
DeclarationDescriptor containingDeclaration = innerClass.getContainingDeclaration();
if (!(containingDeclaration instanceof ClassDescriptor)) return false;
return isInInnerClassesChainFor((ClassDescriptor) containingDeclaration, outerClass);
}
@Nullable
@@ -2790,7 +2852,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@Nullable
public StackValue generateCallableReferenceReceiver(@NotNull ResolvedCall<?> resolvedCall) {
private StackValue generateCallableReferenceReceiver(@NotNull ResolvedCall<?> resolvedCall) {
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
if (descriptor.getExtensionReceiverParameter() == null && descriptor.getDispatchReceiverParameter() == null) return null;

View File

@@ -34,7 +34,7 @@ public class FieldInfo {
}
if (isNonCompanionObject(classDescriptor) || CompanionObjectMapping.INSTANCE.isMappedIntrinsicCompanionObject(classDescriptor)) {
return createSingletonViaInstance(classDescriptor, typeMapper, JvmAbi.INSTANCE_FIELD);
return createSingletonViaInstance(classDescriptor, typeMapper);
}
ClassDescriptor ownerDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
@@ -46,11 +46,10 @@ public class FieldInfo {
@NotNull
public static FieldInfo createSingletonViaInstance(
@NotNull ClassDescriptor classDescriptor,
@NotNull KotlinTypeMapper typeMapper,
@NotNull String name
@NotNull KotlinTypeMapper typeMapper
) {
Type type = typeMapper.mapType(classDescriptor);
return new FieldInfo(type, type, name, true);
return new FieldInfo(type, type, JvmAbi.INSTANCE_FIELD, true);
}
@NotNull

View File

@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode;
import org.jetbrains.kotlin.name.ClassId;
@@ -76,7 +77,6 @@ import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isNonGenericToArray;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtils2Kt.initDefaultSourceMappingIfNeeded;
import static org.jetbrains.kotlin.load.java.JvmAbi.*;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull;
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
@@ -354,8 +354,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
protected void generateSyntheticPartsAfterBody() {
generateFieldForSingleton();
initializeObjects();
generateCompanionObjectBackingFieldCopies();
generateTraitMethods();
@@ -813,21 +811,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateFieldForSingleton() {
if (isCompanionObjectInInterfaceNotIntrinsic(descriptor)) {
StackValue.Field field = StackValue.createSingletonViaInstance(descriptor, typeMapper, HIDDEN_INSTANCE_FIELD);
//hidden instance in interface companion
v.newField(JvmDeclarationOriginKt.OtherOrigin(descriptor),
ACC_SYNTHETIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
}
if (isEnumEntry(descriptor) || isCompanionObject(descriptor)) return;
if (isNonCompanionObject(descriptor)) {
StackValue.Field field = StackValue.createSingletonViaInstance(descriptor, typeMapper, INSTANCE_FIELD);
StackValue.Field field = StackValue.singletonViaInstance(descriptor, typeMapper);
v.newField(JvmDeclarationOriginKt.OtherOriginFromPure(myClass),
ACC_PUBLIC | ACC_STATIC | ACC_FINAL,
field.name, field.type.getDescriptor(), null, null);
if (!state.getClassBuilderMode().generateBodies) return;
// Invoke the object constructor but ignore the result because INSTANCE will be initialized in the first line of <init>
InstructionAdapter v = createOrGetClInitCodegen().v;
markLineNumberForElement(element.getPsiOrParent(), v);
v.anew(classAsmType);
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false);
return;
}
@@ -855,60 +853,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
private void initializeObjects() {
if (!DescriptorUtils.isObject(descriptor)) return;
if (!state.getClassBuilderMode().generateBodies) return;
boolean isNonCompanionObject = isNonCompanionObject(descriptor);
boolean isInterfaceCompanion = isCompanionObjectInInterfaceNotIntrinsic(descriptor);
boolean isMappedIntrinsicCompanionObject = isMappedIntrinsicCompanionObject(descriptor);
if (isNonCompanionObject || isInterfaceCompanion || isMappedIntrinsicCompanionObject) {
ExpressionCodegen clInitCodegen = createOrGetClInitCodegen();
InstructionAdapter v = clInitCodegen.v;
markLineNumberForElement(element.getPsiOrParent(), v);
v.anew(classAsmType);
v.dup();
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false);
//local0 emulates this in object constructor
int local0Index = clInitCodegen.getFrameMap().enterTemp(classAsmType);
assert local0Index == 0 : "Local variable with index 0 in clInit should be used only for singleton instance keeping";
StackValue.Local local0 = StackValue.local(0, classAsmType);
local0.store(StackValue.onStack(classAsmType), clInitCodegen.v);
StackValue.Field singleton =
StackValue.createSingletonViaInstance(
descriptor, typeMapper, isInterfaceCompanion ? HIDDEN_INSTANCE_FIELD : INSTANCE_FIELD
);
singleton.store(local0, clInitCodegen.v);
generateInitializers(clInitCodegen);
if (isInterfaceCompanion) {
//initialize singleton instance in outer by hidden instance
StackValue.singleton(descriptor, typeMapper).store(
singleton, getParentCodegen().createOrGetClInitCodegen().v, true
);
}
}
else if (isCompanionObjectWithBackingFieldsInOuter(descriptor)) {
ImplementationBodyCodegen parentCodegen = (ImplementationBodyCodegen) getParentCodegen();
ExpressionCodegen parentClInitCodegen = parentCodegen.createOrGetClInitCodegen();
InstructionAdapter parentVisitor = parentClInitCodegen.v;
FunctionDescriptor constructor = (FunctionDescriptor) parentCodegen.context.accessibleDescriptor(
CollectionsKt.single(descriptor.getConstructors()), /* superCallExpression = */ null
);
parentCodegen.generateMethodCallTo(constructor, null, parentVisitor);
StackValue instance = StackValue.onStack(parentCodegen.typeMapper.mapClass(descriptor));
StackValue.singleton(descriptor, parentCodegen.typeMapper).store(instance, parentVisitor, true);
generateInitializers(parentClInitCodegen);
}
else {
assert false : "Unknown object type: " + descriptor;
}
}
private void generateCompanionObjectBackingFieldCopies() {
if (companionObjectPropertiesToCopy == null) return;
@@ -956,6 +900,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
field.store(property, codegen.v);
}
private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) {
ExpressionCodegen codegen = createOrGetClInitCodegen();
FunctionDescriptor constructor = (FunctionDescriptor) context.accessibleDescriptor(
CollectionsKt.single(companionObject.getConstructors()), /* superCallExpression = */ null
);
generateMethodCallTo(constructor, null, codegen.v);
StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject));
StackValue.singleton(companionObject, typeMapper).store(instance, codegen.v, true);
}
private void generatePrimaryConstructor(DelegationFieldsInfo delegationFieldsInfo) {
if (isInterface(descriptor) || isAnnotationClass(descriptor)) return;
@@ -1023,6 +978,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor,
getDelegationConstructorCall(bindingContext, constructorDescriptor));
if (isNonCompanionObject(descriptor)) {
StackValue.singletonViaInstance(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
}
for (KtSuperTypeListEntry specifier : myClass.getSuperTypeListEntries()) {
if (specifier instanceof KtDelegatedSuperTypeEntry) {
genCallToDelegatorByExpressionSpecifier(iv, codegen, (KtDelegatedSuperTypeEntry) specifier, fieldsInfo);
@@ -1044,10 +1003,18 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
curParam++;
}
//object initialization was moved to initializeObjects()
if (!isObject(descriptor)) {
if (isCompanionObject(descriptor)) {
ImplementationBodyCodegen parentCodegen = (ImplementationBodyCodegen) getParentCodegen();
parentCodegen.generateCompanionObjectInitializer(descriptor);
}
if (JvmAbi.isCompanionObjectWithBackingFieldsInOuter(descriptor)) {
generateInitializers(((ImplementationBodyCodegen) getParentCodegen())::createOrGetClInitCodegen);
}
else {
generateInitializers(codegen);
}
iv.visitInsn(RETURN);
}
@@ -1192,7 +1159,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (asmType == null) continue;
result.addField((KtDelegatedSuperTypeEntry) specifier, asmType, DELEGATE_SUPER_FIELD_PREFIX + n);
result.addField((KtDelegatedSuperTypeEntry) specifier, asmType, JvmAbi.DELEGATE_SUPER_FIELD_PREFIX + n);
}
n++;
}

View File

@@ -42,7 +42,6 @@ import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.jvm.JvmConstantsKt;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor;
@@ -295,7 +294,8 @@ public class JvmCodegenUtil {
}
public static boolean isInlinedJavaConstProperty(VariableDescriptor descriptor) {
return descriptor instanceof JavaPropertyDescriptor && descriptor.isConst();
if (!(descriptor instanceof JavaPropertyDescriptor)) return false;
return descriptor.isConst();
}
@Nullable

View File

@@ -31,10 +31,8 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl;
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
import org.jetbrains.kotlin.serialization.ProtoBuf;
import org.jetbrains.org.objectweb.asm.Type;
@@ -43,7 +41,6 @@ import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.kotlin.codegen.AsmUtil.writeAnnotationData;
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
public class PackagePartCodegen extends MemberCodegen<KtFile> {
@@ -107,12 +104,6 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.FILE_FACADE, 0, av -> {
writeAnnotationData(av, serializedPart.getFirst(), serializedPart.getSecond());
FqName kotlinPackageFqName = element.getPackageFqName();
if (!kotlinPackageFqName.equals(JvmClassName.byInternalName(packagePartType.getInternalName()).getPackageFqName())) {
av.visit(METADATA_PACKAGE_NAME_FIELD_NAME, kotlinPackageFqName.asString());
}
return Unit.INSTANCE;
});
}

View File

@@ -621,8 +621,8 @@ public abstract class StackValue {
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper), none());
}
public static Field createSingletonViaInstance(@NotNull ClassDescriptor classDescriptor, @NotNull KotlinTypeMapper typeMapper, @NotNull String name) {
return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper, name), none());
public static Field singletonViaInstance(ClassDescriptor classDescriptor, KotlinTypeMapper typeMapper) {
return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper), none());
}
public static StackValue operation(Type type, Function1<InstructionAdapter, Unit> lambda) {

View File

@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.codegen.when.SwitchCodegenProvider;
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.coroutines.CoroutineUtilKt;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
@@ -57,7 +56,6 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.constants.EnumValue;
import org.jetbrains.kotlin.resolve.constants.NullValue;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionsOnDeclarationBodyChecker;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
import org.jetbrains.kotlin.types.KotlinType;
@@ -88,8 +86,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
private final JvmRuntimeTypes runtimeTypes;
private final TypeMappingConfiguration<Type> typeMappingConfiguration;
private final SwitchCodegenProvider switchCodegenProvider;
private final LanguageVersionSettings languageVersionSettings;
private final ClassBuilderMode classBuilderMode;
public CodegenAnnotatingVisitor(@NotNull GenerationState state) {
this.bindingTrace = state.getBindingTrace();
@@ -98,8 +94,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
this.runtimeTypes = state.getJvmRuntimeTypes();
this.typeMappingConfiguration = state.getTypeMapper().getTypeMappingConfiguration();
this.switchCodegenProvider = new SwitchCodegenProvider(state);
this.languageVersionSettings = state.getLanguageVersionSettings();
this.classBuilderMode = state.getClassBuilderMode();
}
@NotNull
@@ -417,8 +411,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
// working around a problem with shallow analysis
if (descriptor == null) return;
checkRuntimeAsserionsOnDeclarationBody(property, descriptor);
if (descriptor instanceof LocalVariableDescriptor) {
recordLocalVariablePropertyMetadata((LocalVariableDescriptor) descriptor);
}
@@ -455,14 +447,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
nameStack.pop();
}
private void checkRuntimeAsserionsOnDeclarationBody(@NotNull KtDeclaration declaration, DeclarationDescriptor descriptor) {
if (classBuilderMode.generateBodies) {
// NB This is required only for bodies generation.
// In light class generation can cause recursion in types resolution.
RuntimeAssertionsOnDeclarationBodyChecker.check(declaration, descriptor, bindingTrace, languageVersionSettings);
}
}
@NotNull
private Type getMetadataOwner(@NotNull KtProperty property) {
for (int i = classStack.size() - 1; i >= 0; i--) {
@@ -485,24 +469,12 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
return Type.getObjectType(JvmFileClassUtil.getFileClassInternalName(property.getContainingKtFile()));
}
@Override
public void visitPropertyAccessor(@NotNull KtPropertyAccessor accessor) {
PropertyAccessorDescriptor accessorDescriptor = bindingContext.get(PROPERTY_ACCESSOR, accessor);
if (accessorDescriptor != null) {
checkRuntimeAsserionsOnDeclarationBody(accessor, accessorDescriptor);
}
super.visitPropertyAccessor(accessor);
}
@Override
public void visitNamedFunction(@NotNull KtNamedFunction function) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, function);
// working around a problem with shallow analysis
if (functionDescriptor == null) return;
checkRuntimeAsserionsOnDeclarationBody(function, functionDescriptor);
String nameForClassOrPackageMember = getNameForClassOrPackageMember(functionDescriptor);
if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) {

View File

@@ -20,8 +20,7 @@ import com.intellij.psi.PsiElement
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
import org.jetbrains.kotlin.codegen.AsmUtil.*
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineOrReturn
import org.jetbrains.kotlin.codegen.coroutines.isBuiltInSuspendCoroutineOrReturnInJvm
import org.jetbrains.kotlin.codegen.intrinsics.bytecode
@@ -30,9 +29,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.isInlineOnly
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
@@ -50,15 +47,13 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral
import org.jetbrains.kotlin.types.expressions.LabelResolver
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.util.*
import kotlin.collections.HashSet
abstract class InlineCodegen<out T: BaseExpressionCodegen>(
protected val codegen: T,
@@ -184,46 +179,6 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
}
}
private fun canSkipStackSpillingOnInline(methodNode: MethodNode): Boolean {
// Stack spilling before inline function 'f' call is required if:
// - 'f' is a suspend function
// - 'f' has try-catch blocks
// - 'f' has loops
//
// Instead of checking for loops precisely, we just check if there are any backward jumps -
// that is, a jump from instruction #i to instruction #j where j < i
if (functionDescriptor.isSuspend) return false
if (methodNode.tryCatchBlocks.isNotEmpty()) return false
fun isBackwardJump(fromIndex: Int, toLabel: LabelNode) =
methodNode.instructions.indexOf(toLabel) < fromIndex
val insns = methodNode.instructions.toArray()
for (i in insns.indices) {
val insn = insns[i]
when (insn) {
is JumpInsnNode ->
if (isBackwardJump(i, insn.label)) return false
is LookupSwitchInsnNode -> {
insn.dflt?.let {
if (isBackwardJump(i, it)) return false
}
if (insn.labels.any { isBackwardJump(i, it) }) return false
}
is TableSwitchInsnNode -> {
insn.dflt?.let {
if (isBackwardJump(i, it)) return false
}
if (insn.labels.any { isBackwardJump(i, it) }) return false
}
}
}
return true
}
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult {
assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" }
@@ -246,11 +201,7 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
//through generation captured parameters will be added to invocationParamBuilder
putClosureParametersOnStack()
val shouldSpillStack = !canSkipStackSpillingOnInline(node)
if (shouldSpillStack) {
addInlineMarker(codegen.v, true)
}
addInlineMarker(codegen.v, true)
val parameters = invocationParamBuilder.buildParameters()
@@ -263,8 +214,7 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
node, parameters, info, FieldRemapper(null, null, parameters), isSameModule,
"Method inlining " + sourceCompiler.callElementText,
createNestedSourceMapper(nodeAndSmap, defaultSourceMapper), info.callSiteInfo,
if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null,
!isInlinedToInlineFunInKotlinRuntime()
if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null
) //with captured
val remapper = LocalVarRemapper(parameters, initialFrameSize)
@@ -289,23 +239,13 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
adapter.accept(MethodBodyVisitor(codegen.v))
if (shouldSpillStack) {
addInlineMarker(codegen.v, false)
}
addInlineMarker(codegen.v, false)
defaultSourceMapper.callSiteMarker = null
return result
}
private fun isInlinedToInlineFunInKotlinRuntime(): Boolean {
val codegen = this.codegen as? ExpressionCodegen ?: return false
val caller = codegen.context.functionDescriptor
if (!caller.isInline) return false
val callerPackage = DescriptorUtils.getParentOfType(caller, PackageFragmentDescriptor::class.java) ?: return false
return callerPackage.fqName.asString().startsWith("kotlin.")
}
private fun generateClosuresBodies() {
for (info in expressionMap.values) {
info.generateLambdaBody(sourceCompiler, reifiedTypeInliner)

View File

@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ClosureCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
@@ -47,8 +46,7 @@ class MethodInliner(
private val errorPrefix: String,
private val sourceMapper: SourceMapper,
private val inlineCallSiteInfo: InlineCallSiteInfo,
private val inlineOnlySmapSkipper: InlineOnlySmapSkipper?, //non null only for root
private val shouldPreprocessApiVersionCalls: Boolean = false
private val inlineOnlySmapSkipper: InlineOnlySmapSkipper? //non null only for root
) {
private val typeMapper = inliningContext.state.typeMapper
private val invokeCalls = ArrayList<InvokeCall>()
@@ -396,9 +394,9 @@ class MethodInliner(
): MethodNode {
val processingNode = prepareNode(node, finallyDeepShift)
preprocessNodeBeforeInline(processingNode, labelOwner)
normalizeLocalReturns(processingNode, labelOwner)
val sources = analyzeMethodNodeBeforeInline(processingNode)
val sources = analyzeMethodNodeWithoutMandatoryTransformations(processingNode)
val toDelete = SmartSet.create<AbstractInsnNode>()
val instructions = processingNode.instructions
@@ -510,19 +508,7 @@ class MethodInliner(
return processingNode
}
private fun preprocessNodeBeforeInline(node: MethodNode, labelOwner: LabelOwner) {
try {
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
}
catch (e: Throwable) {
throw wrapException(e, node, "couldn't inline method call")
}
if (shouldPreprocessApiVersionCalls) {
val targetApiVersion = inliningContext.state.languageVersionSettings.apiVersion
ApiVersionCallsPreprocessingMethodTransformer(targetApiVersion).transform("fake", node)
}
private fun normalizeLocalReturns(node: MethodNode, labelOwner: LabelOwner) {
val frames = analyzeMethodNodeBeforeInline(node)
val localReturnsNormalizer = LocalReturnsNormalizer()
@@ -554,6 +540,17 @@ class MethodInliner(
return info != null && info.shouldRegenerate(true)
}
private fun analyzeMethodNodeBeforeInline(node: MethodNode): Array<Frame<SourceValue>?> {
try {
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
}
catch (e: Throwable) {
throw wrapException(e, node, "couldn't inline method call")
}
return analyzeMethodNodeWithoutMandatoryTransformations(node)
}
private fun buildConstructorInvocation(
anonymousType: String,
desc: String,
@@ -732,7 +729,7 @@ class MethodInliner(
)
}
private fun analyzeMethodNodeBeforeInline(node: MethodNode): Array<Frame<SourceValue>?> {
private fun analyzeMethodNodeWithoutMandatoryTransformations(node: MethodNode): Array<Frame<SourceValue>?> {
val analyzer = object : Analyzer<SourceValue>(SourceInterpreter()) {
override fun newFrame(nLocals: Int, nStack: Int): Frame<SourceValue> {
return object : Frame<SourceValue>(nLocals, nStack) {

View File

@@ -69,7 +69,7 @@ internal const val THIS = "this"
internal const val THIS_0 = "this$0"
internal const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
internal const val SPECIAL_TRANSFORMATION_NAME = "\$special"
const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
internal const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
internal const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
internal const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"

View File

@@ -36,9 +36,9 @@ object LateinitIsInitialized : IntrinsicPropertyGetter() {
private fun getStackValue(resolvedCall: ResolvedCall<*>, codegen: ExpressionCodegen): StackValue? {
val expression =
(resolvedCall.extensionReceiver as? ExpressionReceiver)?.expression as? KtCallableReferenceExpression ?: return null
val referenceResolvedCall = expression.callableReference.getResolvedCallWithAssert(codegen.bindingContext)
val receiver = codegen.generateCallableReferenceReceiver(referenceResolvedCall) ?: StackValue.none()
// TODO: support properties imported from objects as soon as KT-18982 is fixed
val receiver = expression.receiverExpression?.let(codegen::gen) ?: StackValue.none()
val target = expression.callableReference.getResolvedCallWithAssert(codegen.bindingContext).resultingDescriptor
return codegen.intermediateValueForProperty(target as PropertyDescriptor, true, false, null, false, receiver, null, true)

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization
import org.jetbrains.kotlin.codegen.optimization.boxing.isMethodInsnWith
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.MavenComparableVersion
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.*
class ApiVersionCallsPreprocessingMethodTransformer(private val targetApiVersion: ApiVersion) : MethodTransformer() {
private val constantConditionElimination = ConstantConditionEliminationMethodTransformer()
override fun transform(internalClassName: String, methodNode: MethodNode) {
var hasFoldedCalls = false
for (insn in methodNode.instructions.toArray()) {
if (!insn.isApiVersionIsAtLeastCall()) continue
val prev3 = insn.previous ?: continue
val minor = prev3.getIntConstValue() ?: continue
val prev2 = prev3.previous ?: continue
val major = prev2.getIntConstValue() ?: continue
val prev1 = prev2.previous ?: continue
val epic = prev1.getIntConstValue() ?: continue
hasFoldedCalls = true
val atLeastVersion = MavenComparableVersion("$epic.$major.$minor")
val replacementInsn =
if (targetApiVersion.version >= atLeastVersion)
InsnNode(Opcodes.ICONST_1)
else
InsnNode(Opcodes.ICONST_0)
methodNode.instructions.run {
remove(prev1)
remove(prev2)
remove(prev3)
set(insn, replacementInsn)
}
}
if (hasFoldedCalls) {
constantConditionElimination.transform(internalClassName, methodNode)
}
}
private fun AbstractInsnNode.isApiVersionIsAtLeastCall(): Boolean =
isMethodInsnWith(Opcodes.INVOKESTATIC) {
owner.startsWith("kotlin/internal") &&
name == "apiVersionIsAtLeast" &&
desc == "(III)Z"
}
private fun AbstractInsnNode.getIntConstValue(): Int? =
when (this) {
is InsnNode ->
if (opcode in Opcodes.ICONST_M1..Opcodes.ICONST_5)
opcode - Opcodes.ICONST_0
else
null
is IntInsnNode ->
when (opcode) {
Opcodes.BIPUSH -> operand
Opcodes.SIPUSH -> operand
else -> null
}
is LdcInsnNode -> cst as? Int
else -> null
}
}

View File

@@ -19,8 +19,6 @@ package org.jetbrains.kotlin.codegen.optimization.nullCheck
import org.jetbrains.kotlin.codegen.optimization.boxing.*
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.kotlin.codegen.pseudoInsns.isPseudo
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
@@ -74,8 +72,6 @@ class NullabilityInterpreter : OptimizationBasicInterpreter() {
ProgressionIteratorBasicValue.byProgressionClassType(values[0].type)
insn.isNextMethodCallOfProgressionIterator(values) ->
NotNullBasicValue(resultType)
insn.isPseudo(PseudoInsn.AS_NOT_NULL) ->
NotNullBasicValue(values[0].type)
else ->
defaultResult
}

View File

@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.codegen.optimization.nullCheck
import org.jetbrains.kotlin.codegen.coroutines.withInstructionAdapter
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.codegen.optimization.common.debugText
import org.jetbrains.kotlin.codegen.optimization.common.isInsn
@@ -26,12 +28,12 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.kotlin.codegen.pseudoInsns.asNotNull
import org.jetbrains.kotlin.codegen.pseudoInsns.isPseudo
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.*
@@ -44,19 +46,59 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
private var changes = false
fun run(): Boolean {
if (methodNode.instructions.toArray().none { it.isOptimizable() }) return false
val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode()
eliminateRedundantChecks(checkedReferenceTypes)
val nullabilityAssumptions = NullabilityAssumptionsBuilder().injectNullabilityAssumptions()
return changes
}
private fun analyzeTypesAndRemoveDeadCode(): Map<AbstractInsnNode, Type> {
val insns = methodNode.instructions.toArray()
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
val relevantReferenceTypes = HashMap<AbstractInsnNode, Type>()
insnLoop@ for (i in insns.indices) {
val insn = insns[i]
val frame = frames[i] ?: continue
when {
insn.isInstanceOfOrNullCheck() ->
relevantReferenceTypes[insn] = frame.top()?.type ?: continue@insnLoop
insn.isCheckParameterIsNotNull() ||
insn.isCheckExpressionValueIsNotNull() ->
relevantReferenceTypes[insn] = frame.peek(1)?.type ?: continue@insnLoop
insn.isPseudo(PseudoInsn.STORE_NOT_NULL) -> {
val previous = insn.previous ?: continue@insnLoop
if (previous.opcode != Opcodes.ASTORE) continue@insnLoop
val previousFrame = frames[i - 1] ?: continue@insnLoop
relevantReferenceTypes[insn] = previousFrame.top()?.type ?: continue@insnLoop
}
}
}
val dceResult = DeadCodeEliminationMethodTransformer().removeDeadCodeByFrames(methodNode, frames)
if (dceResult.hasRemovedAnything()) {
changes = true
}
return relevantReferenceTypes
}
private fun eliminateRedundantChecks(
checkedReferenceTypes: Map<AbstractInsnNode, Type>
) {
val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes)
val nullabilityMap = analyzeNullabilities()
nullabilityAssumptions.revert()
transformTrivialChecks(nullabilityMap)
return changes
}
private fun injectNullabilityAssumptions(
checkedReferenceTypes: Map<AbstractInsnNode, Type>
) = NullabilityAssumptionsBuilder(checkedReferenceTypes).injectNullabilityAssumptions()
private fun analyzeNullabilities(): Map<AbstractInsnNode, StrictBasicValue> {
val frames = analyze(internalClassName, methodNode, NullabilityInterpreter())
val insns = methodNode.instructions.toArray()
@@ -78,12 +120,6 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
return nullabilityMap
}
private fun AbstractInsnNode.isOptimizable() =
opcode == Opcodes.IFNULL ||
opcode == Opcodes.IFNONNULL ||
opcode == Opcodes.INSTANCEOF ||
isCheckExpressionValueIsNotNull()
private fun transformTrivialChecks(nullabilityMap: Map<AbstractInsnNode, StrictBasicValue>) {
for ((insn, value) in nullabilityMap) {
val nullability = value.getNullability()
@@ -144,7 +180,9 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
}
}
private inner class NullabilityAssumptionsBuilder {
private inner class NullabilityAssumptionsBuilder(
val relatedReferenceTypes: Map<AbstractInsnNode, Type>
) {
private val checksDependingOnVariable = HashMap<Int, MutableList<AbstractInsnNode>>()
@@ -208,7 +246,9 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
val nullabilityAssumptions = NullabilityAssumptions()
for ((varIndex, dependentChecks) in checksDependingOnVariable) {
for (checkInsn in dependentChecks) {
nullabilityAssumptions.injectAssumptionsForInsn(varIndex, checkInsn)
val varType = relatedReferenceTypes[checkInsn]
?: AsmTypes.OBJECT_TYPE
nullabilityAssumptions.injectAssumptionsForInsn(varIndex, checkInsn, varType)
}
}
for (insn in methodNode.instructions) {
@@ -219,28 +259,28 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
return nullabilityAssumptions
}
private fun NullabilityAssumptions.injectAssumptionsForInsn(varIndex: Int, insn: AbstractInsnNode) {
private fun NullabilityAssumptions.injectAssumptionsForInsn(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
when (insn.opcode) {
Opcodes.IFNULL,
Opcodes.IFNONNULL ->
injectAssumptionsForNullCheck(varIndex, insn as JumpInsnNode)
injectAssumptionsForNullCheck(varIndex, insn as JumpInsnNode, varType)
Opcodes.INVOKESTATIC -> {
when {
insn.isCheckParameterIsNotNull() ||
insn.isCheckExpressionValueIsNotNull() ->
injectAssumptionsForNotNullAssertion(varIndex, insn)
injectAssumptionsForNotNullAssertion(varIndex, insn, varType)
insn.isPseudo(PseudoInsn.STORE_NOT_NULL) ->
injectCodeForStoreNotNull(insn)
injectCodeForStoreNotNull(insn, varType)
else ->
throw AssertionError("Expected non-null assertion: ${insn.debugText}")
}
}
Opcodes.INSTANCEOF ->
injectAssumptionsForInstanceOfCheck(varIndex, insn)
injectAssumptionsForInstanceOfCheck(varIndex, insn, varType)
}
}
private fun NullabilityAssumptions.injectAssumptionsForNullCheck(varIndex: Int, insn: JumpInsnNode) {
private fun NullabilityAssumptions.injectAssumptionsForNullCheck(varIndex: Int, insn: JumpInsnNode, varType: Type) {
// ALOAD v
// IFNULL L
// <...> -- v is not null here
@@ -260,16 +300,15 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
insert(insertAfterNull, listOfSynthetics {
aconst(null)
store(varIndex, AsmTypes.OBJECT_TYPE)
store(varIndex, varType)
if (jumpsIfNull) {
goTo(originalLabel.label)
}
})
insert(insertAfterNonNull, listOfSynthetics {
load(varIndex, AsmTypes.OBJECT_TYPE)
asNotNull()
store(varIndex, AsmTypes.OBJECT_TYPE)
anew(varType)
store(varIndex, varType)
if (!jumpsIfNull) {
goTo(originalLabel.label)
}
@@ -277,7 +316,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
}
}
private fun NullabilityAssumptions.injectAssumptionsForNotNullAssertion(varIndex: Int, insn: AbstractInsnNode) {
private fun NullabilityAssumptions.injectAssumptionsForNotNullAssertion(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
// ALOAD v
// LDC *
// INVOKESTATIC checkParameterIsNotNull
@@ -290,13 +329,12 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
// <...> -- v is not null here (otherwise an exception was thrown)
methodNode.instructions.insert(insn, listOfSynthetics {
load(varIndex, AsmTypes.OBJECT_TYPE)
asNotNull()
store(varIndex, AsmTypes.OBJECT_TYPE)
anew(varType)
store(varIndex, varType)
})
}
private fun NullabilityAssumptions.injectAssumptionsForInstanceOfCheck(varIndex: Int, insn: AbstractInsnNode) {
private fun NullabilityAssumptions.injectAssumptionsForInstanceOfCheck(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
// ALOAD v
// INSTANCEOF T
// IFEQ L
@@ -326,9 +364,8 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
methodNode.instructions.run {
insert(insertAfterNotNull, listOfSynthetics {
load(varIndex, AsmTypes.OBJECT_TYPE)
asNotNull()
store(varIndex, AsmTypes.OBJECT_TYPE)
anew(varType)
store(varIndex, varType)
if (originalLabel != null) {
goTo(originalLabel.label)
}
@@ -347,7 +384,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
methodNode.maxStack = methodNode.maxStack + 1 //will be recalculated in prepareForEmitting
}
private fun NullabilityAssumptions.injectCodeForStoreNotNull(insn: AbstractInsnNode) {
private fun NullabilityAssumptions.injectCodeForStoreNotNull(insn: AbstractInsnNode, varType: Type) {
// ASTORE v
// [STORE_NOT_NULL]
// <...> -- v is not null here because codegen told us so
@@ -356,10 +393,8 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
methodNode.instructions.run {
insert(insn, listOfSynthetics {
val varIndex = (previous as VarInsnNode).`var`
load(varIndex, AsmTypes.OBJECT_TYPE)
asNotNull()
store(varIndex, AsmTypes.OBJECT_TYPE)
anew(varType)
store((previous as VarInsnNode).`var`, varType)
})
}
}
@@ -419,6 +454,13 @@ internal fun AbstractInsnNode.isThrowIntrinsic() =
name in THROW_INTRINSIC_METHOD_NAMES
}
internal fun AbstractInsnNode.isThrowIntrinsicWithoutArguments() =
isInsn<MethodInsnNode>(Opcodes.INVOKESTATIC) {
owner == IntrinsicMethods.INTRINSICS_CLASS_NAME &&
name in THROW_INTRINSIC_METHOD_NAMES &&
desc == "()V"
}
internal val THROW_INTRINSIC_METHOD_NAMES =
setOf(
"throwNpe",

View File

@@ -31,8 +31,7 @@ enum class PseudoInsn(val signature: String = "()V") {
FAKE_ALWAYS_FALSE_IFEQ("()I"),
SAVE_STACK_BEFORE_TRY,
RESTORE_STACK_IN_TRY_CATCH,
STORE_NOT_NULL,
AS_NOT_NULL("(Ljava/lang/Object;)Ljava/lang/Object;")
STORE_NOT_NULL
;
fun emit(iv: InstructionAdapter) {
@@ -73,9 +72,5 @@ fun InstructionAdapter.storeNotNull() {
PseudoInsn.STORE_NOT_NULL.emit(this)
}
fun InstructionAdapter.asNotNull() {
PseudoInsn.AS_NOT_NULL.emit(this)
}
fun AbstractInsnNode.isPseudo(pseudoInsn: PseudoInsn) =
pseudoInsn.isa(this)

View File

@@ -17,7 +17,8 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.shouldWritePreReleaseFlag
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
@@ -36,7 +37,7 @@ fun writeKotlinMetadata(
av.visit(JvmAnnotationNames.BYTECODE_VERSION_FIELD_NAME, JvmBytecodeBinaryVersion.INSTANCE.toArray())
av.visit(JvmAnnotationNames.KIND_FIELD_NAME, kind.id)
var flags = extraFlags
if (state.languageVersionSettings.shouldWritePreReleaseFlag()) {
if (KotlinCompilerVersion.isPreRelease() && state.languageVersionSettings.languageVersion == LanguageVersion.LATEST_STABLE) {
flags = flags or JvmAnnotationNames.METADATA_PRE_RELEASE_FLAG
}
if (flags != 0) {
@@ -50,4 +51,4 @@ fun writeSyntheticClassMetadata(cb: ClassBuilder, state: GenerationState) {
writeKotlinMetadata(cb, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0) { _ ->
// Do nothing
}
}
}

View File

@@ -74,8 +74,7 @@ class BuiltInsSerializer(dependOnOldBuiltIns: Boolean) : MetadataSerializer(depe
}
private fun createMessageCollector() = object : GroupingMessageCollector(
PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, false),
false
PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, /* verbose = */ false)
) {
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
// Only report diagnostics without a particular location because there's plenty of errors in built-in sources

View File

@@ -110,7 +110,6 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
return HashMap<AnalysisFlag<*>, Any>().apply {
put(AnalysisFlag.skipMetadataVersionCheck, skipMetadataVersionCheck)
put(AnalysisFlag.multiPlatformDoNotCheckActual, noCheckActual)
put(AnalysisFlag.allowKotlinPackage, allowKotlinPackage)
}
}

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.cli.common.arguments
import org.jetbrains.kotlin.utils.SmartList
import java.io.Serializable
abstract class CommonToolArguments : Freezable(), Serializable {
@@ -23,7 +24,7 @@ abstract class CommonToolArguments : Freezable(), Serializable {
@JvmStatic private val serialVersionUID = 0L
}
var freeArgs: List<String> by FreezableVar(emptyList())
var freeArgs: MutableList<String> = SmartList()
@Transient var errors: ArgumentParseErrors = ArgumentParseErrors()
@@ -43,8 +44,4 @@ abstract class CommonToolArguments : Freezable(), Serializable {
@GradleOption(DefaultValues.BooleanFalseDefault::class)
@Argument(value = "-nowarn", description = "Generate no warnings")
var suppressWarnings: Boolean by FreezableVar(false)
@GradleOption(DefaultValues.BooleanFalseDefault::class)
@Argument(value = "-Werror", description = "Report an error if there are any warnings")
var allWarningsAsErrors: Boolean by FreezableVar(false)
}

View File

@@ -106,16 +106,16 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xno-param-assertions", description = "Don't generate not-null assertions on parameters of methods accessible from Java")
var noParamAssertions: Boolean by FreezableVar(false)
@Argument(value = "-Xstrict-java-nullability-assertions", description = "Generate nullability assertions for non-null Java expressions")
var strictJavaNullabilityAssertions: Boolean by FreezableVar(false)
@Argument(value = "-Xno-optimize", description = "Disable optimizations")
var noOptimize: Boolean by FreezableVar(false)
@Argument(
value = "-Xnormalize-constructor-calls",
valueDescription = "{disable|enable}",
description = "Normalize constructor calls (disable: don't normalize; enable: normalize), default is disable"
valueDescription = "{disable|enable|preserve-class-initialization}",
description = "Normalize constructor calls " +
"(disable: don't normalize; enable: normalize; " +
"preserve-class-initialization: normalize preserving class initialization order), " +
"default is disable"
)
var constructorCallNormalizationMode: String? by FreezableVar(JVMConstructorCallNormalizationMode.DEFAULT.description)

View File

@@ -16,7 +16,7 @@
package org.jetbrains.kotlin.cli.common.arguments
import org.jetbrains.kotlin.utils.SmartList
import com.intellij.util.SmartList
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.full.findAnnotation
@@ -100,14 +100,12 @@ fun <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, resu
return argument.value == arg
}
val freeArgs = ArrayList<String>()
var i = 0
loop@ while (i < args.size) {
val arg = args[i++]
if (freeArgsStarted) {
freeArgs.add(arg)
result.freeArgs.add(arg)
continue
}
if (arg == FREE_ARGS_DELIMITER) {
@@ -120,7 +118,7 @@ fun <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, resu
when {
arg.startsWith(ADVANCED_ARGUMENT_PREFIX) -> errors.unknownExtraFlags.add(arg)
arg.startsWith("-") -> errors.unknownArgs.add(arg)
else -> freeArgs.add(arg)
else -> result.freeArgs.add(arg)
}
continue
}
@@ -150,8 +148,6 @@ fun <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, resu
updateField(property, result, value, argument.delimiter)
}
result.freeArgs += freeArgs
}
private fun <A : CommonToolArguments> updateField(property: KMutableProperty1<A, Any?>, result: A, value: Any, delimiter: String) {

View File

@@ -35,14 +35,11 @@ public enum CompilerMessageSeverity {
*/
OUTPUT;
public static final EnumSet<CompilerMessageSeverity> ERRORS = EnumSet.of(ERROR, EXCEPTION);
public static final EnumSet<CompilerMessageSeverity> VERBOSE = EnumSet.of(LOGGING);
public boolean isError() {
return this == EXCEPTION || this == ERROR;
}
public boolean isWarning() {
return this == STRONG_WARNING || this == WARNING;
return ERRORS.contains(this);
}
@NotNull

View File

@@ -24,19 +24,16 @@ import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public class GroupingMessageCollector implements MessageCollector {
private final MessageCollector delegate;
private final boolean treatWarningsAsErrors;
// Note that the key in this map can be null
private final Multimap<CompilerMessageLocation, Message> groupedMessages = LinkedHashMultimap.create();
public GroupingMessageCollector(@NotNull MessageCollector delegate, boolean treatWarningsAsErrors) {
public GroupingMessageCollector(@NotNull MessageCollector delegate) {
this.delegate = delegate;
this.treatWarningsAsErrors = treatWarningsAsErrors;
}
@Override
@@ -60,29 +57,17 @@ public class GroupingMessageCollector implements MessageCollector {
@Override
public boolean hasErrors() {
return hasExplicitErrors() || (treatWarningsAsErrors && hasWarnings());
}
private boolean hasExplicitErrors() {
return groupedMessages.entries().stream().anyMatch(entry -> entry.getValue().severity.isError());
}
private boolean hasWarnings() {
return groupedMessages.entries().stream().anyMatch(entry -> entry.getValue().severity.isWarning());
}
public void flush() {
boolean hasExplicitErrors = hasExplicitErrors();
if (treatWarningsAsErrors && !hasExplicitErrors && hasWarnings()) {
report(CompilerMessageSeverity.ERROR, "warnings found and -Werror specified", null);
}
boolean hasErrors = hasErrors();
List<CompilerMessageLocation> sortedKeys =
CollectionsKt.sortedWith(groupedMessages.keySet(), Comparator.nullsFirst(CompilerMessageLocationComparator.INSTANCE));
for (CompilerMessageLocation location : sortedKeys) {
for (Message message : groupedMessages.get(location)) {
if (!hasExplicitErrors || message.severity.isError() || message.severity == CompilerMessageSeverity.STRONG_WARNING) {
if (!hasErrors || message.severity.isError() || message.severity == CompilerMessageSeverity.STRONG_WARNING) {
delegate.report(message.severity, message.message, message.location);
}
}

View File

@@ -69,7 +69,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
@NotNull
@Override
public ExitCode execImpl(@NotNull MessageCollector messageCollector, @NotNull Services services, @NotNull A arguments) {
GroupingMessageCollector groupingCollector = new GroupingMessageCollector(messageCollector, arguments.getAllWarningsAsErrors());
GroupingMessageCollector groupingCollector = new GroupingMessageCollector(messageCollector);
CompilerConfiguration configuration = new CompilerConfiguration();
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, groupingCollector);
@@ -204,8 +204,6 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
extraLanguageFeatures.put(LanguageFeature.Coroutines, coroutinesState);
}
setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, arguments);
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, new LanguageVersionSettingsImpl(
languageVersion,
ApiVersion.createByLanguageVersion(apiVersion),
@@ -214,13 +212,6 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
));
}
protected void setupPlatformSpecificLanguageFeatureSettings(
@NotNull Map<LanguageFeature, LanguageFeature.State> extraLanguageFeatures,
@NotNull A commandLineArguments
) {
// do nothing
}
@Nullable
private static KotlinPaths computeKotlinPaths(@NotNull MessageCollector messageCollector, @NotNull CommonCompilerArguments arguments) {
KotlinPaths paths;

View File

@@ -81,7 +81,7 @@ abstract class CLITool<A : CommonToolArguments> {
fun exec(messageCollector: MessageCollector, services: Services, arguments: A): ExitCode {
printVersionIfNeeded(messageCollector, arguments)
val fixedMessageCollector = if (arguments.suppressWarnings && !arguments.allWarningsAsErrors) {
val fixedMessageCollector = if (arguments.suppressWarnings) {
FilteringMessageCollector(messageCollector, Predicate.isEqual(CompilerMessageSeverity.WARNING))
}
else {

View File

@@ -180,7 +180,7 @@ object JvmRuntimeVersionsConsistencyChecker {
// The "Core" jar files should not be newer than the compiler. This behavior is reserved for the future if we realise that we're
// going to break language/library compatibility in such a way that it's easier to make the old compiler just report an error
// in the case the new runtime library is specified in the classpath, rather than employing any other compatibility breakage tools
// we have at our disposal (Deprecated, SinceKotlin, VersionRequirement in metadata, etc.)
// we have at our disposal (Deprecated, SinceKotlin, SinceKotlinInfo in metadata, etc.)
if (runtimeJarsInfo.coreJars.map {
checkNotNewerThanCompiler(messageCollector, it)
}.any { it }) return ClasspathConsistency.InconsistentWithCompilerVersion

View File

@@ -228,17 +228,6 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
}
override fun setupPlatformSpecificLanguageFeatureSettings(
extraLanguageFeatures: MutableMap<LanguageFeature, LanguageFeature.State>,
commandLineArguments: K2JVMCompilerArguments
) {
if (commandLineArguments.strictJavaNullabilityAssertions) {
extraLanguageFeatures[LanguageFeature.StrictJavaNullabilityAssertions] = LanguageFeature.State.ENABLED
}
super.setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, commandLineArguments)
}
private fun registerJavacIfNeeded(environment: KotlinCoreEnvironment,
arguments: K2JVMCompilerArguments): Boolean {
if (arguments.useJavac) {
@@ -385,6 +374,8 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
configuration.put(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES, arguments.addCompilerBuiltIns)
configuration.put(JVMConfigurationKeys.CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES, arguments.loadBuiltInsFromDependencies)
arguments.declarationsOutputPath?.let { configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) }
}

View File

@@ -19,10 +19,9 @@ package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
//import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiManager
//import com.intellij.psi.impl.light.LightJavaModule
import com.intellij.psi.impl.light.LightJavaModule
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
@@ -92,22 +91,22 @@ class ClasspathRootsResolver(
for ((root, packagePrefix) in javaSourceRoots) {
val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath)
if (modularRoot != null) {
modules += modularRoot
}
else {
if (modularRoot != null) {
modules += modularRoot
}
else {
result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix ->
if (isValidJavaFqName(prefix)) FqName(prefix)
else null.also {
report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix")
}
})
if (isValidJavaFqName(prefix)) FqName(prefix)
else null.also {
report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix")
}
}
})
}
}
for (root in jvmClasspathRoots) {
result += JavaRoot(root, JavaRoot.RootType.BINARY)
}
result += JavaRoot(root, JavaRoot.RootType.BINARY)
}
val outputDirectoryAddedAsPartOfModule = modules.any { module -> module.moduleRoots.any { it.file == outputDirectory } }
@@ -117,19 +116,17 @@ class ClasspathRootsResolver(
if (outputDirectoryAddedAsPartOfModule && root == outputDirectory) continue
val module = modularBinaryRoot(root)
if (module != null) {
modules += module
}
}
if (module != null) {
modules += module
}
}
addModularRoots(modules, result)
return RootsAndModules(result, modules)
}
private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, *>? {
return null
/*
private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, PsiJavaModule>? {
val moduleInfoFile =
when {
root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE)
@@ -141,12 +138,9 @@ class ClasspathRootsResolver(
val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null
return moduleInfoFile to psiJavaModule
*/
}
private fun modularSourceRoot(root: VirtualFile, hasOutputDirectoryInClasspath: Boolean): JavaModule.Explicit? {
return null
/*
val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null
val sourceRoot = JavaModule.Root(root, isBinary = false)
val roots =
@@ -154,14 +148,19 @@ class ClasspathRootsResolver(
listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true))
else listOf(sourceRoot)
return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile)
*/
}
private fun modularBinaryRoot(root: VirtualFile): JavaModule? {
return null
/*
val moduleInfoFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
return if (moduleInfoFile != null) {
val isJar = root.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL
val manifest: Attributes? by lazy(NONE) { readManifestAttributes(root) }
val moduleInfoFile =
root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf {
manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true
}
if (moduleInfoFile != null) {
val moduleInfo = JavaModuleInfo.read(moduleInfoFile) ?: return null
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(root, isBinary = true)), moduleInfoFile)
}
@@ -183,6 +182,8 @@ class ClasspathRootsResolver(
}
return JavaModule.Automatic(moduleName, moduleRoot)
}
return null
}
private fun readManifestAttributes(jarRoot: VirtualFile): Attributes? {
@@ -193,7 +194,6 @@ class ClasspathRootsResolver(
catch (e: IOException) {
null
}
*/
}
private fun addModularRoots(modules: List<JavaModule>, result: MutableList<JavaRoot>) {
@@ -261,9 +261,9 @@ class ClasspathRootsResolver(
else {
for ((root, isBinary) in module.moduleRoots) {
result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE))
}
}
}
}
if (requireStdlibModule && sourceModule != null && KOTLIN_STDLIB_MODULE_NAME !in allDependencies) {
report(
@@ -320,6 +320,7 @@ class ClasspathRootsResolver(
}
private companion object {
const val MULTI_RELEASE_MODULE_INFO_CLS_FILE = "META-INF/versions/9/${PsiJavaModule.MODULE_INFO_CLS_FILE}"
const val AUTOMATIC_MODULE_NAME = "Automatic-Module-Name"
const val IS_MULTI_RELEASE = "Multi-Release"
}

View File

@@ -26,6 +26,7 @@ import com.intellij.core.JavaCoreApplicationEnvironment
import com.intellij.core.JavaCoreProjectEnvironment
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.lang.MetaLanguage
import com.intellij.lang.java.JavaParserDefinition
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
@@ -120,6 +121,28 @@ class KotlinCoreEnvironment private constructor(
override fun preregisterServices() {
registerProjectExtensionPoints(Extensions.getArea(project))
}
override fun registerJavaPsiFacade() {
with (project) {
registerService(CoreJavaFileManager::class.java, ServiceManager.getService(this, JavaFileManager::class.java) as CoreJavaFileManager)
val cliLightClassGenerationSupport = CliLightClassGenerationSupport(this)
registerService(LightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(CliLightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(CodeAnalyzerInitializer::class.java, cliLightClassGenerationSupport)
registerService(ExternalAnnotationsManager::class.java, MockExternalAnnotationsManager())
registerService(InferredAnnotationsManager::class.java, MockInferredAnnotationsManager())
val area = Extensions.getArea(this)
area.getExtensionPoint(PsiElementFinder.EP_NAME).registerExtension(JavaElementFinder(this, cliLightClassGenerationSupport))
area.getExtensionPoint(PsiElementFinder.EP_NAME).registerExtension(
PsiElementFinderImpl(this, ServiceManager.getService(this, JavaFileManager::class.java)))
}
super.registerJavaPsiFacade()
}
}
private val sourceFiles = mutableListOf<KtFile>()
@@ -201,12 +224,12 @@ class KotlinCoreEnvironment private constructor(
this.initialRoots = initialRoots
if (!configuration.getBoolean(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK) && messageCollector != null) {
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(
messageCollector,
configuration,
initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null }
)
}
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(
messageCollector,
configuration,
initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null }
)
}
val (roots, singleJavaFileRoots) =
initialRoots.partition { (file) -> file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION }
@@ -295,7 +318,7 @@ class KotlinCoreEnvironment private constructor(
for (packagePartProvider in packagePartProviders) {
packagePartProvider.addRoots(newRoots)
}
}
return rootsIndex.addNewIndexForRoots(newRoots)?.let { newIndex ->
updateClasspathFromRootsIndex(newIndex)
@@ -321,9 +344,9 @@ class KotlinCoreEnvironment private constructor(
return findLocalFile(root.file.absolutePath).also {
if (it == null) {
report(STRONG_WARNING, "Classpath entry points to a non-existent location: ${root.file}")
}
}
}
}
private fun findJarRoot(file: File): VirtualFile? =
applicationEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
@@ -437,7 +460,6 @@ class KotlinCoreEnvironment private constructor(
Extensions.cleanRootArea(parentDisposable)
registerAppExtensionPoints()
val applicationEnvironment = object : JavaCoreApplicationEnvironment(parentDisposable) {
@Suppress("NOTHING_TO_OVERRIDE")
override fun createJrtFileSystem(): VirtualFileSystem? = CoreJrtFileSystem()
}
@@ -464,6 +486,7 @@ class KotlinCoreEnvironment private constructor(
CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler::class.java)
//
CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier::class.java)
CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), MetaLanguage.EP_NAME, MetaLanguage::class.java)
}
private fun registerApplicationExtensionPointsAndExtensionsFrom(configuration: CompilerConfiguration, configFilePath: String) {
@@ -531,23 +554,11 @@ class KotlinCoreEnvironment private constructor(
}
private fun registerProjectServicesForCLI(@Suppress("UNUSED_PARAMETER") projectEnvironment: JavaCoreProjectEnvironment) {
with (projectEnvironment.project) {
registerService(CoreJavaFileManager::class.java, ServiceManager.getService(this, JavaFileManager::class.java) as CoreJavaFileManager)
/**
* Note that Kapt may restart code analysis process, and CLI services should be aware of that.
* Use PsiManager.getModificationTracker() to ensure that all the data you cached is still valid.
*/
val cliLightClassGenerationSupport = CliLightClassGenerationSupport(this)
registerService(LightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(CliLightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(CodeAnalyzerInitializer::class.java, cliLightClassGenerationSupport)
registerService(ExternalAnnotationsManager::class.java, MockExternalAnnotationsManager())
registerService(InferredAnnotationsManager::class.java, MockInferredAnnotationsManager())
val area = Extensions.getArea(this)
area.getExtensionPoint(PsiElementFinder.EP_NAME).registerExtension(JavaElementFinder(this, cliLightClassGenerationSupport))
area.getExtensionPoint(PsiElementFinder.EP_NAME).registerExtension(
PsiElementFinderImpl(this, ServiceManager.getService(this, JavaFileManager::class.java)))
}
}
private fun CompilerConfiguration.setupJdkClasspathRoots(configFiles: EnvironmentConfigFiles) {

View File

@@ -26,11 +26,5 @@ open class KotlinCoreProjectEnvironment(
disposable: Disposable,
applicationEnvironment: JavaCoreApplicationEnvironment
) : JavaCoreProjectEnvironment(disposable, applicationEnvironment) {
init {
myProject.registerService<ControlFlowFactory>(ControlFlowFactory::class.java,
ControlFlowFactory(myPsiManager))
}
override fun createCoreFileManager() = KotlinCliJavaFileManagerImpl(PsiManager.getInstance(project))
}

View File

@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
//import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.PsiModificationTrackerImpl
import com.intellij.psi.search.DelegatingGlobalSearchScope
@@ -191,15 +191,14 @@ object KotlinToJVMBytecodeCompiler {
}
}
val isJava9Module = false
/*chunk.any { module ->
val isJava9Module = chunk.any { module ->
module.getJavaSourceRoots().any { (path, packagePrefix) ->
val file = File(path)
packagePrefix == null &&
(file.name == PsiJavaModule.MODULE_INFO_FILE ||
(file.isDirectory && file.listFiles().any { it.name == PsiJavaModule.MODULE_INFO_FILE }))
}
}*/
}
for (module in chunk) {
for (classpathRoot in module.getClasspathRoots()) {

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.codeInsight.ExternalAnnotationsManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.*
class MockExternalAnnotationsManager : ExternalAnnotationsManager() {
@@ -40,4 +41,8 @@ class MockExternalAnnotationsManager : ExternalAnnotationsManager() {
override fun editExternalAnnotation(listOwner: PsiModifierListOwner, annotationFQN: String, value: Array<out PsiNameValuePair>?): Boolean {
throw UnsupportedOperationException("not implemented")
}
override fun hasAnnotationRootsForFile(file: VirtualFile): Boolean {
throw UnsupportedOperationException("not implemented")
}
}

View File

@@ -17,8 +17,7 @@
package org.jetbrains.kotlin.cli.jvm.modules
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileSystem
//import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiJavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleFinder
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
@@ -41,11 +40,8 @@ class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name]
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
return null
/*
val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null
val moduleInfo = JavaModuleInfo.read(file) ?: return null
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(moduleRoot, isBinary = true)), file)
*/
}
}

View File

@@ -153,8 +153,8 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
return delegateFactory.getPackageMemberDeclarationProvider(packageFqName)
}
override fun diagnoseMissingPackageFragment(file: KtFile) {
delegateFactory.diagnoseMissingPackageFragment(file)
override fun diagnoseMissingPackageFragment(fqName: FqName, file: KtFile?) {
delegateFactory.diagnoseMissingPackageFragment(fqName, file)
}
class AdaptablePackageMemberDeclarationProvider(

View File

@@ -28,8 +28,7 @@ class ReplTerminalDiagnosticMessageHolder : MessageCollectorBasedReporter, Diagn
private val outputStream = ByteArrayOutputStream()
override val messageCollector: GroupingMessageCollector = GroupingMessageCollector(
PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.WITHOUT_PATHS, false),
false
PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.WITHOUT_PATHS, false)
)
override val renderedDiagnostics: String

View File

@@ -69,7 +69,6 @@ messages/**)
#-libraryjars '<bootstrap.script.runtime>'
#-libraryjars '<tools.jar>'
-target 1.6
-dontoptimize
-dontobfuscate

View File

@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.*
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackagePartProvider
import org.jetbrains.kotlin.frontend.di.configureModule
@@ -110,8 +109,6 @@ fun createContainerForLazyResolveWithJava(
}
targetEnvironment.configure(this)
useImpl<ContractDeserializerImpl>()
}.apply {
get<AbstractJavaClassFinder>().initialize(bindingTrace, get<KotlinCodeAnalyzer>())
}

View File

@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.psiUtil.contains
class JavaClassImpl(psiClass: PsiClass) : JavaClassifierImpl<PsiClass>(psiClass), VirtualFileBoundJavaClass, JavaAnnotationOwnerImpl, JavaModifierListOwnerImpl {
init {
@@ -115,7 +114,7 @@ class JavaClassImpl(psiClass: PsiClass) : JavaClassifierImpl<PsiClass>(psiClass)
override val virtualFile: VirtualFile?
get() = psi.containingFile?.virtualFile
override fun isFromSourceCodeInScope(scope: SearchScope): Boolean = psi.containingFile in scope
override fun isFromSourceCodeInScope(scope: SearchScope): Boolean = psi.containingFile.virtualFile in scope
override fun getAnnotationOwnerPsi() = psi.modifierList

View File

@@ -22,6 +22,7 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.util.Computable
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule
class KotlinBinaryClassCache : Disposable {
private class RequestCache {
@@ -55,6 +56,8 @@ class KotlinBinaryClassCache : Disposable {
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
if (file.fileType !== JavaClassFileType.INSTANCE) return null
if (file.name == PsiJavaModule.MODULE_INFO_CLS_FILE) return null
val service = ServiceManager.getService(KotlinBinaryClassCache::class.java)
val requestCache = service.cache.get()

View File

@@ -32,9 +32,6 @@ object JvmBindingContextSlices {
@JvmField
val RECEIVER_RUNTIME_ASSERTION_INFO: WritableSlice<ExpressionReceiver, RuntimeAssertionInfo> = BasicWritableSlice(RewritePolicy.DO_NOTHING)
@JvmField
val BODY_RUNTIME_ASSERTION_INFO: WritableSlice<KtExpression, RuntimeAssertionInfo> = BasicWritableSlice(RewritePolicy.DO_NOTHING)
@JvmField
val LOAD_FROM_JAVA_SIGNATURE_ERRORS: WritableSlice<DeclarationDescriptor, List<String>> = Slices.createCollectiveSlice()

View File

@@ -1,43 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.jvm
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DeclarationReturnTypeSanitizer
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.WrappedTypeFactory
object JvmDeclarationReturnTypeSanitizer : DeclarationReturnTypeSanitizer {
override fun sanitizeReturnType(
inferred: UnwrappedType,
wrappedTypeFactory: WrappedTypeFactory,
trace: BindingTrace,
languageVersionSettings: LanguageVersionSettings
): UnwrappedType =
if (languageVersionSettings.supportsFeature(LanguageFeature.StrictJavaNullabilityAssertions)) {
// NB can't check for presence of EnhancedNullability here,
// because it will also cause recursion in declaration type resolution.
inferred.replaceAnnotations(FilteredAnnotations(inferred.annotations) {
it != JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION
})
}
else inferred
}

View File

@@ -18,12 +18,9 @@ package org.jetbrains.kotlin.resolve.jvm
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
@@ -34,9 +31,9 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.isClassType
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class RuntimeAssertionInfo(val needNotNullAssertion: Boolean, val message: String) {
@@ -86,9 +83,6 @@ class RuntimeAssertionInfo(val needNotNullAssertion: Boolean, val message: Strin
}
}
private val KtExpression.textForRuntimeAssertionInfo
get() = StringUtil.trimMiddle(text, 50)
class RuntimeAssertionsDataFlowExtras(
private val c: ResolutionContext<*>,
private val dataFlowValue: DataFlowValue,
@@ -99,7 +93,7 @@ class RuntimeAssertionsDataFlowExtras(
override val possibleTypes: Set<KotlinType>
get() = c.dataFlowInfo.getCollectedTypes(dataFlowValue)
override val presentableText: String
get() = expression.textForRuntimeAssertionInfo
get() = StringUtil.trimMiddle(expression.text, 50)
}
object RuntimeAssertionsTypeChecker : AdditionalTypeChecker {
@@ -144,101 +138,4 @@ object RuntimeAssertionsOnExtensionReceiverCallChecker : CallChecker {
c.trace.record(JvmBindingContextSlices.RECEIVER_RUNTIME_ASSERTION_INFO, expressionReceiverValue, assertionInfo)
}
}
}
object RuntimeAssertionsOnDeclarationBodyChecker {
@JvmStatic
fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
bindingTrace: BindingTrace,
languageVersionSettings: LanguageVersionSettings
) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.StrictJavaNullabilityAssertions)) return
when {
declaration is KtProperty && descriptor is VariableDescriptor ->
checkLocalVariable(declaration, descriptor, bindingTrace)
declaration is KtFunction && descriptor is FunctionDescriptor ->
checkFunction(declaration, descriptor, bindingTrace)
declaration is KtProperty && descriptor is PropertyDescriptor ->
checkProperty(declaration, descriptor, bindingTrace)
declaration is KtPropertyAccessor && descriptor is PropertyAccessorDescriptor ->
checkPropertyAccessor(declaration, descriptor, bindingTrace)
}
}
private fun checkLocalVariable(
declaration: KtProperty,
descriptor: VariableDescriptor,
bindingTrace: BindingTrace
) {
if (declaration.typeReference != null) return
checkNullabilityAssertion(declaration.initializer ?: return, descriptor.type, bindingTrace)
}
private fun checkFunction(
declaration: KtFunction,
descriptor: FunctionDescriptor,
bindingTrace: BindingTrace
) {
if (declaration.typeReference != null || declaration.hasBlockBody()) return
checkNullabilityAssertion(declaration.bodyExpression ?: return, descriptor.returnType ?: return,
bindingTrace)
}
private fun checkProperty(
declaration: KtProperty,
descriptor: PropertyDescriptor,
bindingTrace: BindingTrace
) {
if (declaration.typeReference != null) return
// TODO nullability assertion on delegate initialization expression, see KT-20823
if (declaration.hasDelegateExpression()) return
checkNullabilityAssertion(declaration.initializer ?: return, descriptor.type, bindingTrace)
}
private fun checkPropertyAccessor(
declaration: KtPropertyAccessor,
descriptor: PropertyAccessorDescriptor,
bindingTrace: BindingTrace
) {
if (declaration.property.typeReference != null || declaration.hasBlockBody()) return
checkNullabilityAssertion(declaration.bodyExpression ?: return, descriptor.correspondingProperty.type,
bindingTrace)
}
private fun checkNullabilityAssertion(
expression: KtExpression,
declarationType: KotlinType,
bindingTrace: BindingTrace
) {
if (declarationType.unwrap().canContainNull()) return
val expressionType = bindingTrace.getType(expression) ?: return
if (expressionType.isError) return
if (!expressionType.hasEnhancedNullability()) return
bindingTrace.record(
JvmBindingContextSlices.BODY_RUNTIME_ASSERTION_INFO,
expression,
RuntimeAssertionInfo(true, expression.textForRuntimeAssertionInfo)
)
}
private fun UnwrappedType.canContainNull(): Boolean {
val upper = upperIfFlexible()
return when {
upper.isMarkedNullable -> true
upper.isClassType -> false
else -> upper.immediateSupertypes().all { it.unwrap().canContainNull() }
}
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.resolve.jvm.getCompileTimeConstant
object ApiVersionIsAtLeastArgumentsChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (!isApiVersionIsAtLeast(resolvedCall.resultingDescriptor)) return
val bindingContext = context.trace.bindingContext
val shouldInlineConstVals = context.languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals)
for ((_, resolvedValueArgument) in resolvedCall.valueArguments) {
for (valueArgument in resolvedValueArgument.arguments) {
val ktExpression = KtPsiUtil.deparenthesize(valueArgument.getArgumentExpression() ?: continue) ?: continue
val constant = getCompileTimeConstant(ktExpression, bindingContext, false, shouldInlineConstVals)
if (constant == null) {
context.trace.report(ErrorsJvm.API_VERSION_IS_AT_LEAST_ARGUMENT_SHOULD_BE_CONSTANT.on(ktExpression))
}
}
}
}
private fun isApiVersionIsAtLeast(descriptor: CallableDescriptor): Boolean {
val functionDescriptor = descriptor as? FunctionDescriptor ?: return false
if (functionDescriptor.name.asString() != "apiVersionIsAtLeast") return false
val returnType = functionDescriptor.returnType ?: return false
if (!KotlinBuiltIns.isBoolean(returnType)) return false
if (!functionDescriptor.valueParameters.all { KotlinBuiltIns.isInt(it.type) }) return false
val containingPackage = functionDescriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
return containingPackage.fqName.asString() == "kotlin.internal"
}
}

View File

@@ -115,7 +115,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
"Please make explicit overrides (abstract or concrete) for the following non-abstract members of ''{1}'': {2}",
NAME, NAME, STRING);
MAP.put(DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET, "Super calls to Java default methods are prohibited in JVM target 1.6. Recompile with '-jvm-target 1.8'");
MAP.put(DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET, "Super calls to Java default methods are deprecated in JVM target 1.6. Recompile with '-jvm-target 1.8'");
MAP.put(INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET, "Calls to static methods in Java interfaces are deprecated in JVM target 1.6. Recompile with '-jvm-target 1.8'");
MAP.put(INLINE_FROM_HIGHER_PLATFORM, "Cannot inline bytecode built with {0} into bytecode that is being built with {1}. Please specify proper ''-jvm-target'' option", STRING, STRING);
@@ -123,8 +123,6 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
MAP.put(JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE, "Symbol is declared in module ''{0}'' which current module does not depend on", STRING);
MAP.put(JAVA_MODULE_DOES_NOT_READ_UNNAMED_MODULE, "Symbol is declared in unnamed module which is not read by current module");
MAP.put(JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE, "Symbol is declared in module ''{0}'' which does not export package ''{1}''", STRING, STRING);
MAP.put(API_VERSION_IS_AT_LEAST_ARGUMENT_SHOULD_BE_CONSTANT, "'apiVersionIsAtLeast' argument should be a constant expression");
}
@NotNull

View File

@@ -96,7 +96,7 @@ public interface ErrorsJvm {
DiagnosticFactory3<PsiElement, DeclarationDescriptor, DeclarationDescriptor, String> TARGET6_INTERFACE_INHERITANCE = DiagnosticFactory3.create(ERROR);
DiagnosticFactory0<PsiElement> DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET = DiagnosticFactory0.create(WARNING);
DiagnosticFactory2<PsiElement, String, String> INLINE_FROM_HIGHER_PLATFORM = DiagnosticFactory2.create(ERROR);
@@ -105,8 +105,6 @@ public interface ErrorsJvm {
DiagnosticFactory0<PsiElement> JAVA_MODULE_DOES_NOT_READ_UNNAMED_MODULE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory2<PsiElement, String, String> JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE = DiagnosticFactory2.create(ERROR);
DiagnosticFactory0<KtExpression> API_VERSION_IS_AT_LEAST_ARGUMENT_SHOULD_BE_CONSTANT = DiagnosticFactory0.create(WARNING);
enum NullabilityInformationSource {
KOTLIN {
@NotNull

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.jvm
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
fun getCompileTimeConstant(
expression: KtExpression,
bindingContext: BindingContext,
takeUpConstValsAsConst: Boolean,
shouldInlineConstVals: Boolean
): ConstantValue<*>? {
val compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, bindingContext)
if (compileTimeValue == null || compileTimeValue.usesNonConstValAsConstant) {
return null
}
if (!shouldInlineConstVals && !takeUpConstValsAsConst && compileTimeValue.usesVariableAsConstant) {
val constantChecker = ConstantsChecker(bindingContext)
expression.accept(constantChecker)
if (constantChecker.containsKotlinConstVals) return null
}
val expectedType = bindingContext.getType(expression) ?: return null
return compileTimeValue.toConstantValue(expectedType)
}
private class ConstantsChecker(private val bindingContext: BindingContext) : KtVisitorVoid() {
var containsKotlinConstVals = false
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
val resolvedCall = expression.getResolvedCall(bindingContext)
if (resolvedCall != null) {
val callableDescriptor = resolvedCall.resultingDescriptor
if (callableDescriptor is PropertyDescriptor && callableDescriptor !is JavaPropertyDescriptor && callableDescriptor.isConst) {
containsKotlinConstVals = true
}
}
}
override fun visitKtElement(element: KtElement) {
if (!containsKotlinConstVals) {
element.acceptChildren(this)
}
}
}

View File

@@ -17,16 +17,15 @@
package org.jetbrains.kotlin.resolve.jvm.modules
import com.intellij.openapi.vfs.VirtualFile
//import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiModifier
import org.jetbrains.kotlin.name.FqName
/*
import org.jetbrains.kotlin.utils.compact
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.ModuleVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Opcodes.*
*/
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_TRANSITIVE
import java.io.IOException
class JavaModuleInfo(
@@ -42,7 +41,6 @@ class JavaModuleInfo(
"Module $moduleName (${requires.size} requires, ${exports.size} exports)"
companion object {
/*
fun create(psiJavaModule: PsiJavaModule): JavaModuleInfo {
return JavaModuleInfo(
psiJavaModule.name,
@@ -58,10 +56,7 @@ class JavaModuleInfo(
}
)
}
*/
fun read(file: VirtualFile): JavaModuleInfo? = null // unsupported with this version of ASM
/*
fun read(file: VirtualFile): JavaModuleInfo? {
val contents = try { file.contentsToByteArray() } catch (e: IOException) { return null }
@@ -90,6 +85,5 @@ class JavaModuleInfo(
JavaModuleInfo(moduleName!!, requires.compact(), exports.compact())
else null
}
*/
}
}

View File

@@ -54,8 +54,7 @@ object JvmPlatformConfigurator : PlatformConfigurator(
SuperCallWithDefaultArgumentsChecker(),
ProtectedSyntheticExtensionCallChecker,
ReifiedTypeParameterSubstitutionChecker(),
RuntimeAssertionsOnExtensionReceiverCallChecker,
ApiVersionIsAtLeastArgumentsChecker
RuntimeAssertionsOnExtensionReceiverCallChecker
),
additionalTypeCheckers = listOf(
@@ -81,9 +80,7 @@ object JvmPlatformConfigurator : PlatformConfigurator(
delegationFilter = JvmDelegationFilter,
overridesBackwardCompatibilityHelper = JvmOverridesBackwardCompatibilityHelper,
declarationReturnTypeSanitizer = JvmDeclarationReturnTypeSanitizer
overridesBackwardCompatibilityHelper = JvmOverridesBackwardCompatibilityHelper
) {
override fun configureModuleComponents(container: StorageComponentContainer) {
container.useImpl<JvmReflectionAPICallChecker>()

View File

@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.cfg
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -28,8 +27,9 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
interface ControlFlowBuilder {
// Subroutines
fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null)
fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode
fun enterSubroutine(subroutine: KtElement)
fun exitSubroutine(subroutine: KtElement): Pseudocode
val currentSubroutine: KtElement
val returnSubroutine: KtElement
@@ -49,8 +49,6 @@ interface ControlFlowBuilder {
fun declareVariable(property: KtVariableDeclaration)
fun declareFunction(subroutine: KtElement, pseudocode: Pseudocode)
fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, invocationKind: InvocationKind)
fun declareEntryOrObject(entryOrObject: KtClassOrObject)
// Labels

View File

@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.cfg
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -135,12 +134,11 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.exitTryFinally()
}
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
delegateBuilder.enterSubroutine(subroutine, invocationKind)
override fun enterSubroutine(subroutine: KtElement) {
delegateBuilder.enterSubroutine(subroutine)
}
override fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind?): Pseudocode =
delegateBuilder.exitSubroutine(subroutine, invocationKind)
override fun exitSubroutine(subroutine: KtElement): Pseudocode = delegateBuilder.exitSubroutine(subroutine)
override val currentSubroutine: KtElement
get() = delegateBuilder.currentSubroutine
@@ -180,10 +178,6 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.declareFunction(subroutine, pseudocode)
}
override fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, invocationKind: InvocationKind) {
delegateBuilder.declareInlinedFunction(subroutine, pseudocode, invocationKind)
}
override fun declareEntryOrObject(entryOrObject: KtClassOrObject) {
delegateBuilder.declareEntryOrObject(entryOrObject)
}

View File

@@ -369,8 +369,7 @@ class ControlFlowInformationProvider private constructor(
// Do not consider top-level properties
if (containingDeclarationDescriptor is PackageFragmentDescriptor) return false
var parentDeclaration = getElementParentDeclaration(writeValueInstruction.element)
loop@ while (true) {
while (true) {
val context = trace.bindingContext
val parentDescriptor = getDeclarationDescriptorIncludingConstructors(context, parentDeclaration)
if (parentDescriptor == containingDeclarationDescriptor) {
@@ -382,13 +381,6 @@ class ControlFlowInformationProvider private constructor(
parentDeclaration = getElementParentDeclaration(parentDeclaration)
}
is KtDeclarationWithBody -> {
// If it is captured write in lambda that is called in-place, then skip it (treat as parent)
val maybeEnclosingLambdaExpr = parentDeclaration.parent
if (maybeEnclosingLambdaExpr is KtLambdaExpression && trace[BindingContext.LAMBDA_INVOCATIONS, maybeEnclosingLambdaExpr] != null) {
parentDeclaration = getElementParentDeclaration(parentDeclaration)
continue@loop
}
if (parentDeclaration is KtFunction && parentDeclaration.isLocal) return true
// miss non-local function or accessor just once
parentDeclaration = getElementParentDeclaration(parentDeclaration)

View File

@@ -30,9 +30,6 @@ import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.canBeRevisited
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Errors.*
@@ -61,20 +58,18 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
import java.util.*
typealias DeferredGenerator = (ControlFlowBuilder) -> Unit
class ControlFlowProcessor(private val trace: BindingTrace) {
private val builder: ControlFlowBuilder = ControlFlowInstructionsGenerator()
fun generatePseudocode(subroutine: KtElement): Pseudocode {
val pseudocode = generate(subroutine, null)
val pseudocode = generate(subroutine)
(pseudocode as PseudocodeImpl).postProcess()
return pseudocode
}
private fun generate(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode {
builder.enterSubroutine(subroutine, invocationKind)
private fun generate(subroutine: KtElement): Pseudocode {
builder.enterSubroutine(subroutine)
val cfpVisitor = CFPVisitor(builder)
if (subroutine is KtDeclarationWithBody && subroutine !is KtSecondaryConstructor) {
val valueParameters = subroutine.valueParameters
@@ -92,7 +87,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
else {
cfpVisitor.generateInstructions(subroutine)
}
return builder.exitSubroutine(subroutine, invocationKind)
return builder.exitSubroutine(subroutine)
}
private fun generateImplicitReturnValue(bodyExpression: KtExpression, subroutine: KtElement) {
@@ -110,7 +105,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
val afterDeclaration = builder.createUnboundLabel("after local declaration")
builder.nondeterministicJump(afterDeclaration, subroutine, null)
generate(subroutine, null)
generate(subroutine)
builder.bindLabel(afterDeclaration)
}
@@ -120,13 +115,6 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
private val catchFinallyStack = Stack<CatchFinallyLabels>()
// Some language constructs (e.g. inlined lambdas) should be partially processed before call
// (to provide argument for call itself), and partially - after (in case of inlined lambdas,
// their body should be generated after call). To do so, we store deferred generators, which
// will be called after call instruction is emitted.
// Stack is necessary to store generators across nested calls
private val deferredGeneratorsStack = Stack<MutableList<DeferredGenerator>>()
private val conditionVisitor = object : KtVisitorVoid() {
private fun getSubjectExpression(condition: KtWhenCondition): KtExpression? =
@@ -1032,42 +1020,14 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
return parent.parent is KtDoWhileExpression
}
private fun visitFunction(function: KtFunction, invocationKind: InvocationKind? = null) {
if (invocationKind == null) {
processLocalDeclaration(function)
}
else {
visitInlinedFunction(function, invocationKind)
}
private fun visitFunction(function: KtFunction) {
processLocalDeclaration(function)
val isAnonymousFunction = function is KtFunctionLiteral || function.name == null
if (isAnonymousFunction || function.isLocal && function.parent !is KtBlockExpression) {
builder.createLambda(function)
}
}
private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, invocationKind: InvocationKind) {
// Defer emitting of inlined declaration
deferredGeneratorsStack.peek().add({ builder ->
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
val afterDeclaration = builder.createUnboundLabel("after inlined declaration")
builder.bindLabel(beforeDeclaration)
if (!invocationKind.isDefinitelyVisited()) {
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
}
generate(lambdaFunctionLiteral, invocationKind)
if (invocationKind.canBeRevisited()) {
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
}
builder.bindLabel(afterDeclaration)
})
}
override fun visitNamedFunction(function: KtNamedFunction) {
visitFunction(function)
}
@@ -1075,11 +1035,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
mark(lambdaExpression)
val functionLiteral = lambdaExpression.functionLiteral
// NB. Behaviour here is implicitly controlled by the LanguageFeature 'CallsInPlaceEffect'
// If this feature is turned off, then slice LAMBDA_INVOCATIONS is never written and invocationKind
// in all subsequent calls always 'null', resulting in falling back to old behaviour
visitFunction(functionLiteral, trace[BindingContext.LAMBDA_INVOCATIONS, lambdaExpression])
visitFunction(functionLiteral)
copyValue(functionLiteral, lambdaExpression)
}
@@ -1529,8 +1485,6 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
val receivers = getReceiverValues(resolvedCall)
deferredGeneratorsStack.push(mutableListOf())
var parameterValues = SmartFMap.emptyMap<PseudoValue, ValueParameterDescriptor>()
for (argument in resolvedCall.call.valueArguments) {
val argumentMapping = resolvedCall.getArgumentMapping(argument)
@@ -1553,10 +1507,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
}
mark(resolvedCall.call.callElement)
val callInstruction = builder.call(callElement, resolvedCall, receivers, parameterValues)
val deferredGeneratorsForCall = deferredGeneratorsStack.pop()
deferredGeneratorsForCall.forEach { it.invoke(builder) }
return callInstruction
return builder.call(callElement, resolvedCall, receivers, parameterValues)
}
private fun getReceiverValues(resolvedCall: ResolvedCall<*>): Map<PseudoValue, ReceiverValue> {

View File

@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.cfg.pseudocodeTraverser
import org.jetbrains.kotlin.cfg.ControlFlowInfo
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.InlinedLocalFunctionDeclarationInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineEnterInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineSinkInstruction
@@ -97,13 +96,8 @@ private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
if (instruction is LocalFunctionDeclarationInstruction) {
val subroutinePseudocode = instruction.body
subroutinePseudocode.collectDataFromSubgraph(
traversalOrder, edgesMap, mergeEdges, updateEdge, previousInstructions, changed, true
)
// Special case for inlined functions: take flow from EXIT instructions (it contains flow which exits declaration normally)
val lastInstruction = if (instruction is InlinedLocalFunctionDeclarationInstruction && traversalOrder == FORWARD)
subroutinePseudocode.exitInstruction
else
subroutinePseudocode.getLastInstruction(traversalOrder)
traversalOrder, edgesMap, mergeEdges, updateEdge, previousInstructions, changed, true)
val lastInstruction = subroutinePseudocode.getLastInstruction(traversalOrder)
val previousValue = edgesMap[instruction]
val newValue = edgesMap[lastInstruction]
val updatedValue = newValue?.let {

View File

@@ -190,7 +190,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
private fun WriteValueInstruction.isTrivialInitializer() =
element is KtVariableDeclaration || element is KtParameter
// WriteValueInstruction having KtDeclaration as an element means
// it must be a write happened at the same time when
// the variable (common variable/parameter/object) has been declared
element is KtDeclaration
private inner class ReadOnlyInitControlFlowInfoImpl(
val declaredSet: ImmutableSet<VariableDescriptor>,

View File

@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.*
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -48,8 +47,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
private val allBlocks = Stack<BlockInfo>()
private fun pushBuilder(scopingElement: KtElement, subroutine: KtElement, shouldInline: Boolean) {
val worker = ControlFlowInstructionsGeneratorWorker(scopingElement, subroutine, shouldInline)
private fun pushBuilder(scopingElement: KtElement, subroutine: KtElement) {
val worker = ControlFlowInstructionsGeneratorWorker(scopingElement, subroutine)
builders.push(worker)
builder = worker
}
@@ -65,42 +64,32 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
return worker
}
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
override fun enterSubroutine(subroutine: KtElement) {
val builder = builder
val shouldInlnie = invocationKind != null
if (builder != null && subroutine is KtFunctionLiteral) {
pushBuilder(subroutine, builder.returnSubroutine, shouldInlnie)
pushBuilder(subroutine, builder.returnSubroutine)
}
else {
pushBuilder(subroutine, subroutine, shouldInlnie)
pushBuilder(subroutine, subroutine)
}
delegateBuilder.enterBlockScope(subroutine)
delegateBuilder.enterSubroutine(subroutine)
}
override fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind?): Pseudocode {
super.exitSubroutine(subroutine, invocationKind)
override fun exitSubroutine(subroutine: KtElement): Pseudocode {
super.exitSubroutine(subroutine)
delegateBuilder.exitBlockScope(subroutine)
val worker = popBuilder()
if (!builders.empty()) {
val builder = builders.peek()
if (invocationKind == null) {
builder.declareFunction(subroutine, worker.pseudocode)
}
else {
builder.declareInlinedFunction(subroutine, worker.pseudocode, invocationKind)
}
builder.declareFunction(subroutine, worker.pseudocode)
}
return worker.pseudocode
}
private inner class ControlFlowInstructionsGeneratorWorker(
scopingElement: KtElement,
override val returnSubroutine: KtElement,
shouldInline: Boolean
) : ControlFlowBuilder {
private inner class ControlFlowInstructionsGeneratorWorker(scopingElement: KtElement, override val returnSubroutine: KtElement) : ControlFlowBuilder {
val pseudocode: PseudocodeImpl = PseudocodeImpl(scopingElement, shouldInline)
val pseudocode: PseudocodeImpl = PseudocodeImpl(scopingElement)
private val error: Label = pseudocode.createLabel("error", null)
private val sink: Label = pseudocode.createLabel("sink", null)
@@ -156,7 +145,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override val currentLoop: KtLoopExpression?
get() = if (loopInfo.empty()) null else loopInfo.peek().element
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
override fun enterSubroutine(subroutine: KtElement) {
val blockInfo = SubroutineInfo(
subroutine,
/* entry point */ createUnboundLabel(),
@@ -215,7 +204,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
}
override fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind?): Pseudocode {
override fun exitSubroutine(subroutine: KtElement): Pseudocode {
getSubroutineExitPoint(subroutine)?.let { bindLabel(it) }
pseudocode.addExitInstruction(SubroutineExitInstruction(subroutine, currentScope, false))
bindLabel(error)
@@ -272,10 +261,6 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
add(LocalFunctionDeclarationInstruction(subroutine, pseudocode, currentScope))
}
override fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, invocationKind: InvocationKind) {
add(InlinedLocalFunctionDeclarationInstruction(subroutine, pseudocode, currentScope, invocationKind))
}
override fun declareEntryOrObject(entryOrObject: KtClassOrObject) {
add(VariableDeclarationInstruction(entryOrObject, currentScope))
}

View File

@@ -45,7 +45,6 @@ interface Pseudocode {
val enterInstruction: SubroutineEnterInstruction
val isInlined: Boolean
val containsDoWhile: Boolean
val rootPseudocode: Pseudocode

View File

@@ -27,7 +27,10 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MergeInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.NondeterministicJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineEnterInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineExitInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineSinkInstruction
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.BACKWARD
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.FORWARD
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraverseInstructionResult
@@ -35,7 +38,7 @@ import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverseFollowingInstruction
import org.jetbrains.kotlin.psi.KtElement
import java.util.*
class PseudocodeImpl(override val correspondingElement: KtElement, override val isInlined: Boolean) : Pseudocode {
class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode {
internal val mutableInstructionList = ArrayList<Instruction>()
override val instructions = ArrayList<Instruction>()
@@ -53,8 +56,6 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
getLocalDeclarations(this)
}
val reachableInstructions = hashSetOf<Instruction>()
private val representativeInstructions = HashMap<KtElement, KtElementInstruction>()
private val labels = ArrayList<PseudocodeLabel>()
@@ -109,7 +110,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
override val reversedInstructions: List<Instruction>
get() {
val traversedInstructions = linkedSetOf<Instruction>()
traverseFollowingInstructions(if (this.isInlined) instructions.last() else sinkInstruction, traversedInstructions, BACKWARD, null)
traverseFollowingInstructions(sinkInstruction, traversedInstructions, BACKWARD, null)
if (traversedInstructions.size < instructions.size) {
val simplyReversedInstructions = instructions.reversed()
for (instruction in simplyReversedInstructions) {
@@ -223,17 +224,22 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
postPrecessed = true
errorInstruction.sink = sinkInstruction
exitInstruction.sink = sinkInstruction
for ((index, instruction) in mutableInstructionList.withIndex()) {
//recursively invokes 'postProcess' for local declarations, thus it needs global set of reachable instructions
//recursively invokes 'postProcess' for local declarations
instruction.processInstruction(index)
}
if (parent != null) return
// Collecting reachable instructions should be done after processing all instructions
// (including instructions in local declarations) to avoid being in incomplete state.
collectAndCacheReachableInstructions()
for (localFunctionDeclarationInstruction in localDeclarations) {
(localFunctionDeclarationInstruction.body as PseudocodeImpl).collectAndCacheReachableInstructions()
}
}
private fun collectAndCacheReachableInstructions() {
collectReachableInstructions()
val reachableInstructions = collectReachableInstructions()
for (instruction in mutableInstructionList) {
if (reachableInstructions.contains(instruction)) {
instructions.add(instruction)
@@ -281,14 +287,6 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
instruction.next = sinkInstruction
}
override fun visitInlinedLocalFunctionDeclarationInstruction(instruction: InlinedLocalFunctionDeclarationInstruction) {
val body = instruction.body as PseudocodeImpl
body.parent = this@PseudocodeImpl
body.postProcess()
// Don't add edge to next instruction if flow can't reach exit of inlined declaration
instruction.next = if (body.instructions.contains(body.exitInstruction)) getNextPosition(currentPosition) else sinkInstruction
}
override fun visitSubroutineExit(instruction: SubroutineExitInstruction) {
// Nothing
}
@@ -303,25 +301,25 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
})
}
private fun collectReachableInstructions() {
val reachableFromThisPseudocode = hashSetOf<Instruction>()
traverseFollowingInstructions(enterInstruction, reachableFromThisPseudocode, FORWARD
private fun collectReachableInstructions(): Set<Instruction> {
val visited = hashSetOf<Instruction>()
traverseFollowingInstructions(enterInstruction, visited, FORWARD
) { instruction ->
if (instruction is MagicInstruction && instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
return@traverseFollowingInstructions TraverseInstructionResult.SKIP
}
TraverseInstructionResult.CONTINUE
}
// Don't force-add EXIT and ERROR for inlined pseudocodes because for such
// declarations those instructions has special semantic
if (!isInlined) {
reachableFromThisPseudocode.add(exitInstruction)
reachableFromThisPseudocode.add(errorInstruction)
reachableFromThisPseudocode.add(sinkInstruction)
if (!visited.contains(exitInstruction)) {
visited.add(exitInstruction)
}
reachableFromThisPseudocode.forEach { (it.owner as PseudocodeImpl).reachableInstructions.add(it) }
if (!visited.contains(errorInstruction)) {
visited.add(errorInstruction)
}
if (!visited.contains(sinkInstruction)) {
visited.add(sinkInstruction)
}
return visited
}
private fun markDeadInstructions() {
@@ -345,7 +343,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
}
override fun copy(): PseudocodeImpl {
val result = PseudocodeImpl(correspondingElement, isInlined)
val result = PseudocodeImpl(correspondingElement)
result.repeatWhole(this)
return result
}

View File

@@ -33,10 +33,6 @@ open class InstructionVisitor {
visitInstructionWithNext(instruction)
}
open fun visitInlinedLocalFunctionDeclarationInstruction(instruction: InlinedLocalFunctionDeclarationInstruction) {
visitLocalFunctionDeclarationInstruction(instruction)
}
open fun visitVariableDeclarationInstruction(instruction: VariableDeclarationInstruction) {
visitInstructionWithNext(instruction)
}

View File

@@ -30,9 +30,6 @@ abstract class InstructionVisitorWithResult<out R> {
open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction): R =
visitInstructionWithNext(instruction)
open fun visitInlinedFunctionDeclarationInstruction(instruction: InlinedLocalFunctionDeclarationInstruction): R =
visitLocalFunctionDeclarationInstruction(instruction)
open fun visitVariableDeclarationInstruction(instruction: VariableDeclarationInstruction): R = visitInstructionWithNext(instruction)
open fun visitUnconditionalJump(instruction: UnconditionalJumpInstruction): R = visitJump(instruction)

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.cfg.pseudocode.instructions.special
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.instructions.BlockScope
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.psi.KtElement
class InlinedLocalFunctionDeclarationInstruction(
element: KtElement,
body: Pseudocode,
blockScope: BlockScope,
val kind: InvocationKind
) : LocalFunctionDeclarationInstruction(element, body, blockScope) {
override fun createCopy(): InstructionImpl = InlinedLocalFunctionDeclarationInstruction(element, body, blockScope, kind)
override fun accept(visitor: InstructionVisitor) = visitor.visitInlinedLocalFunctionDeclarationInstruction(this)
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitInlinedFunctionDeclarationInstruction(this)
override fun toString(): String = "inlined(${render(element)})"
}

View File

@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
open class LocalFunctionDeclarationInstruction(
class LocalFunctionDeclarationInstruction(
element: KtElement,
val body: Pseudocode,
blockScope: BlockScope

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.model.ESValue
import org.jetbrains.kotlin.contracts.model.MutableContextInfo
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.IdentifierInfo
fun MutableContextInfo.toDataFlowInfo(languageVersionSettings: LanguageVersionSettings): DataFlowInfo {
var resultingDataFlowInfo = DataFlowInfoFactory.EMPTY
extractDataFlowStatements(equalValues) { leftDfv, rightValue ->
val rightDfv = rightValue.toDataFlowValue()
if (rightDfv != null) {
resultingDataFlowInfo = resultingDataFlowInfo.equate(leftDfv, rightDfv, false, languageVersionSettings)
}
IntArray(42) { it }
}
extractDataFlowStatements(notEqualValues) { leftDfv, rightValue ->
val rightDfv = rightValue.toDataFlowValue()
if (rightDfv != null) {
resultingDataFlowInfo = resultingDataFlowInfo.disequate(leftDfv, rightDfv, languageVersionSettings)
}
}
extractDataFlowStatements(subtypes) { leftDfv, type ->
resultingDataFlowInfo = resultingDataFlowInfo.establishSubtyping(leftDfv, type, languageVersionSettings)
}
return resultingDataFlowInfo
}
inline private fun <D> extractDataFlowStatements(dictionary: Map<ESValue, Set<D>>, callback: (DataFlowValue, D) -> Unit) {
for ((key, setOfValues) in dictionary) {
val leftDfv = key.toDataFlowValue() ?: continue
setOfValues.forEach { callback(leftDfv, it) }
}
}
private fun ESValue.toDataFlowValue(): DataFlowValue? = when (this) {
is ESDataFlowValue -> dataFlowValue
ESConstant.NULL -> DataFlowValue.nullValue(DefaultBuiltIns.Instance)
is ESConstant -> DataFlowValue(IdentifierInfo.NO, type)
else -> null
}

View File

@@ -1,248 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.contracts.description.*
import org.jetbrains.kotlin.contracts.description.expressions.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.ContractDeserializer
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
import org.jetbrains.kotlin.serialization.deserialization.TypeDeserializer
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addIfNotNull
class ContractDeserializerImpl(private val configuration: DeserializationConfiguration) : ContractDeserializer {
override fun deserializeContractFromFunction(
proto: ProtoBuf.Function,
ownerFunction: FunctionDescriptor,
typeTable: TypeTable,
typeDeserializer: TypeDeserializer
): Pair<FunctionDescriptor.UserDataKey<*>, LazyContractProvider>? {
if (!proto.hasContract()) return null
if (!configuration.returnsEffectAllowed && !configuration.callsInPlaceEffectAllowed) return null
val worker = ContractDeserializationWorker(typeTable, typeDeserializer, ownerFunction)
val contract = worker.deserializeContract(proto.contract)
return ContractProviderKey to LazyContractProvider.createInitialized(contract)
}
private class ContractDeserializationWorker(
private val typeTable: TypeTable,
private val typeDeserializer: TypeDeserializer,
private val ownerFunction: FunctionDescriptor
) {
fun deserializeContract(proto: ProtoBuf.Contract): ContractDescription? {
val effects = proto.effectList.map { deserializePossiblyConditionalEffect(it) ?: return null }
return ContractDescription(effects, ownerFunction)
}
private fun deserializePossiblyConditionalEffect(proto: ProtoBuf.Effect): EffectDeclaration? {
if (proto.hasConclusionOfConditionalEffect()) {
// conditional effect
val conclusion = deserializeExpression(proto.conclusionOfConditionalEffect) ?: return null
val effect = deserializeSimpleEffect(proto) ?: return null
return ConditionalEffectDeclaration(effect, conclusion)
}
return deserializeSimpleEffect(proto)
}
private fun deserializeSimpleEffect(proto: ProtoBuf.Effect): EffectDeclaration? {
val type = if (proto.hasEffectType()) proto.effectType else return null
return when (type!!) {
ProtoBuf.Effect.EffectType.RETURNS_CONSTANT -> {
val argument = proto.effectConstructorArgumentList.getOrNull(0)
val returnValue = if (argument == null) ConstantReference.WILDCARD else deserializeExpression(argument) as? ConstantReference ?: return null
ReturnsEffectDeclaration(returnValue)
}
ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL -> {
ReturnsEffectDeclaration(ConstantReference.NOT_NULL)
}
ProtoBuf.Effect.EffectType.CALLS -> {
val argument = proto.effectConstructorArgumentList.getOrNull(0) ?: return null
val callable = extractVariable(argument) ?: return null
val invocationKind = if (proto.hasKind())
proto.kind.toDescriptorInvocationKind() ?: return null
else
InvocationKind.UNKNOWN
CallsEffectDeclaration(callable, invocationKind)
}
}
}
private fun deserializeExpression(proto: ProtoBuf.Expression): BooleanExpression? {
val primitiveType = getPrimitiveType(proto)
val primitiveExpression = extractPrimitiveExpression(proto, primitiveType)
val complexType = getComplexType(proto)
val childs: MutableList<BooleanExpression> = mutableListOf()
childs.addIfNotNull(primitiveExpression)
return when (complexType) {
ComplexExpressionType.AND_SEQUENCE -> {
proto.andArgumentList.mapTo(childs) { deserializeExpression(it) ?: return null }
childs.reduce { acc, booleanExpression -> LogicalAnd(acc, booleanExpression) }
}
ComplexExpressionType.OR_SEQUENCE -> {
proto.orArgumentList.mapTo(childs) { deserializeExpression(it) ?: return null }
childs.reduce { acc, booleanExpression -> LogicalOr(acc, booleanExpression) }
}
null -> primitiveExpression
}
}
private fun extractPrimitiveExpression(proto: ProtoBuf.Expression, primitiveType: PrimitiveExpressionType?): BooleanExpression? {
val isInverted = proto.hasFlags() && Flags.IS_NEGATED.get(proto.flags)
return when (primitiveType) {
PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE, PrimitiveExpressionType.RECEIVER_REFERENCE -> {
(extractVariable(proto) as? BooleanVariableReference?)?.invertIfNecessary(isInverted)
}
PrimitiveExpressionType.CONSTANT ->
(deserializeConstant(proto.constantValue) as? BooleanConstantReference)?.invertIfNecessary(isInverted)
PrimitiveExpressionType.INSTANCE_CHECK -> {
val variable = extractVariable(proto) ?: return null
val type = extractType(proto) ?: return null
IsInstancePredicate(variable, type, isInverted)
}
PrimitiveExpressionType.NULLABILITY_CHECK -> {
val variable = extractVariable(proto) ?: return null
IsNullPredicate(variable, isInverted)
}
null -> null
}
}
private fun BooleanExpression.invertIfNecessary(shouldInvert: Boolean) = if (shouldInvert) LogicalNot(this) else this
private fun extractVariable(proto: ProtoBuf.Expression): VariableReference? {
if (!proto.hasValueParameterReference()) return null
val parameterDescriptor = if (proto.valueParameterReference == 0)
ownerFunction.extensionReceiverParameter ?: return null
else
ownerFunction.valueParameters.getOrNull(proto.valueParameterReference - 1) ?: return null
return if (!KotlinBuiltIns.isBoolean(parameterDescriptor.type))
VariableReference(parameterDescriptor)
else
BooleanVariableReference(parameterDescriptor)
}
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): InvocationKind? = when (this) {
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> InvocationKind.AT_MOST_ONCE
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> InvocationKind.EXACTLY_ONCE
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> InvocationKind.AT_LEAST_ONCE
}
private fun extractType(proto: ProtoBuf.Expression): KotlinType? {
val protoType = when {
proto.hasIsInstanceType() -> proto.isInstanceType
proto.hasIsInstanceTypeId() -> typeTable.types.getOrNull(proto.isInstanceTypeId) ?: return null
else -> return null
}
return typeDeserializer.type(protoType)
}
private fun deserializeConstant(value: ProtoBuf.Expression.ConstantValue): ConstantReference? = when (value) {
ProtoBuf.Expression.ConstantValue.TRUE -> BooleanConstantReference.TRUE
ProtoBuf.Expression.ConstantValue.FALSE -> BooleanConstantReference.FALSE
ProtoBuf.Expression.ConstantValue.NULL -> ConstantReference.NULL
}
private fun getComplexType(proto: ProtoBuf.Expression): ComplexExpressionType? {
val isOrSequence = proto.orArgumentCount != 0
val isAndSequence = proto.andArgumentCount != 0
return when {
isOrSequence && isAndSequence -> null
isOrSequence -> ComplexExpressionType.OR_SEQUENCE
isAndSequence -> ComplexExpressionType.AND_SEQUENCE
else -> null
}
}
private fun getPrimitiveType(proto: ProtoBuf.Expression): PrimitiveExpressionType? {
// Expected to be one element, but can be empty (unknown expression) or contain several elements (invalid data)
val expressionTypes: MutableList<PrimitiveExpressionType> = mutableListOf()
// Check for predicates
when {
proto.hasValueParameterReference() && proto.hasType() ->
expressionTypes.add(PrimitiveExpressionType.INSTANCE_CHECK)
proto.hasValueParameterReference() && proto.hasFlag(Flags.IS_NULL_CHECK_PREDICATE) ->
expressionTypes.add(PrimitiveExpressionType.NULLABILITY_CHECK)
}
// If message contains correct predicate, then predicate's type overrides type of value,
// even is message has one
if (expressionTypes.isNotEmpty()) {
return expressionTypes.singleOrNull()
}
// Otherwise, check if it is a value
when {
proto.hasValueParameterReference() && proto.valueParameterReference > 0 ->
expressionTypes.add(PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE)
proto.hasValueParameterReference() && proto.valueParameterReference == 0 ->
expressionTypes.add(PrimitiveExpressionType.RECEIVER_REFERENCE)
proto.hasConstantValue() -> expressionTypes.add(PrimitiveExpressionType.CONSTANT)
}
return expressionTypes.singleOrNull()
}
private fun ProtoBuf.Expression.hasType(): Boolean = this.hasIsInstanceType() || this.hasIsInstanceTypeId()
private fun ProtoBuf.Expression.hasFlag(flag: Flags.BooleanFlagField) =
this.hasFlags() && flag.get(this.flags)
// Arguments of expressions with such types are never other expressions
private enum class PrimitiveExpressionType {
VALUE_PARAMETER_REFERENCE,
RECEIVER_REFERENCE,
CONSTANT,
INSTANCE_CHECK,
NULLABILITY_CHECK
}
// Expressions with such type can take other expressions as arguments.
// Additionally, for performance reasons, "complex expression" and "primitive expression"
// can co-exist in the one and the same message. If "primitive expression" is present
// in the current message, it is treated as the first argument of "complex expression".
private enum class ComplexExpressionType {
AND_SEQUENCE,
OR_SEQUENCE
}
}
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts
import org.jetbrains.kotlin.contracts.model.ESValue
import org.jetbrains.kotlin.contracts.model.structure.ESVariable
import org.jetbrains.kotlin.contracts.model.ESExpressionVisitor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
class ESDataFlowValue(descriptor: ValueDescriptor, val dataFlowValue: DataFlowValue) : ESVariable(descriptor)
class ESLambda(val lambda: KtLambdaExpression) : ESValue(null) {
override fun <T> accept(visitor: ESExpressionVisitor<T>): T {
throw IllegalStateException("Lambdas shouldn't be visited by ESExpressionVisitor")
}
}

View File

@@ -1,124 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.model.structure.ESCalls
import org.jetbrains.kotlin.contracts.model.structure.ESReturns
import org.jetbrains.kotlin.contracts.model.functors.EqualsFunctor
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
import org.jetbrains.kotlin.contracts.model.structure.UNKNOWN_COMPUTATION
import org.jetbrains.kotlin.contracts.model.structure.lift
import org.jetbrains.kotlin.contracts.model.ESEffect
import org.jetbrains.kotlin.contracts.model.Computation
import org.jetbrains.kotlin.contracts.model.MutableContextInfo
import org.jetbrains.kotlin.contracts.model.visitors.InfoCollector
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.ConditionalDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
fun getDataFlowInfoForFinishedCall(
resolvedCall: ResolvedCall<*>,
bindingTrace: BindingTrace,
moduleDescriptor: ModuleDescriptor
): DataFlowInfo {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return DataFlowInfo.EMPTY
// Prevent launch of effect system machinery on pointless cases (constants/enums/constructors/etc.)
val callExpression = resolvedCall.call.callElement as? KtCallExpression ?: return DataFlowInfo.EMPTY
if (callExpression is KtDeclaration) return DataFlowInfo.EMPTY
val resultContextInfo = getContextInfoWhen(ESReturns(ESConstant.WILDCARD), callExpression, bindingTrace, moduleDescriptor)
return resultContextInfo.toDataFlowInfo(languageVersionSettings)
}
fun getDataFlowInfoWhenEquals(
leftExpression: KtExpression?,
rightExpression: KtExpression?,
bindingTrace: BindingTrace,
moduleDescriptor: ModuleDescriptor
): ConditionalDataFlowInfo {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return ConditionalDataFlowInfo.EMPTY
if (leftExpression == null || rightExpression == null) return ConditionalDataFlowInfo.EMPTY
val leftComputation = getNonTrivialComputation(leftExpression, bindingTrace, moduleDescriptor) ?: return ConditionalDataFlowInfo.EMPTY
val rightComputation = getNonTrivialComputation(rightExpression, bindingTrace, moduleDescriptor) ?: return ConditionalDataFlowInfo.EMPTY
val effects = EqualsFunctor(false).invokeWithArguments(leftComputation, rightComputation)
val equalsContextInfo = InfoCollector(ESReturns(true.lift())).collectFromSchema(effects)
val notEqualsContextInfo = InfoCollector(ESReturns(false.lift())).collectFromSchema(effects)
return ConditionalDataFlowInfo(
equalsContextInfo.toDataFlowInfo(languageVersionSettings),
notEqualsContextInfo.toDataFlowInfo(languageVersionSettings)
)
}
fun recordDefiniteInvocations(resolvedCall: ResolvedCall<*>, bindingTrace: BindingTrace, moduleDescriptor: ModuleDescriptor) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect)) return
// Prevent launch of effect system machinery on pointless cases (constants/enums/constructors/etc.)
val callExpression = resolvedCall.call.callElement as? KtCallExpression ?: return
if (callExpression is KtDeclaration) return
val resultingContextInfo = getContextInfoWhen(ESReturns(ESConstant.WILDCARD), callExpression, bindingTrace, moduleDescriptor)
for (effect in resultingContextInfo.firedEffects) {
val callsEffect = effect as? ESCalls ?: continue
val lambdaExpression = (callsEffect.callable as? ESLambda)?.lambda ?: continue
bindingTrace.record(BindingContext.LAMBDA_INVOCATIONS, lambdaExpression, callsEffect.kind)
}
}
fun extractDataFlowInfoFromCondition(
condition: KtExpression?,
value: Boolean,
bindingTrace: BindingTrace,
moduleDescriptor: ModuleDescriptor
): DataFlowInfo {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return DataFlowInfo.EMPTY
if (condition == null) return DataFlowInfo.EMPTY
return getContextInfoWhen(ESReturns(value.lift()), condition, bindingTrace, moduleDescriptor)
.toDataFlowInfo(languageVersionSettings)
}
private fun getContextInfoWhen(
observedEffect: ESEffect,
expression: KtExpression,
bindingTrace: BindingTrace,
moduleDescriptor: ModuleDescriptor
): MutableContextInfo {
val computation = getNonTrivialComputation(expression, bindingTrace, moduleDescriptor) ?: return MutableContextInfo.EMPTY
return InfoCollector(observedEffect).collectFromSchema(computation.effects)
}
private fun getNonTrivialComputation(expression: KtExpression, trace: BindingTrace, moduleDescriptor: ModuleDescriptor): Computation? {
val computation = EffectsExtractingVisitor(trace, moduleDescriptor).extractOrGetCached(expression)
return if (computation == UNKNOWN_COMPUTATION) null else computation
}
}

View File

@@ -1,170 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.contracts.interpretation.ContractInterpretationDispatcher
import org.jetbrains.kotlin.contracts.model.Computation
import org.jetbrains.kotlin.contracts.model.Functor
import org.jetbrains.kotlin.contracts.model.functors.*
import org.jetbrains.kotlin.contracts.model.structure.CallComputation
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
import org.jetbrains.kotlin.contracts.model.structure.UNKNOWN_COMPUTATION
import org.jetbrains.kotlin.contracts.model.structure.lift
import org.jetbrains.kotlin.contracts.parsing.isEqualsDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addIfNotNull
/**
* Visits a given PSI-tree of call (and nested calls, if any) and extracts information
* about effects of that call.
*/
class EffectsExtractingVisitor(
private val trace: BindingTrace,
private val moduleDescriptor: ModuleDescriptor
) : KtVisitor<Computation, Unit>() {
fun extractOrGetCached(element: KtElement): Computation {
trace[BindingContext.EXPRESSION_EFFECTS, element]?.let { return it }
return element.accept(this, Unit).also { trace.record(BindingContext.EXPRESSION_EFFECTS, element, it) }
}
override fun visitKtElement(element: KtElement, data: Unit): Computation {
val resolvedCall = element.getResolvedCall(trace.bindingContext) ?: return UNKNOWN_COMPUTATION
if (resolvedCall.isCallWithUnsupportedReceiver()) return UNKNOWN_COMPUTATION
val arguments = resolvedCall.getCallArgumentsAsComputations() ?: return UNKNOWN_COMPUTATION
val descriptor = resolvedCall.resultingDescriptor
return when {
descriptor.isEqualsDescriptor() -> CallComputation(DefaultBuiltIns.Instance.booleanType, EqualsFunctor(false).invokeWithArguments(arguments))
descriptor is ValueDescriptor -> ESDataFlowValue(descriptor, (element as KtExpression).createDataFlowValue() ?: return UNKNOWN_COMPUTATION)
descriptor is FunctionDescriptor -> CallComputation(descriptor.returnType, descriptor.getFunctor()?.invokeWithArguments(arguments) ?: emptyList())
else -> UNKNOWN_COMPUTATION
}
}
// We need lambdas only as arguments currently, and it is processed in 'visitElement' while parsing arguments of call.
// For all other cases we don't need lambdas.
override fun visitLambdaExpression(expression: KtLambdaExpression, data: Unit?): Computation = UNKNOWN_COMPUTATION
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: Unit): Computation =
KtPsiUtil.deparenthesize(expression)?.accept(this, data) ?: UNKNOWN_COMPUTATION
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit): Computation {
val bindingContext = trace.bindingContext
val type: KotlinType = bindingContext.getType(expression) ?: return UNKNOWN_COMPUTATION
val compileTimeConstant: CompileTimeConstant<*>
= bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expression) ?: return UNKNOWN_COMPUTATION
val value: Any? = compileTimeConstant.getValue(type)
return when (value) {
is Boolean -> value.lift()
null -> ESConstant.NULL
else -> UNKNOWN_COMPUTATION
}
}
override fun visitIsExpression(expression: KtIsExpression, data: Unit): Computation {
val rightType: KotlinType = trace[BindingContext.TYPE, expression.typeReference] ?: return UNKNOWN_COMPUTATION
val arg = extractOrGetCached(expression.leftHandSide)
return CallComputation(DefaultBuiltIns.Instance.booleanType, IsFunctor(rightType, expression.isNegated).invokeWithArguments(listOf(arg)))
}
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Unit): Computation {
val left = extractOrGetCached(expression.left ?: return UNKNOWN_COMPUTATION)
val right = extractOrGetCached(expression.right ?: return UNKNOWN_COMPUTATION)
val args = listOf(left, right)
return when (expression.operationToken) {
KtTokens.EXCLEQ -> CallComputation(DefaultBuiltIns.Instance.booleanType, EqualsFunctor(true).invokeWithArguments(args))
KtTokens.EQEQ -> CallComputation(DefaultBuiltIns.Instance.booleanType, EqualsFunctor(false).invokeWithArguments(args))
KtTokens.ANDAND -> CallComputation(DefaultBuiltIns.Instance.booleanType, AndFunctor().invokeWithArguments(args))
KtTokens.OROR -> CallComputation(DefaultBuiltIns.Instance.booleanType, OrFunctor().invokeWithArguments(args))
else -> UNKNOWN_COMPUTATION
}
}
override fun visitUnaryExpression(expression: KtUnaryExpression, data: Unit): Computation {
val arg = extractOrGetCached(expression.baseExpression ?: return UNKNOWN_COMPUTATION)
return when (expression.operationToken) {
KtTokens.EXCL -> CallComputation(DefaultBuiltIns.Instance.booleanType, NotFunctor().invokeWithArguments(arg))
else -> UNKNOWN_COMPUTATION
}
}
private fun ReceiverValue.toComputation(): Computation = when (this) {
is ExpressionReceiver -> extractOrGetCached(expression)
else -> UNKNOWN_COMPUTATION
}
private fun KtExpression.createDataFlowValue(): DataFlowValue? {
return DataFlowValueFactory.createDataFlowValue(
expression = this,
type = trace.getType(this) ?: return null,
bindingContext = trace.bindingContext,
containingDeclarationOrModule = moduleDescriptor
)
}
private fun FunctionDescriptor.getFunctor(): Functor? {
trace[BindingContext.FUNCTOR, this]?.let { return it }
val functor = ContractInterpretationDispatcher().resolveFunctor(this) ?: return null
trace.record(BindingContext.FUNCTOR, this, functor)
return functor
}
private fun ResolvedCall<*>.isCallWithUnsupportedReceiver(): Boolean =
(extensionReceiver as? ExpressionReceiver)?.expression?.getResolvedCall(trace.bindingContext) == this ||
(dispatchReceiver as? ExpressionReceiver)?.expression?.getResolvedCall(trace.bindingContext) == this ||
(explicitReceiverKind == ExplicitReceiverKind.BOTH_RECEIVERS)
private fun ResolvedCall<*>.getCallArgumentsAsComputations(): List<Computation>? {
val arguments = mutableListOf<Computation>()
arguments.addIfNotNull(extensionReceiver?.toComputation())
arguments.addIfNotNull(dispatchReceiver?.toComputation())
valueArgumentsByIndex?.mapTo(arguments) {
val valueArgument = (it as? ExpressionValueArgument)?.valueArgument ?: return null
when (valueArgument) {
is KtLambdaArgument -> ESLambda(valueArgument.getLambdaExpression())
else -> extractOrGetCached(valueArgument.getArgumentExpression() ?: return null)
}
} ?: return null
return arguments
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.ContractDescription
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
class ContractParsingServices(val languageVersionSettings: LanguageVersionSettings) {
fun fastCheckIfContractPresent(element: KtElement): Boolean {
if (!isContractAllowedHere(element)) return false
val firstExpression = ((element as? KtFunction)?.bodyExpression as? KtBlockExpression)?.statements?.firstOrNull() ?: return false
return isContractDescriptionCallFastCheck(firstExpression)
}
fun checkContractAndRecordIfPresent(expression: KtExpression, trace: BindingTrace, scope: LexicalScope, isFirstStatement: Boolean) {
val ownerDescriptor = scope.ownerDescriptor
if (!isContractDescriptionCallFastCheck(expression) || ownerDescriptor !is FunctionDescriptor) return
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey) ?: return
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect) ||
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
languageVersionSettings.getFlag(AnalysisFlag.Flags.allowKotlinPackage)
val contractDescriptor = when {
!isFeatureTurnedOn || !isContractDescriptionCallPreciseCheck(expression, trace.bindingContext) -> null
!isContractAllowedHere(scope) || !isFirstStatement -> {
trace.report(Errors.CONTRACT_NOT_ALLOWED.on(expression))
null
}
else -> parseContract(expression, trace, ownerDescriptor)
}
contractProvider.setContractDescription(contractDescriptor)
}
private fun parseContract(expression: KtExpression?, trace: BindingTrace, ownerDescriptor: FunctionDescriptor): ContractDescription? =
PsiContractParserDispatcher(trace, this).parseContract(expression, ownerDescriptor)
internal fun isContractDescriptionCall(expression: KtExpression, context: BindingContext): Boolean =
isContractDescriptionCallFastCheck(expression) && isContractDescriptionCallPreciseCheck(expression, context)
private fun isContractAllowedHere(element: KtElement): Boolean =
element is KtNamedFunction && element.isTopLevel && element.hasBlockBody() && !element.hasModifier(KtTokens.OPERATOR_KEYWORD)
private fun isContractAllowedHere(scope: LexicalScope): Boolean =
scope.kind == LexicalScopeKind.CODE_BLOCK && (scope.parent as? LexicalScope)?.kind == LexicalScopeKind.FUNCTION_INNER_SCOPE
private fun isContractDescriptionCallFastCheck(expression: KtExpression): Boolean =
expression is KtCallExpression && expression.calleeExpression?.text == "contract"
private fun isContractDescriptionCallPreciseCheck(expression: KtExpression, context: BindingContext): Boolean =
expression.getResolvedCall(context)?.resultingDescriptor?.isContractCallDescriptor() ?: false
}

View File

@@ -1,111 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.contracts.description.*
import org.jetbrains.kotlin.contracts.description.expressions.*
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
internal class PsiConditionParser(val trace: BindingTrace, val dispatcher: PsiContractParserDispatcher) : KtVisitor<BooleanExpression?, Unit>() {
override fun visitIsExpression(expression: KtIsExpression, data: Unit): BooleanExpression? {
val variable = dispatcher.parseVariable(expression.leftHandSide) ?: return null
val typeReference = expression.typeReference ?: return null
val type = trace[BindingContext.TYPE, typeReference] ?: return null
return IsInstancePredicate(variable, type, expression.isNegated)
}
override fun visitKtElement(element: KtElement, data: Unit): BooleanExpression? {
val resolvedCall = element.getResolvedCall(trace.bindingContext)
val descriptor = resolvedCall?.resultingDescriptor ?: return null
// boolean variable
if (descriptor is ValueDescriptor) {
val booleanVariable = dispatcher.parseVariable(element as? KtExpression) ?: return null
// we don't report type mismatch because it will be reported by the typechecker
return booleanVariable as? BooleanVariableReference
}
// operator
when {
descriptor.isEqualsDescriptor() -> {
val left = dispatcher.parseValue((resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression) ?: return null
val right = dispatcher.parseValue(resolvedCall.firstArgumentAsExpressionOrNull()) ?: return null
val isNegated = (element as? KtBinaryExpression)?.operationToken == KtTokens.EXCLEQ ?: false
if (left is ConstantReference && left == ConstantReference.NULL && right is VariableReference) {
return IsNullPredicate(right, isNegated)
}
if (right is ConstantReference && right == ConstantReference.NULL && left is VariableReference) {
return IsNullPredicate(left, isNegated)
}
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(element, "only equality comparisons with 'null' allowed"))
return null
}
else -> {
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(element, "unsupported construction"))
return null
}
}
}
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit?): BooleanExpression? {
// we don't report type mismatch because it will be reported by the typechecker
return dispatcher.parseConstant(expression) as? BooleanConstantReference
}
override fun visitCallExpression(expression: KtCallExpression, data: Unit?): BooleanExpression? {
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression, "call-expressions are not supported yet"))
return null
}
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Unit): BooleanExpression? {
val operationConstructor: (BooleanExpression, BooleanExpression) -> BooleanExpression
when (expression.operationToken) {
KtTokens.ANDAND -> operationConstructor = ::LogicalAnd
KtTokens.OROR -> operationConstructor = ::LogicalOr
else -> return super.visitBinaryExpression(expression, data) // pass binary expression further
}
val left = expression.left?.accept(this, data) ?: return null
val right = expression.right?.accept(this, data) ?: return null
return operationConstructor(left, right)
}
override fun visitUnaryExpression(expression: KtUnaryExpression, data: Unit): BooleanExpression? {
if (expression.operationToken != KtTokens.EXCL) return super.visitUnaryExpression(expression, data)
val arg = expression.baseExpression?.accept(this, data) ?: return null
if (arg !is ContractDescriptionValue) {
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression.baseExpression!!, "negations in contract description can be applied only to variables/values"))
}
return LogicalNot(arg)
}
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: Unit): BooleanExpression? =
KtPsiUtil.deparenthesize(expression)?.accept(this, data)
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.contracts.description.expressions.BooleanConstantReference
import org.jetbrains.kotlin.contracts.description.expressions.ConstantReference
import org.jetbrains.kotlin.psi.KtConstantExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtVisitor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.types.KotlinType
internal class PsiConstantParser(val trace: BindingTrace) : KtVisitor<ConstantReference?, Unit>() {
override fun visitKtElement(element: KtElement, data: Unit?): ConstantReference? = null
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit?): ConstantReference? {
val type: KotlinType = trace.getType(expression) ?: return null
val compileTimeConstant: CompileTimeConstant<*>
= trace.get(BindingContext.COMPILE_TIME_VALUE, expression) ?: return null
val value: Any? = compileTimeConstant.getValue(type)
return when (value) {
true -> BooleanConstantReference.TRUE
false -> BooleanConstantReference.FALSE
null -> ConstantReference.NULL
else -> null
}
}
}

View File

@@ -1,112 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.contracts.description.BooleanExpression
import org.jetbrains.kotlin.contracts.description.ContractDescription
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
import org.jetbrains.kotlin.contracts.description.expressions.BooleanVariableReference
import org.jetbrains.kotlin.contracts.description.expressions.ConstantReference
import org.jetbrains.kotlin.contracts.description.expressions.ContractDescriptionValue
import org.jetbrains.kotlin.contracts.description.expressions.VariableReference
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.CALLS_IN_PLACE_EFFECT
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.CONDITIONAL_EFFECT
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.RETURNS_EFFECT
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.RETURNS_NOT_NULL_EFFECT
import org.jetbrains.kotlin.contracts.parsing.effects.PsiCallsEffectParser
import org.jetbrains.kotlin.contracts.parsing.effects.PsiConditionalEffectParser
import org.jetbrains.kotlin.contracts.parsing.effects.PsiReturnsEffectParser
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
internal class PsiContractParserDispatcher(val trace: BindingTrace, val contractParsingServices: ContractParsingServices) {
private val conditionParser = PsiConditionParser(trace, this)
private val constantParser = PsiConstantParser(trace)
private val effectsParsers: Map<Name, PsiEffectParser> = mapOf(
RETURNS_EFFECT to PsiReturnsEffectParser(trace, this),
RETURNS_NOT_NULL_EFFECT to PsiReturnsEffectParser(trace, this),
CALLS_IN_PLACE_EFFECT to PsiCallsEffectParser(trace, this),
CONDITIONAL_EFFECT to PsiConditionalEffectParser(trace, this)
)
fun parseContract(expression: KtExpression?, ownerDescriptor: FunctionDescriptor): ContractDescription? {
if (expression == null) return null
if (!contractParsingServices.isContractDescriptionCall(expression, trace.bindingContext)) return null
val resolvedCall = expression.getResolvedCall(trace.bindingContext)!! // Must be non-null due to 'isContractDescriptionCall' check
val lambda = resolvedCall.firstArgumentAsExpressionOrNull() as? KtLambdaExpression ?: return null
val effects = lambda.bodyExpression?.statements?.mapNotNull { parseEffect(it) } ?: return null
if (effects.isEmpty()) return null
return ContractDescription(effects, ownerDescriptor)
}
fun parseCondition(expression: KtExpression?): BooleanExpression? = expression?.accept(conditionParser, Unit)
fun parseEffect(expression: KtExpression?): EffectDeclaration? {
if (expression == null) return null
val returnType = expression.getType(trace.bindingContext) ?: return null
val parser = effectsParsers[returnType.constructor.declarationDescriptor?.name]
if (parser == null) {
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression, "Unrecognized effect"))
return null
}
return parser.tryParseEffect(expression)
}
fun parseConstant(expression: KtExpression?): ConstantReference? {
if (expression == null) return null
return expression.accept(constantParser, Unit)
}
fun parseVariable(expression: KtExpression?): VariableReference? {
if (expression == null) return null
val descriptor = expression.getResolvedCall(trace.bindingContext)?.resultingDescriptor ?: return null
if (descriptor !is ParameterDescriptor) {
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression, "only references to parameters are allowed in contract description"))
return null
}
if (descriptor is ReceiverParameterDescriptor && descriptor.type.constructor.declarationDescriptor?.isFromContractDsl() == true) {
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression, "only references to parameters are allowed. Did you miss label on <this>?"))
}
return if (KotlinBuiltIns.isBoolean(descriptor.type))
BooleanVariableReference(descriptor)
else
VariableReference(descriptor)
}
fun parseValue(expression: KtExpression?): ContractDescriptionValue? {
val variable = parseVariable(expression)
if (variable != null) return variable
return parseConstant(expression)
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.CALLS_IN_PLACE
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.CONTRACT
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.CONTRACTS_DSL_ANNOTATION_FQN
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.EFFECT
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.IMPLIES
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.INVOCATION_KIND_ENUM
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.RETURNS
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames.RETURNS_NOT_NULL
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.typeUtil.isBoolean
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object ContractsDslNames {
// Internal marker-annotation for distinguishing our API
val CONTRACTS_DSL_ANNOTATION_FQN = FqName("kotlin.internal.ContractsDsl")
// Types
val EFFECT = Name.identifier("Effect")
val CONDITIONAL_EFFECT = Name.identifier("ConditionalEffect")
val SIMPLE_EFFECT = Name.identifier("SimpleEffect")
val RETURNS_EFFECT = Name.identifier("Returns")
val RETURNS_NOT_NULL_EFFECT = Name.identifier("ReturnsNotNull")
val CALLS_IN_PLACE_EFFECT = Name.identifier("CallsInPlace")
// Structure-defining calls
val CONTRACT = Name.identifier("contract")
val IMPLIES = Name.identifier("implies")
// Effect-declaration calls
val RETURNS = Name.identifier("returns")
val RETURNS_NOT_NULL = Name.identifier("returnsNotNull")
val CALLS_IN_PLACE = Name.identifier("callsInPlace")
// enum class InvocationKind
val INVOCATION_KIND_ENUM = Name.identifier("InvocationKind")
val EXACTLY_ONCE_KIND = Name.identifier("EXACTLY_ONCE")
val AT_LEAST_ONCE_KIND = Name.identifier("AT_LEAST_ONCE")
val UNKNOWN_KIND = Name.identifier("UNKNOWN")
val AT_MOST_ONCE_KIND = Name.identifier("AT_MOST_ONCE")
}
fun DeclarationDescriptor.isFromContractDsl(): Boolean = this.annotations.hasAnnotation(CONTRACTS_DSL_ANNOTATION_FQN)
fun DeclarationDescriptor.isContractCallDescriptor(): Boolean = equalsDslDescriptor(CONTRACT)
fun DeclarationDescriptor.isImpliesCallDescriptor(): Boolean = equalsDslDescriptor(IMPLIES)
fun DeclarationDescriptor.isReturnsEffectDescriptor(): Boolean = equalsDslDescriptor(RETURNS)
fun DeclarationDescriptor.isReturnsNotNullDescriptor(): Boolean = equalsDslDescriptor(RETURNS_NOT_NULL)
fun DeclarationDescriptor.isEffectDescriptor(): Boolean = equalsDslDescriptor(EFFECT)
fun DeclarationDescriptor.isCallsInPlaceEffectDescriptor(): Boolean = equalsDslDescriptor(CALLS_IN_PLACE)
fun DeclarationDescriptor.isInvocationKindEnum(): Boolean = equalsDslDescriptor(INVOCATION_KIND_ENUM)
fun DeclarationDescriptor.isEqualsDescriptor(): Boolean =
this is FunctionDescriptor && this.name == Name.identifier("equals") && // fast checks
this.returnType?.isBoolean() == true && this.valueParameters.singleOrNull()?.type?.isNullableAny() == true // signature matches
internal fun ResolvedCall<*>.firstArgumentAsExpressionOrNull(): KtExpression? =
this.valueArgumentsByIndex?.firstOrNull()?.safeAs<ExpressionValueArgument>()?.valueArgument?.getArgumentExpression()
private fun DeclarationDescriptor.equalsDslDescriptor(dslName: Name): Boolean = this.name == dslName && this.isFromContractDsl()

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingTrace
internal interface PsiEffectParser {
fun tryParseEffect(expression: KtExpression): EffectDeclaration?
}
internal abstract class AbstractPsiEffectParser(val trace: BindingTrace, val contractParserDispatcher: PsiContractParserDispatcher) : PsiEffectParser

View File

@@ -1,67 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing.effects
import org.jetbrains.kotlin.contracts.description.CallsEffectDeclaration
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.parsing.*
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
internal class PsiCallsEffectParser(
trace: BindingTrace,
contractParserDispatcher: PsiContractParserDispatcher
) : AbstractPsiEffectParser(trace, contractParserDispatcher) {
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null
val descriptor = resolvedCall.resultingDescriptor
if (!descriptor.isCallsInPlaceEffectDescriptor()) return null
val lambda = contractParserDispatcher.parseVariable(resolvedCall.firstArgumentAsExpressionOrNull()) ?: return null
val kindArgument = resolvedCall.valueArgumentsByIndex?.getOrNull(1)
val kind = when (kindArgument) {
is DefaultValueArgument -> InvocationKind.UNKNOWN
is ExpressionValueArgument -> kindArgument.valueArgument?.getArgumentExpression()?.toInvocationKind(trace) ?: return null
else -> return null
}
return CallsEffectDeclaration(lambda, kind)
}
private fun KtExpression.toInvocationKind(trace: BindingTrace): InvocationKind? {
val descriptor = this.getResolvedCall(trace.bindingContext)?.resultingDescriptor ?: return null
if (!descriptor.parents.first().isInvocationKindEnum()) return null
return when (descriptor.fqNameSafe.shortName()) {
ContractsDslNames.AT_MOST_ONCE_KIND -> InvocationKind.AT_MOST_ONCE
ContractsDslNames.EXACTLY_ONCE_KIND -> InvocationKind.EXACTLY_ONCE
ContractsDslNames.AT_LEAST_ONCE_KIND -> InvocationKind.AT_LEAST_ONCE
ContractsDslNames.UNKNOWN_KIND -> InvocationKind.UNKNOWN
else -> null
}
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing.effects
import org.jetbrains.kotlin.contracts.description.ConditionalEffectDeclaration
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
import org.jetbrains.kotlin.contracts.parsing.AbstractPsiEffectParser
import org.jetbrains.kotlin.contracts.parsing.PsiContractParserDispatcher
import org.jetbrains.kotlin.contracts.parsing.firstArgumentAsExpressionOrNull
import org.jetbrains.kotlin.contracts.parsing.isImpliesCallDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal class PsiConditionalEffectParser(
trace: BindingTrace,
dispatcher: PsiContractParserDispatcher
) : AbstractPsiEffectParser(trace, dispatcher) {
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null
if (!resolvedCall.resultingDescriptor.isImpliesCallDescriptor()) return null
val effect = contractParserDispatcher.parseEffect(resolvedCall.dispatchReceiver.safeAs<ExpressionReceiver>()?.expression)
?: return null
val condition = contractParserDispatcher.parseCondition(resolvedCall.firstArgumentAsExpressionOrNull())
?: return null
return ConditionalEffectDeclaration(effect, condition)
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.parsing.effects
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
import org.jetbrains.kotlin.contracts.description.ReturnsEffectDeclaration
import org.jetbrains.kotlin.contracts.description.expressions.ConstantReference
import org.jetbrains.kotlin.contracts.parsing.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
internal class PsiReturnsEffectParser(
trace: BindingTrace,
contractParserDispatcher: PsiContractParserDispatcher
) : AbstractPsiEffectParser(trace, contractParserDispatcher) {
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null
val descriptor = resolvedCall.resultingDescriptor
if (descriptor.isReturnsNotNullDescriptor())
return ReturnsEffectDeclaration(ConstantReference.NOT_NULL)
if (!descriptor.isReturnsEffectDescriptor()) return null
val argumentExpression = resolvedCall.firstArgumentAsExpressionOrNull()
val constantValue = if (argumentExpression == null)
ConstantReference.WILDCARD
else {
// Note that we distinguish absence of an argument and unparsed argument
val constant = contractParserDispatcher.parseConstant(argumentExpression)
if (constant == null) {
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(argumentExpression, "only true/false/null constants in Returns-effect are currently supported"))
return null
}
constant
}
return ReturnsEffectDeclaration(constantValue)
}
}

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