Compare commits

...

88 Commits

Author SHA1 Message Date
Vyacheslav Gerasimov
3726f6331d Update changelog for 1.2.71 2018-09-24 17:23:03 +03:00
Ilya Gorbunov
a4f20ba14c Mix kotlin-annotations-jvm with kotlin-reflect into proguard
So it can strip these annotations from the resulting jar.

#KT-26929 Fixed

(cherry picked from commit 86ba5ebf29)
2018-09-19 16:12:16 +03:00
Nikolay Krasko
d41cf03ccd Fix compilation error in MavenMigrateTest.kt
(cherry picked from commit b31de355db)
2018-09-18 18:32:55 +03:00
Nikolay Krasko
85f1ce234d Don't show migration dialog if no actual migrations are available (KT-26889)
#KT-26889 Fixed
2018-09-18 15:01:14 +03:00
Nikolay Krasko
d10d140ef7 Postpone migration till indexes are ready (KT-26428)
#KT-26428 Fixed
2018-09-18 15:01:03 +03:00
Mikhail Glukhikh
3d407d489a Kotlin migration: fix data context calculation for 173 / AS31
Version for IDEA 182 does not work properly here (returns null),
so we have to use `DataManager.getDataContext(focusedComponent)` directly

#KT-26399 Fixed
2018-09-18 15:00:48 +03:00
Mikhail Glukhikh
e0723c573d Kotlin migration: extract data context into a function, check it on null
The extraction itself is needed due to different behaviour of related
IDEA functions in different platforms.
Check on null is needed because `createFromAnAction` last argument
cannot be null, otherwise we will get an exception.

Partial fix of KT-26399
2018-09-18 15:00:36 +03:00
Nikolay Krasko
4447e4ce4e Update Android Studio 3.2 dependency to 3.2 RC 3 2018-09-18 14:58:54 +03:00
Nikolay Krasko
1c6ae28889 Better parsing for external library name (KT-26794)
- Migration notification fixed
- Make fix for replacing old coroutines libraries applicable

 #KT-26794
2018-09-16 15:20:47 +03:00
Mikhail Zarechenskiy
2d99872dc6 Add regression test for KT-26806
#KT-26806
2018-09-14 20:30:41 +03:00
Mikhail Zarechenskiy
7a54feded5 Revert "Do not return field signature if there's none in the metadata"
This reverts commit 3345dc81fd.

The problem is actually that stdlib 1.2.70 is compiled with the old version of
the Kotlin compiler, which doesn't write `has_field` flag for const vals
inside multifile classes (kotlin.math.PI case) and in this commit
we rely on the fix (see if operator with signature.hasField() condition)

Also, we can't just advance bootstrap, because the same problem then will
occur with the stdlib 1.2.60. The right fix will depend on the metadata
version and will be introduced in the future release

 #KT-26806 Fixed
2018-09-14 20:30:41 +03:00
Raluca Sauciuc
833be3d349 Expand the fix from commit 6c274cecff to cover AndroidX
Android Studio users who migrated to AndroidX are running into the
databinding deadlock again: https://issuetracker.google.com/111788726

(cherry picked from commit de989c4050)
2018-09-14 18:15:35 +03:00
Toshiaki Kameyama
6527fbfacc Extract function: make default visibility private #KT-25454 Fixed
(cherry picked from commit e1dd85429f)
2018-09-14 13:21:45 +03:00
Vyacheslav Gerasimov
86e5d48716 Update changelog for 1.2.70 Release 2018-09-11 18:47:26 +03:00
Nikolay Krasko
a04ea1a16d Fix code style applier (KT-23400)
- Stop removing defined schemes and clone settings before modification
- Clone code styles before modification
- Don't bother users that already have needed code style with settings change

(cherry picked from commit 462000ae19)
2018-09-10 19:59:40 +03:00
Nikolay Krasko
07dc7e3b19 Forgotten utility for getting Kotlin code style defaults 2018-09-10 19:59:38 +03:00
Vyacheslav Gerasimov
c579b5615c Fix for 1.2.70: Handle implicit receivers more accurately in if-then to safe access 2018-09-10 15:10:00 +03:00
Nikolay Krasko
e403f8f930 Import Kotlin code style from Maven properties (KT-23400)
(cherry picked from commit f679b3f6dd)
2018-09-10 14:11:56 +03:00
Nikolay Krasko
1a5f4d884e Refactoring: extract method for applying codestyle from string (KT-23400)
(cherry picked from commit 1820028086)
2018-09-10 14:11:56 +03:00
Nikolay Krasko
51c0e3272d Import code style if gradle.properties has kotlin.code.style option (KT-23400)
(cherry picked from commit 921af44cb9)
2018-09-10 14:11:56 +03:00
Nikolay Krasko
c3c7115450 Implement transition project code style to predefined code style (KT-23400)
(cherry picked from commit f94ff3dc26)
2018-09-10 14:11:56 +03:00
Mikhail Glukhikh
fa6b0c878b Handle implicit receivers more accurately in if-then to safe access
#KT-26599 Fixed
2018-09-10 14:00:25 +03:00
Mikhael Bogdanov
b4e059f2e6 Properly cast right-hand side value for inline property setter
#KT-22649 Fixed

(cherry picked from commit da93ff1a30)
2018-09-10 10:11:46 +02:00
Sergey Igushkin
c102f7ca77 Move KotlinSourceSet back to org.jetbrains.kotlin.gradle.plugin.*
After all MPP related changes, the `KotlinSourceSet` interface turns out
compatible with the old `KotlinSourceSet`, and, since there are external
usages of `KotlinSourceSet`, it is reasonable to expose the new
interface under the old FQ-name to fix those external usages.

Issue #KT-26498 Fixed

(cherry picked from commit 96901c5487)
2018-09-10 01:20:48 +03:00
Sergey Igushkin
35fd69c395 Bring back two methods used by old MPP K/N plugin
* First, it overrides `addCommonSourceSetToPlatformSourceSet` with an
  old signature that was drop during migration to 'KotlinSourceSet's

* Second, it uses an extension SourceSet.kotlin that got dropped during
  the aforementioned migration

Now, for the old MPP K/N plugin, `addCommonSourceSetToPlatformSourceSet`
is called twice, one time with the new signature and another with the
old one, which it overrides.

(cherry picked from commit 90ec151258)
2018-09-10 01:08:50 +03:00
Nicolay Mitropolsky
3e810b756b 183: fixed nullability for various listeners update in 183 2018-09-08 11:52:34 +03:00
Nicolay Mitropolsky
9d155b0eab 183: gson for 183 updated to 2.8.5
(cherry picked from commit 7068992937)
2018-09-08 11:52:34 +03:00
Vyacheslav Gerasimov
955f7bb287 Set until-build for Idea 182 plugin to 182.* 2018-09-08 11:52:33 +03:00
Nicolay Mitropolsky
07bf6a6b99 183: IDEA 183 version set to 183.2153.8
(cherry picked from commit e80a01a3fd)
2018-09-08 11:52:33 +03:00
Yan Zhulanow
d5385a73a7 Maven: Do not consider 'kapt' and 'test-kapt' executions as non-JVM (KT-26211)
(cherry picked from commit ca4b99b1a0)
2018-09-08 01:02:24 +03:00
Anton Bannykh
1f8eb7211b JS: fix module aliasing for inline imports (KT-26466 fixed)
Consider an import from an inline function invocation. If it is
being called from another inline function, it should be defined
in a special way (e.g. `$$importsForInline$$.foo`) so that
the compiler knows where to load transitive dependencies from.
What's more, the declaration itself should be inside the inline
function wrapper.

Otherwise it should be defined in a regular way (e.g.
`$module$bar.foo` among other top-level imports).

By default the imports are loaded in the first form, and
transformed into the second one when needed. To check
whether this transformation the following predicate is
used: `inlineFunctionDepth == 0`.

At the moment the mentioned variable is increased upon
visiting an inline function declaration (`defineInlineFunction`),
and upon visiting an unknown (not visited before) inline function invocation.

It seems that instead the variable should be increased when processing
an existing inline function wrapper. At that point a new place to
put import definitions (`statementContextForInline`) is set.

Due to way JS code is generated (lambda's come before their call sites)
this issue seems to have been masked. Primary class constructors are a special
case - they come before any other declaration within. Hence a lambda
invocation inside a constructor leads to incorrect import definition.

(cherry picked from commit 779d9aafe7)
2018-09-07 12:12:14 +03:00
Mikhail Glukhikh
0600cb6174 Do not report OPTIONAL_DECLARATION_USAGE_... in IDE for platform modules
#KT-26585 Fixed
Also fixes MultiPlatformHighlightingTestGenerated.testMultifileFacade

(cherry picked from commit 5f2c7d3c84)
2018-09-06 11:36:10 +03:00
Vyacheslav Gerasimov
5fb09f98d2 Add missing tickets to changelog for 1.2.70 RC 2018-09-05 16:30:49 +03:00
Vyacheslav Gerasimov
64c2bd427f Update changelog for 1.2.70 RC 2018-09-05 15:40:50 +03:00
Natalia Selezneva
5f1e5d7bb2 Add dependency on script-util for idea-core module 2018-09-04 23:37:28 +03:00
Natalia Selezneva
21470e59f5 Use correct classpath for Ide Scripting Console files during highlighting
KT-25606

(cherry picked from commit 3979ad7a1d)
2018-09-04 15:27:55 +03:00
Ilya Chernikov
46b78b1df4 Extract urls from any classloader that has getUrls(): List<URL> method
via reflection, e.g. IDEA platform UrlClassloader. This fix allow
kotlin JSR223 host for IDEA to extract classpath from the environment
properly (with appropriate fix on IDEA side as well).
2018-09-04 14:43:49 +03:00
Sergey Rostov
af28757eda IC: Fix CacheVersionsManager IC flag set.
Previously flag was set before the IncrementalCompilation.isEnabledForJvm() system property was set.
This causes that the cache versions was not saved.

(cherry picked from commit cdcc588a55)
2018-08-31 17:20:29 +03:00
Denis Zharkov
0feab3e0d9 Add some new String methods in JDK 11 to built-ins mapping blacklist
These three methods are conflicting with existing extensions,
thus the behavior might be changed when switching to JDK 11

Probably, it's worth revisiting our strategy here,
e.g. by blacklisting all new methods in

 #KT-24974 Fixed
2018-08-30 22:09:50 +03:00
Sergey Rostov
54c15bb330 JPS: Refactor cache compatibility checking and build targets loading/dependency analysis.
CacheVersion class refactoring:

Responsibilities of class CacheVersion are splitted into:
	- interface CacheAttributesManager<Attrs>, that should:
	    - load actual cache attribute values from FS
	    - provide expected attribute values (that is required for current build)
	    - checks when the existed cache (with actual attributes) values is suitable for current build (expected atribute values)
	    - write new values to FS for next build
	- CacheAttributesDiff is created by calling CacheAttributesManager.loadDiff extension method. This is just pair of actual and expected cache attributes values, with reference to manager. Result of loadDiff can be saved.

CacheAttributesDiff are designed to be used as facade of attributes operations: CacheAttributesDiff.status are calculated based on actual and expected attribute values. Based on that status system may perform required actions (i.e. rebuild something, clearing caches, etc...).

Methods of CacheAttributesManager other then loadDiff should be used only through CacheAttributesDiff.
Build system should work in this order:
    - get implementation of CacheAttributesManager for particular compiler and cache
    - call loadDiff __once__ and save it result
    - perform actions based on `diff.status`
    - save new cache attribute values by calling `diff.saveExpectedIfNeeded()`

There are 2 implementation of CacheAttributesManager:
    - CacheVersionManager that simple checks cache version number.
    - CompositeLookupsCacheAttributesManager - manager for global lookups cache that may contain lookups for several compilers (jvm, js).

Gradle:

Usages of CacheVersion in gradle are kept as is. For compatibility this methods are added: CacheAttributesManager.saveIfNeeded, CacheAttributesManager.clean. This methods should not be used in new code.

JPS:

All JPS logic that was responsible for cache version checking completely rewritten.

To write proper implementation for version checking, this things also changed:
	- KotlinCompileContext introduced. This context lives between first calling build of kotlin target until build finish. As of now all kotlin targets are loaded on KotlinCompileContext initialization. This is required to collect kotlin target types used in this build (jvm/js). Also all build-wide logic are moved from KotlinBuilder to KotlinCompileContext. Chunk dependency calculation also moved to build start which improves performance for big projects #KT-26113
	- Kotlin bindings to JPS build targets also stored in KotlinCompileContext, and binding is fixed. Previously it is stored in local Context and reacreated for each chunk, now they stored in KotlinCompileContext which is binded by GlobalContextKey with this exception: source roots are calculated for each round, since temporary source roots with groovy stubs are created at build time and visible only in local compile context.
	- KotlinChunk introduced. All chunk-wide logic are moved from KotlinModuleBuildTarget (i.e compiler, language, cache version checking and dependent cache loading)
	- Fix legacy MPP common dependent modules

Cache version checking logic now works as following:
- At first chunk building all targets are loaded and used platforms are collected. Lookups cache manger is created based on this set. Actual cache attributes are loaded from FS. Based on CacheAttributesDiff.status this actions are performed: if cache is invalid all kotlin will be rebuilt. If cache is not required anymore it will be cleaned.
- Before build of each chunk local chunk cache attributes will be checked. If cache is invalid, chunk will be rebuilt. If cache is not required anymore it will be cleaned.

#KT-26113 Fixed
#KT-26072 Fixed
2018-08-30 16:15:51 +03:00
Yan Zhulanow
dd6bebe340 Gradle importer: Join compiler plugin options as before the new MPP refactoring (KT-26424) 2018-08-29 19:02:32 +05:00
Mikhail Zarechenskiy
344fdfe648 [NI] Fix overload resolution ambiguity for incorrect provideDelegate
#KT-25810
2018-08-29 12:02:09 +03:00
Ilya Gorbunov
1986603404 Support multiple expectedBy dependencies when building -Xcommon-sources list
`addCommonSourceSetToPlatformSourceSet` may be called multiple times during
a platform project configuration.

(cherry picked from commit 36936d252c)
2018-08-28 19:21:09 +03:00
Ilya Gorbunov
6043c35ac1 Do not use JVM-specific annotations in pure-JS generated sources 2018-08-28 19:21:06 +03:00
Ilya Gorbunov
64db423b8b Provide JvmSynthetic annotation in stdlib-common as optional 2018-08-27 15:24:55 +03:00
Ilya Gorbunov
7dc19af994 Introduce platform specific annotations as optional in common stdlib 2018-08-27 15:24:55 +03:00
Ilya Gorbunov
8165e4546f Move OptionalExpectation and related annotations to another source root 2018-08-27 15:24:55 +03:00
Sergey Igushkin
3cc01632a0 Always apply the java-base plugin from the new MPP plugin
This fixes misconfigured test tasks and the `Usage` attribute
compatibility rule missing that is added by `java-base`.

Issue #KT-26301 Fixed

(cherry picked from commit ef85fe7ab2)
2018-08-27 14:15:35 +03:00
Sergey Igushkin
e4916a8f80 Add missing Gradle task input path sensitivity
Fix after the commit 0f003802f

(cherry picked from commit 2040cdde4b)
2018-08-27 14:15:35 +03:00
Sergey Igushkin
2e9182cefc Fix the SourceSet.projectDefault() extension adding sources to resources
The `include` calls were effectively made on the `resources`
`SourceDirectorySet`, which meant including '**' from 'src' as well.

Since the 'SourceDirectorySet' API is quite limited and does not support
specifying includes/excludes separately, configure the
`ProcessResources` task instead.

(cherry picked from commit a71c66a82f)
2018-08-27 14:15:35 +03:00
Sergey Igushkin
098cfe7967 Fix Kotlin source directories not added into the Java source set srcDirs
Before the new MPP, Kotlin source directories were added to the Java
source set's `allJava` and `allSource` by all of the Kotlin plugins,
including common and JS ones. As it turned out, this was required by the
IntelliJ Gradle import.

* Make all `KotlinSourceSetProcessor`s (not just JVM) check whether a
  compilation has a Java source set and add the Kotlin source
  directories to `allSource` and `allJava`

* Also disable the unclear resource `exclude` for the Java source set
  that filters Kotlin source directories out of the resources

Issue #KT-26020 Fixed
Issue #KT-26267 Fixed

(cherry picked from commit 674e464230)
2018-08-27 14:15:35 +03:00
Sergey Igushkin
5f6b997894 Revert "Fix source set resources filtering broken by refactoring"
This reverts commit 6af6834

(cherry picked from commit b125f1e23e)
2018-08-27 14:15:34 +03:00
Sergey Igushkin
d53a28de26 Enable metadata publishing for new MPP and consumption from source sets
* Add configurations for consuming source sets metadata (extending the
  source set's dependency configurations). These configurations will be
  used by the IDE to pick up the dependencies metadata.

* Remove the universal preset from the default presets, create a
  metadata target by default for compiling and publishing the metadata
  of `commonMain` (in the future, we will publish and consume the
  metadata of the other source sets as well).

* Make the classpath configurations of common modules consume the
  metadata and thus ensure compatibility of 1.2.x MPP with the new MPP
  model.

(cherry picked from commit 1a3dd67176)
2018-08-27 14:15:34 +03:00
Alexander Podkhalyuzin
4949ff3e63 Added Kotlin svg icon to the distribution
#KT-26393 Fixed

(cherry picked from commit 54922362e3)
2018-08-25 17:59:22 +03:00
Alexander Podkhalyuzin
e062be9fb3 Added resolve scope enlarger to module infos in Kotlin
From now it's possible to enlarge resolve scope for analysis in IDE,
the only difference is that it's based on module file.

#KT-26313 Fixed

(cherry picked from commit c0e92ba350)
2018-08-25 12:21:04 +03:00
Juan Chen
cfcecbd389 Add sync after Kotlin configured in Android Studio projects.
(cherry picked from commit 1a562d477a)
2018-08-24 22:26:49 +03:00
Yan Zhulanow
926e6ba1b5 Parcelize, Minor: Fix tests (writeToParcel/describeContents are not final anymore)
(cherry picked from commit d0fd74982d)
2018-08-24 04:30:34 +05:00
Yan Zhulanow
1a6c860595 Kapt: Ignore annotation-processing-gradle compiler plugin we got from Gradle (KT-24714)
Cause it's built for the shaded Kotlin compiler and won't work with JPS.

(cherry picked from commit d08a32c7cb)
2018-08-24 04:30:13 +05:00
Yan Zhulanow
58f852ff3f Parcelize: Fix infinite recursive loop for zero-parameter Parcelable classes (KT-25839)
(cherry picked from commit 8c05769745)
2018-08-24 04:30:09 +05:00
Anton Bannykh
a43ea8f7ca JS: don't throw AssertionError from RedundantCallElimination
Also mark JS `call` function to avoid removing a custom `call`

(cherry picked from commit 4e496cf2b2)
2018-08-23 14:45:43 +03:00
Nicolay Mitropolsky
9a56ba49fc CreateCallableFromUsageFix always calls openInEditor to force proper editor and focus
(cherry picked from commit 9eb612a605)
2018-08-23 09:27:53 +03:00
Nicolay Mitropolsky
2a9ceef833 KotlinElementActionsFactory uses createAddMethodActions to create properties
(cherry picked from commit 18db40474a)
2018-08-23 09:21:56 +03:00
Alexey Tsvetkov
a443476918 Recompile all subclasses of changed classes
Previously inter-project IC recompiled only direct subclasses
of changed classes

    #KT-25455 fixed
2018-08-22 00:18:01 +03:00
Alexey Tsvetkov
e5a0d4e761 Use file trees in InspectClassesForMultiModuleIC
#KT-26208
2018-08-22 00:18:01 +03:00
Alexey Tsvetkov
e71c868620 Minor: remove redundant default argument 'weakTesting = false' 2018-08-22 00:18:01 +03:00
Alexey Tsvetkov
a69ca81c26 Minor: remove GradleICReporter 2018-08-22 00:18:00 +03:00
Alexey Tsvetkov
44e17f74a3 Implement inter-project JS IC with Gradle
#KT-25025 fixed
2018-08-22 00:18:00 +03:00
Alexey Tsvetkov
b024c997ca Minor: move tests for incremental compilation of Kotlin when Java changes 2018-08-22 00:18:00 +03:00
Alexey Tsvetkov
9f43922eb2 Refactoring: extract function for getting classpath changes 2018-08-22 00:17:59 +03:00
Alexey Tsvetkov
3a76611b95 Refactoring: introduce DirtyFilesContainer for better code reuse in IC 2018-08-22 00:17:59 +03:00
Alexey Tsvetkov
aaad2d589c Avoid rebuild when '--verbose' is used in Gradle
#KT-23472 fixed
2018-08-22 00:17:59 +03:00
Alexey Tsvetkov
b98aeeb77c Use same system property to avoid deleting module file in JPS and Gradle 2018-08-22 00:17:59 +03:00
Anton Bannykh
edeba28e84 JS: fix complex nested cross-module inlining (KT-26117 fixed)
(cherry picked from commit 04b04f919d)
2018-08-21 20:42:48 +03:00
Alexander Udalov
b0757e3080 Use kotlinx-metadata-jvm of version 0.0.4 in kotlin-reflect build script
To prevent various problems with non-shaded artifact (shading was added
in 0.0.3)

(cherry picked from commit e41e28271b)
2018-08-21 17:13:13 +02:00
Alexander Udalov
3ccdb9f2a9 Report error on incompatible .kotlin_module files in classpath
Also remove obsolete test wrongAbiVersionNoErrors

 #KT-25973 Fixed
 #KT-26266 Open

(cherry picked from commit 852760b3b0)
2018-08-21 17:13:00 +02:00
Alexander Udalov
e0126f9036 Report error instead of throwing exception in JvmPackagePartProvider
(cherry picked from commit 4f11812668)
2018-08-21 17:12:57 +02:00
Vyacheslav Gerasimov
d0ea36b2ab as33: Restore gradle-java.xml 2018-08-21 17:48:19 +03:00
Vyacheslav Gerasimov
fc5a56983d as33: Add missing GooglePluginUpdateVerifier 2018-08-21 16:38:06 +03:00
Alexander Udalov
8c7db2a8d0 Fix compilation in KotlinTestUtils for IDEA 173
(cherry picked from commit 3442c7385f)
2018-08-21 14:05:51 +02:00
Alexander Udalov
3857775684 Fix compilation in KotlinTestUtils for AS 3.1 & 3.2
(cherry picked from commit 97c0f1712a)
2018-08-21 14:05:49 +02:00
Alexander Udalov
cca12ac647 Minor, use resolveSibling in getAbsolutePaths
(cherry picked from commit f069686a14)
2018-08-21 13:04:03 +02:00
Alexander Udalov
de1aada638 Disallow using optional annotations outside common module sources
#KT-25196 Fixed

(cherry picked from commit e56374908e)
2018-08-21 13:04:01 +02:00
Alexander Udalov
7b87d2bfc3 Introduce -Xcommon-sources and pass it correctly from build tool plugins
#KT-25196 In Progress

(cherry picked from commit 0f003802fe)
2018-08-21 13:03:55 +02:00
Svyatoslav Kuzmich
e238423425 [JS BE] KT-22053 Fix constructor delegation of immediate subtype of Error 2018-08-20 13:43:02 +03:00
Nikolay Krasko
f730f14d0d Workaround for IndexNotReadyException from icon provider (EA-118965)
Provider is DumbAware and isn't expected to access indexes.

(cherry picked from commit 8f566132e4)
2018-08-19 17:49:32 +03:00
Anton Bannykh
cf53922f1f JS: create appropriate nameBinding's upon inlining
Otherwise JsName's don't get linked properly upon deserialization.
As a result a function/constructor doesn't get renamed at
call site during the name conflict resolution phase.

(cherry picked from commit 8e5b2fe657)
2018-08-17 15:29:17 +03:00
Alexey Tsvetkov
b81c590e12 Add test for KT-26064
(cherry picked from commit 3b4a49eebf)
2018-08-17 15:28:24 +03:00
Vyacheslav Gerasimov
ed0a79e556 Add changelog for 1.2.70 EAP 1 2018-08-17 14:43:26 +03:00
363 changed files with 12289 additions and 8309 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -64,6 +64,9 @@ abstract class BuildMetaInfoFactory<T : BuildMetaInfo>(private val metaInfoClass
)
}
fun serializeToString(args: CommonCompilerArguments): String =
serializeToString(create(args))
fun serializeToString(info: T): String =
serializeToPlainText(info, metaInfoClass)

View File

@@ -1,111 +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.incremental
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmBytecodeBinaryVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import java.io.File
import java.io.IOException
private val NORMAL_VERSION = 9
private val DATA_CONTAINER_VERSION = 3
private val NORMAL_VERSION_FILE_NAME = "format-version.txt"
private val DATA_CONTAINER_VERSION_FILE_NAME = "data-container-format-version.txt"
class CacheVersion(
private val ownVersion: Int,
private val versionFile: File,
private val whenVersionChanged: CacheVersion.Action,
private val whenTurnedOn: CacheVersion.Action,
private val whenTurnedOff: CacheVersion.Action,
private val isEnabled: Boolean
) {
private val actualVersion: Int?
get() = try {
versionFile.readText().toInt()
}
catch (e: NumberFormatException) {
null
}
catch (e: IOException) {
null
}
private val expectedVersion: Int
get() {
val metadata = JvmMetadataVersion.INSTANCE
val bytecode = JvmBytecodeBinaryVersion.INSTANCE
return ownVersion * 1000000 +
bytecode.major * 10000 + bytecode.minor * 100 +
metadata.major * 1000 + metadata.minor
}
fun checkVersion(): Action =
when (versionFile.exists() to isEnabled) {
true to true -> if (actualVersion != expectedVersion) whenVersionChanged else Action.DO_NOTHING
false to true -> whenTurnedOn
true to false -> whenTurnedOff
else -> Action.DO_NOTHING
}
fun saveIfNeeded() {
if (!isEnabled) return
if (!versionFile.parentFile.exists()) {
versionFile.parentFile.mkdirs()
}
versionFile.writeText(expectedVersion.toString())
}
fun clean() {
versionFile.delete()
}
@get:TestOnly
val formatVersionFile: File
get() = versionFile
// Order of entries is important, because actions are sorted in KotlinBuilder::checkVersions
enum class Action {
REBUILD_ALL_KOTLIN,
REBUILD_CHUNK,
CLEAN_NORMAL_CACHES,
CLEAN_DATA_CONTAINER,
DO_NOTHING
}
}
fun normalCacheVersion(dataRoot: File, enabled: Boolean): CacheVersion =
CacheVersion(ownVersion = NORMAL_VERSION,
versionFile = File(dataRoot, NORMAL_VERSION_FILE_NAME),
whenVersionChanged = CacheVersion.Action.REBUILD_CHUNK,
whenTurnedOn = CacheVersion.Action.REBUILD_CHUNK,
whenTurnedOff = CacheVersion.Action.CLEAN_NORMAL_CACHES,
isEnabled = enabled)
fun dataContainerCacheVersion(dataRoot: File, enabled: Boolean): CacheVersion =
CacheVersion(ownVersion = DATA_CONTAINER_VERSION,
versionFile = File(dataRoot, DATA_CONTAINER_VERSION_FILE_NAME),
whenVersionChanged = CacheVersion.Action.REBUILD_ALL_KOTLIN,
whenTurnedOn = CacheVersion.Action.REBUILD_ALL_KOTLIN,
whenTurnedOff = CacheVersion.Action.CLEAN_DATA_CONTAINER,
isEnabled = enabled)

View File

@@ -25,6 +25,8 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.build.GeneratedJvmClass
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.incremental.storage.*
import org.jetbrains.kotlin.incremental.storage.version.clean
import org.jetbrains.kotlin.incremental.storage.version.localCacheVersionManager
import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
@@ -43,8 +45,8 @@ import java.util.*
val KOTLIN_CACHE_DIRECTORY_NAME = "kotlin"
open class IncrementalJvmCache(
private val targetDataRoot: File,
targetOutputDir: File?
private val targetDataRoot: File,
targetOutputDir: File?
) : AbstractIncrementalCache<JvmClassName>(File(targetDataRoot, KOTLIN_CACHE_DIRECTORY_NAME)), IncrementalCache {
companion object {
private val PROTO_MAP = "proto"
@@ -81,16 +83,16 @@ open class IncrementalJvmCache(
// used in gradle
@Suppress("unused")
fun classesBySources(sources: Iterable<File>): Iterable<JvmClassName> =
sources.flatMap { sourceToClassesMap[it] }
sources.flatMap { sourceToClassesMap[it] }
fun sourceInCache(file: File): Boolean =
sourceToClassesMap.contains(file)
fun sourcesByInternalName(internalName: String): Collection<File> =
internalNameToSource[internalName]
internalNameToSource[internalName]
fun isMultifileFacade(className: JvmClassName): Boolean =
className in multifileFacadeToParts
className in multifileFacadeToParts
override fun getClassFilePath(internalClassName: String): String {
return toSystemIndependentName(File(outputDir, "$internalClassName.class").canonicalPath)
@@ -129,7 +131,7 @@ open class IncrementalJvmCache(
}
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
val partNames = kotlinClass.classHeader.data?.toList()
?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}")
?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}")
multifileFacadeToParts[className] = partNames
// When a class is replaced with a facade with the same name,
// the class' proto wouldn't ever be deleted,
@@ -177,15 +179,15 @@ open class IncrementalJvmCache(
}
fun getObsoleteJavaClasses(): Collection<ClassId> =
dirtyOutputClassesMap.getDirtyOutputClasses()
.mapNotNull {
javaSourcesProtoMap[it]?.classId
}
dirtyOutputClassesMap.getDirtyOutputClasses()
.mapNotNull {
javaSourcesProtoMap[it]?.classId
}
fun isJavaClassToTrack(classId: ClassId): Boolean {
val jvmClassName = JvmClassName.byClassId(classId)
return dirtyOutputClassesMap.isDirty(jvmClassName) ||
jvmClassName !in javaSourcesProtoMap
jvmClassName !in javaSourcesProtoMap
}
fun isJavaClassAlreadyInCache(classId: ClassId): Boolean {
@@ -210,8 +212,7 @@ open class IncrementalJvmCache(
if (notRemovedParts.isEmpty()) {
multifileFacadeToParts.remove(facade)
}
else {
} else {
multifileFacadeToParts[facade] = notRemovedParts
}
}
@@ -265,7 +266,7 @@ open class IncrementalJvmCache(
override fun clean() {
super.clean()
normalCacheVersion(targetDataRoot, IncrementalCompilation.isEnabledForJvm()).clean()
localCacheVersionManager(targetDataRoot, IncrementalCompilation.isEnabledForJvm()).clean()
}
private inner class ProtoMap(storageFile: File) : BasicStringMap<ProtoMapValue>(storageFile, ProtoMapValueExternalizer) {
@@ -290,9 +291,11 @@ open class IncrementalJvmCache(
val key = kotlinClass.className.internalName
val oldData = storage[key]
val newData = ProtoMapValue(header.kind != KotlinClassHeader.Kind.CLASS,
BitEncoding.decodeBytes(header.data!!),
header.strings!!)
val newData = ProtoMapValue(
header.kind != KotlinClassHeader.Kind.CLASS,
BitEncoding.decodeBytes(header.data!!),
header.strings!!
)
storage[key] = newData
val packageFqName = kotlinClass.className.packageFqName
@@ -300,10 +303,10 @@ open class IncrementalJvmCache(
}
operator fun contains(className: JvmClassName): Boolean =
className.internalName in storage
className.internalName in storage
operator fun get(className: JvmClassName): ProtoMapValue? =
storage[className.internalName]
storage[className.internalName]
fun remove(className: JvmClassName, changesCollector: ChangesCollector) {
val key = className.internalName
@@ -319,15 +322,16 @@ open class IncrementalJvmCache(
}
}
private inner class JavaSourcesProtoMap(storageFile: File) : BasicStringMap<SerializedJavaClass>(storageFile, JavaClassProtoMapValueExternalizer) {
private inner class JavaSourcesProtoMap(storageFile: File) :
BasicStringMap<SerializedJavaClass>(storageFile, JavaClassProtoMapValueExternalizer) {
fun process(jvmClassName: JvmClassName, newData: SerializedJavaClass, changesCollector: ChangesCollector) {
val key = jvmClassName.internalName
val oldData = storage[key]
storage[key] = newData
changesCollector.collectProtoChanges(
oldData?.toProtoData(), newData.toProtoData(),
collectAllMembersForNewClass = true
oldData?.toProtoData(), newData.toProtoData(),
collectAllMembersForNewClass = true
)
}
@@ -340,13 +344,13 @@ open class IncrementalJvmCache(
}
operator fun get(className: JvmClassName): SerializedJavaClass? =
storage[className.internalName]
storage[className.internalName]
operator fun contains(className: JvmClassName): Boolean =
className.internalName in storage
className.internalName in storage
override fun dumpValue(value: SerializedJavaClass): String =
java.lang.Long.toHexString(value.proto.toByteArray().md5())
java.lang.Long.toHexString(value.proto.toByteArray().md5())
}
// todo: reuse code with InlineFunctionsMap?
@@ -368,7 +372,7 @@ open class IncrementalJvmCache(
}
operator fun contains(className: JvmClassName): Boolean =
className.internalName in storage
className.internalName in storage
fun process(kotlinClass: LocalFileKotlinClass, changesCollector: ChangesCollector) {
val key = kotlinClass.className.internalName
@@ -377,8 +381,7 @@ open class IncrementalJvmCache(
val newMap = getConstantsMap(kotlinClass.fileContents)
if (newMap.isNotEmpty()) {
storage[key] = newMap
}
else {
} else {
storage.remove(key)
}
@@ -392,7 +395,7 @@ open class IncrementalJvmCache(
}
override fun dumpValue(value: Map<String, Any>): String =
value.dumpMap(Any::toString)
value.dumpMap(Any::toString)
}
private inner class PackagePartMap(storageFile: File) : BasicStringMap<Boolean>(storageFile, BooleanDataDescriptor.INSTANCE) {
@@ -405,21 +408,22 @@ open class IncrementalJvmCache(
}
fun isPackagePart(className: JvmClassName): Boolean =
className.internalName in storage
className.internalName in storage
override fun dumpValue(value: Boolean) = ""
}
private inner class MultifileClassFacadeMap(storageFile: File) : BasicStringMap<Collection<String>>(storageFile, StringCollectionExternalizer) {
private inner class MultifileClassFacadeMap(storageFile: File) :
BasicStringMap<Collection<String>>(storageFile, StringCollectionExternalizer) {
operator fun set(className: JvmClassName, partNames: Collection<String>) {
storage[className.internalName] = partNames
}
operator fun get(className: JvmClassName): Collection<String>? =
storage[className.internalName]
storage[className.internalName]
operator fun contains(className: JvmClassName): Boolean =
className.internalName in storage
className.internalName in storage
fun remove(className: JvmClassName) {
storage.remove(className.internalName)
@@ -428,13 +432,14 @@ open class IncrementalJvmCache(
override fun dumpValue(value: Collection<String>): String = value.dumpCollection()
}
private inner class MultifileClassPartMap(storageFile: File) : BasicStringMap<String>(storageFile, EnumeratorStringDescriptor.INSTANCE) {
private inner class MultifileClassPartMap(storageFile: File) :
BasicStringMap<String>(storageFile, EnumeratorStringDescriptor.INSTANCE) {
fun set(partName: String, facadeName: String) {
storage[partName] = facadeName
}
fun get(partName: JvmClassName): String? =
storage[partName.internalName]
storage[partName.internalName]
fun remove(className: JvmClassName) {
storage.remove(className.internalName)
@@ -443,20 +448,21 @@ open class IncrementalJvmCache(
override fun dumpValue(value: String): String = value
}
inner class InternalNameToSourcesMap(storageFile: File) : BasicStringMap<Collection<String>>(storageFile, EnumeratorStringDescriptor(), PathCollectionExternalizer) {
inner class InternalNameToSourcesMap(storageFile: File) :
BasicStringMap<Collection<String>>(storageFile, EnumeratorStringDescriptor(), PathCollectionExternalizer) {
operator fun set(internalName: String, sourceFiles: Iterable<File>) {
storage[internalName] = sourceFiles.map { it.canonicalPath }
}
operator fun get(internalName: String): Collection<File> =
(storage[internalName] ?: emptyList()).map(::File)
(storage[internalName] ?: emptyList()).map(::File)
fun remove(internalName: String) {
storage.remove(internalName)
}
override fun dumpValue(value: Collection<String>): String =
value.dumpCollection()
value.dumpCollection()
}
private fun addToClassStorage(kotlinClass: LocalFileKotlinClass, srcFile: File) {
@@ -464,7 +470,8 @@ open class IncrementalJvmCache(
addToClassStorage(proto, nameResolver, srcFile)
}
private inner class InlineFunctionsMap(storageFile: File) : BasicStringMap<Map<String, Long>>(storageFile, StringToLongMapExternalizer) {
private inner class InlineFunctionsMap(storageFile: File) :
BasicStringMap<Map<String, Long>>(storageFile, StringToLongMapExternalizer) {
private fun getInlineFunctionsMap(header: KotlinClassHeader, bytes: ByteArray): Map<String, Long> {
val inlineFunctions = inlineFunctionsJvmNames(header)
if (inlineFunctions.isEmpty()) return emptyMap()
@@ -472,7 +479,13 @@ open class IncrementalJvmCache(
val result = HashMap<String, Long>()
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.ASM5) {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
override fun visitMethod(
access: Int,
name: String,
desc: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
val dummyClassWriter = ClassWriter(Opcodes.ASM5)
return object : MethodVisitor(Opcodes.ASM5, dummyClassWriter.visitMethod(0, name, desc, null, exceptions)) {
@@ -499,30 +512,35 @@ open class IncrementalJvmCache(
val newMap = getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
if (newMap.isNotEmpty()) {
storage[key] = newMap
}
else {
} else {
storage.remove(key)
}
for (fn in oldMap.keys + newMap.keys) {
changesCollector.collectMemberIfValueWasChanged(kotlinClass.scopeFqName(), functionNameBySignature(fn), oldMap[fn], newMap[fn])
changesCollector.collectMemberIfValueWasChanged(
kotlinClass.scopeFqName(),
functionNameBySignature(fn),
oldMap[fn],
newMap[fn]
)
}
}
// TODO get name in better way instead of using substringBefore
private fun functionNameBySignature(signature: String): String =
signature.substringBefore("(")
signature.substringBefore("(")
fun remove(className: JvmClassName) {
storage.remove(className.internalName)
}
override fun dumpValue(value: Map<String, Long>): String =
value.dumpMap { java.lang.Long.toHexString(it) }
value.dumpMap { java.lang.Long.toHexString(it) }
}
}
private object PathCollectionExternalizer : CollectionExternalizer<String>(PathStringDescriptor, { THashSet(FileUtil.PATH_HASHING_STRATEGY) })
private object PathCollectionExternalizer :
CollectionExternalizer<String>(PathStringDescriptor, { THashSet(FileUtil.PATH_HASHING_STRATEGY) })
sealed class ChangeInfo(val fqName: FqName) {
open class MembersChanged(fqName: FqName, val names: Collection<String>) : ChangeInfo(fqName) {
@@ -542,10 +560,10 @@ sealed class ChangeInfo(val fqName: FqName) {
}
private fun LocalFileKotlinClass.scopeFqName() =
when (classHeader.kind) {
KotlinClassHeader.Kind.CLASS -> className.fqNameForClassNameWithoutDollars
else -> className.packageFqName
}
when (classHeader.kind) {
KotlinClassHeader.Kind.CLASS -> className.fqNameForClassNameWithoutDollars
else -> className.packageFqName
}
fun ByteArray.md5(): Long {
val d = MessageDigest.getInstance("MD5").digest(this)!!
@@ -557,23 +575,24 @@ fun ByteArray.md5(): Long {
or ((d[5].toLong() and 0xFFL) shl 40)
or ((d[6].toLong() and 0xFFL) shl 48)
or ((d[7].toLong() and 0xFFL) shl 56)
)
)
}
@TestOnly
fun <K : Comparable<K>, V> Map<K, V>.dumpMap(dumpValue: (V)->String): String =
buildString {
append("{")
for (key in keys.sorted()) {
if (length != 1) {
append(", ")
}
val value = get(key)?.let(dumpValue) ?: "null"
append("$key -> $value")
fun <K : Comparable<K>, V> Map<K, V>.dumpMap(dumpValue: (V) -> String): String =
buildString {
append("{")
for (key in keys.sorted()) {
if (length != 1) {
append(", ")
}
append("}")
}
@TestOnly fun <T : Comparable<T>> Collection<T>.dumpCollection(): String =
"[${sorted().joinToString(", ", transform = Any::toString)}]"
val value = get(key)?.let(dumpValue) ?: "null"
append("$key -> $value")
}
append("}")
}
@TestOnly
fun <T : Comparable<T>> Collection<T>.dumpCollection(): String =
"[${sorted().joinToString(", ", transform = Any::toString)}]"

View File

@@ -34,11 +34,14 @@ import org.jetbrains.kotlin.synthetic.SAM_LOOKUP_NAME
import java.io.File
import java.util.*
const val DELETE_MODULE_FILE_PROPERTY = "kotlin.delete.module.file.after.build"
fun makeModuleFile(
name: String,
isTest: Boolean,
outputDir: File,
sourcesToCompile: Iterable<File>,
commonSources: Iterable<File>,
javaSourceRoots: Iterable<JvmSourceRoot>,
classpath: Iterable<File>,
friendDirs: Iterable<File>
@@ -53,6 +56,7 @@ fun makeModuleFile(
sourcesToCompile.map { it.absoluteFile },
javaSourceRoots,
classpath,
commonSources.map { it.absoluteFile },
null,
"java-production",
isTest,
@@ -130,6 +134,7 @@ fun ChangesCollector.getDirtyData(
if (change is ChangeInfo.SignatureChanged) {
val fqNames = if (!change.areSubclassesAffected) listOf(change.fqName) else withSubtypes(change.fqName, caches)
dirtyClassesFqNames.addAll(fqNames)
for (classFqName in fqNames) {
assert(!classFqName.isRoot) { "$classFqName is root when processing $change" }

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.incremental.storage.version
/**
* Diff between actual and expected cache attributes.
* [status] are calculated based on this diff (see [CacheStatus]).
* Based on that [status] system may perform required actions (i.e. rebuild something, clearing caches, etc...).
*
* [CacheAttributesDiff] can be used to cache current attribute values and as facade for version operations.
*/
data class CacheAttributesDiff<Attrs: Any>(
val manager: CacheAttributesManager<Attrs>,
val actual: Attrs?,
val expected: Attrs?
) {
val status: CacheStatus
get() =
if (expected != null) {
if (actual != null && manager.isCompatible(actual, expected)) CacheStatus.VALID
else CacheStatus.INVALID
} else {
if (actual != null) CacheStatus.SHOULD_BE_CLEARED
else CacheStatus.CLEARED
}
fun saveExpectedIfNeeded() {
if (expected != actual) manager.writeActualVersion(expected)
}
override fun toString(): String {
return "$status: actual=$actual -> expected=$expected"
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.incremental.storage.version
/**
* Manages cache attributes values.
*
* Attribute values can be loaded by calling [loadActual].
* Based on loaded actual and fixed [expected] values [CacheAttributesDiff] can be constructed which can calculate [CacheStatus].
* Build system may perform required actions based on that (i.e. rebuild something, clearing caches, etc...).
*
* [CacheAttributesDiff] can be used to cache current attribute values and then can be used as facade for cache version operations.
*/
interface CacheAttributesManager<Attrs : Any> {
/**
* Cache attribute values expected by the current version of build system and compiler.
* `null` means that cache is not required (incremental compilation is disabled).
*/
val expected: Attrs?
/**
* Load actual cache attribute values.
* `null` means that cache is not yet created.
*
* This is internal operation that should be implemented by particular implementation of CacheAttributesManager.
* Consider using `loadDiff().actual` for getting actual values.
*/
fun loadActual(): Attrs?
/**
* Write [values] as cache attributes for next build execution.
*
* This is internal operation that should be implemented by particular implementation of CacheAttributesManager.
* Consider using `loadDiff().saveExpectedIfNeeded()` for saving attributes values for next build.
*/
fun writeActualVersion(values: Attrs?)
/**
* Check if cache with [actual] attributes values can be used when [expected] attributes are required.
*/
fun isCompatible(actual: Attrs, expected: Attrs): Boolean = actual == expected
}
fun <Attrs : Any> CacheAttributesManager<Attrs>.loadDiff(
actual: Attrs? = this.loadActual(),
expected: Attrs? = this.expected
) = CacheAttributesDiff(this, actual, expected)
fun <Attrs : Any> CacheAttributesManager<Attrs>.loadAndCheckStatus() =
loadDiff().status
/**
* This method is kept only for compatibility.
* Save [expected] cache attributes values if it is enabled and not equals to [actual].
*/
@Deprecated(
message = "Consider using `this.loadDiff().saveExpectedIfNeeded()` and cache `loadDiff()` result.",
replaceWith = ReplaceWith("loadDiff().saveExpectedIfNeeded()")
)
fun <Attrs : Any> CacheAttributesManager<Attrs>.saveIfNeeded(
actual: Attrs? = this.loadActual(),
expected: Attrs = this.expected
?: error("To save disabled cache status [delete] should be called (this behavior is kept for compatibility)")
) = loadDiff(actual, expected).saveExpectedIfNeeded()
/**
* This method is kept only for compatibility.
* Delete actual cache attributes values if it existed.
*/
@Deprecated(
message = "Consider using `this.loadDiff().saveExpectedIfNeeded()` and cache `loadDiff()` result.",
replaceWith = ReplaceWith("writeActualVersion(null)")
)
fun CacheAttributesManager<*>.clean() {
writeActualVersion(null)
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.incremental.storage.version
/**
* Status that is used by system to perform required actions (i.e. rebuild something, clearing caches, etc...).
*/
enum class CacheStatus {
/**
* Cache is valid and ready to use.
*/
VALID,
/**
* Cache is not exists or have outdated versions and/or other attributes.
*/
INVALID,
/**
* Cache is exists, but not required anymore.
*/
SHOULD_BE_CLEARED,
/**
* Cache is not exists and not required.
*/
CLEARED
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.incremental.storage.version
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmBytecodeBinaryVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import java.io.File
import java.io.IOException
/**
* Manages files with actual version [loadActual] and provides expected version [expected].
* Based on that actual and expected versions [CacheStatus] can be calculated.
* This can be done by constructing [CacheAttributesDiff] and calling [CacheAttributesDiff.status].
* Based on that status system may perform required actions (i.e. rebuild something, clearing caches, etc...).
*/
class CacheVersionManager(
private val versionFile: File,
expectedOwnVersion: Int?
) : CacheAttributesManager<CacheVersion> {
override val expected: CacheVersion? =
if (expectedOwnVersion == null) null
else {
val metadata = JvmMetadataVersion.INSTANCE
val bytecode = JvmBytecodeBinaryVersion.INSTANCE
CacheVersion(
expectedOwnVersion * 1000000 +
bytecode.major * 10000 + bytecode.minor * 100 +
metadata.major * 1000 + metadata.minor
)
}
override fun loadActual(): CacheVersion? =
if (!versionFile.exists()) null
else try {
CacheVersion(versionFile.readText().toInt())
} catch (e: NumberFormatException) {
null
} catch (e: IOException) {
null
}
override fun writeActualVersion(values: CacheVersion?) {
if (values == null) versionFile.delete()
else {
versionFile.parentFile.mkdirs()
versionFile.writeText(values.version.toString())
}
}
@get:TestOnly
val versionFileForTesting: File
get() = versionFile
}
data class CacheVersion(val version: Int)

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.incremental.storage.version
import java.io.File
private val NORMAL_VERSION = 9
private val NORMAL_VERSION_FILE_NAME = "format-version.txt"
fun localCacheVersionManager(dataRoot: File, isCachesEnabled: Boolean) =
CacheVersionManager(
File(dataRoot, NORMAL_VERSION_FILE_NAME),
if (isCachesEnabled) NORMAL_VERSION else null
)

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.incremental.storage.version
import java.io.File
private val DATA_CONTAINER_VERSION_FILE_NAME = "data-container-format-version.txt"
private val DATA_CONTAINER_VERSION = 3
fun lookupsCacheVersionManager(dataRoot: File, isEnabled: Boolean) =
CacheVersionManager(
File(dataRoot, DATA_CONTAINER_VERSION_FILE_NAME),
if (isEnabled) DATA_CONTAINER_VERSION else null
)
fun readLookupsCacheStatus(dataRoot: File, isEnabled: Boolean): CacheStatus =
lookupsCacheVersionManager(dataRoot, isEnabled).loadAndCheckStatus()

View File

@@ -34,16 +34,18 @@ class KotlinModuleXmlBuilder {
}
fun addModule(
moduleName: String,
outputDir: String,
sourceFiles: Iterable<File>,
javaSourceRoots: Iterable<JvmSourceRoot>,
classpathRoots: Iterable<File>,
modularJdkRoot: File?,
targetTypeId: String,
isTests: Boolean,
directoriesToFilterOut: Set<File>,
friendDirs: Iterable<File>): KotlinModuleXmlBuilder {
moduleName: String,
outputDir: String,
sourceFiles: Iterable<File>,
javaSourceRoots: Iterable<JvmSourceRoot>,
classpathRoots: Iterable<File>,
commonSourceFiles: Iterable<File>,
modularJdkRoot: File?,
targetTypeId: String,
isTests: Boolean,
directoriesToFilterOut: Set<File>,
friendDirs: Iterable<File>
): KotlinModuleXmlBuilder {
assert(!done) { "Already done" }
p.println("<!-- Module script for ${if (isTests) "tests" else "production"} -->")
@@ -62,6 +64,10 @@ class KotlinModuleXmlBuilder {
p.println("<", SOURCES, " ", PATH, "=\"", getEscapedPath(sourceFile), "\"/>")
}
for (commonSourceFile in commonSourceFiles) {
p.println("<", COMMON_SOURCES, " ", PATH, "=\"", getEscapedPath(commonSourceFile), "\"/>")
}
processJavaSourceRoots(javaSourceRoots)
processClasspath(classpathRoots, directoriesToFilterOut)

View File

@@ -4,6 +4,8 @@ import org.gradle.api.*
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.*
import org.gradle.kotlin.dsl.*
import org.gradle.language.jvm.tasks.ProcessResources
//import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
inline fun Project.sourceSets(crossinline body: SourceSetsBuilder.() -> Unit) =
@@ -25,18 +27,20 @@ fun SourceSet.none() {
resources.setSrcDirs(emptyList<String>())
}
fun SourceSet.projectDefault() {
when (name) {
"main" -> {
java.srcDirs("src")
resources.srcDir("resources").apply { include("**") }
resources.srcDir("src").apply { include("META-INF/**", "**/*.properties") }
}
"test" -> {
java.srcDirs("test", "tests")
val SourceSet.projectDefault: Project.() -> Unit
get() = {
when (this@projectDefault.name) {
"main" -> {
java.srcDirs("src")
val processResources = tasks.getByName(processResourcesTaskName) as ProcessResources
processResources.from("resources") { include("**") }
processResources.from("src") { include("META-INF/**", "**/*.properties") }
}
"test" -> {
java.srcDirs("test", "tests")
}
}
}
}
// TODO: adding KotlinSourceSet dep to the plugin breaks the build unexpectedly, resolve and uncomment
//val SourceSet.kotlin: SourceDirectorySet

View File

@@ -201,7 +201,9 @@ public class ClassFileFactory implements OutputFileCollection {
case "kotlin_module": {
ModuleMapping mapping = ModuleMappingUtilKt.loadModuleMapping(
ModuleMapping.Companion, file.asByteArray(), relativePath.getPath(),
CompilerDeserializationConfiguration.Default.INSTANCE
CompilerDeserializationConfiguration.Default.INSTANCE, version -> {
throw new IllegalStateException("Version of the generated module cannot be incompatible: " + version);
}
);
for (Map.Entry<String, PackageParts> entry : mapping.getPackageFqName2Parts().entrySet()) {
FqName packageFqName = new FqName(entry.getKey());

View File

@@ -1592,7 +1592,10 @@ public abstract class StackValue {
putReceiver(v, false);
}
callGenerator.processAndPutHiddenParameters(true);
callGenerator.putValueIfNeeded(new JvmKotlinType(rightSide.type, rightSide.kotlinType), rightSide);
callGenerator.putValueIfNeeded(new JvmKotlinType(
CollectionsKt.last(setter.getValueParameters()).getAsmType(),
CollectionsKt.last(setterDescriptor.getValueParameters()).getType()),
rightSide);
callGenerator.putHiddenParamsIntoLocals();
callGenerator.genCall(setter, resolvedCall, false, codegen);
}

View File

@@ -38,7 +38,9 @@ private fun Iterable<PackageParts>.addCompiledParts(state: GenerationState): Lis
val incrementalCache = state.incrementalCacheForThisTarget ?: return this.toList()
val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this.toList()
val mapping = ModuleMapping.loadModuleMapping(moduleMappingData, "<incremental>", state.deserializationConfiguration)
val mapping = ModuleMapping.loadModuleMapping(moduleMappingData, "<incremental>", state.deserializationConfiguration) { version ->
throw IllegalStateException("Version of the generated module cannot be incompatible: $version")
}
incrementalCache.getObsoletePackageParts().forEach { internalName ->
val qualifier = JvmClassName.byInternalName(internalName).packageFqName.asString()

View File

@@ -180,6 +180,14 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
)
var metadataVersion: String? by FreezableVar(null)
@Argument(
value = "-Xcommon-sources",
valueDescription = "<path>",
description = "Sources of the common module that need to be compiled together with this module in the multi-platform mode.\n" +
"Should be a subset of sources passed as free arguments"
)
var commonSources: Array<String>? by FreezableVar(null)
open fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
return HashMap<AnalysisFlag<*>, Any>().apply {
put(AnalysisFlag.skipMetadataVersionCheck, skipMetadataVersionCheck)

View File

@@ -21,11 +21,12 @@ import org.jetbrains.kotlin.modules.Module
import java.util.*
class ModuleBuilder(
private val name: String,
private val outputDir: String,
private val type: String
private val name: String,
private val outputDir: String,
private val type: String
) : Module {
private val sourceFiles = ArrayList<String>()
private val commonSourceFiles = ArrayList<String>()
private val classpathRoots = ArrayList<String>()
private val javaSourceRoots = ArrayList<JavaRootPath>()
private val friendDirs = ArrayList<String>()
@@ -35,6 +36,10 @@ class ModuleBuilder(
sourceFiles.add(path)
}
fun addCommonSourceFiles(path: String) {
commonSourceFiles.add(path)
}
fun addClasspathEntry(path: String) {
classpathRoots.add(path)
}
@@ -51,6 +56,7 @@ class ModuleBuilder(
override fun getFriendPaths(): List<String> = friendDirs
override fun getJavaSourceRoots(): List<JavaRootPath> = javaSourceRoots
override fun getSourceFiles(): List<String> = sourceFiles
override fun getCommonSourceFiles(): List<String> = commonSourceFiles
override fun getClasspathRoots(): List<String> = classpathRoots
override fun getModuleName(): String = name
override fun getModuleType(): String = type

View File

@@ -47,6 +47,7 @@ public class ModuleXmlParser {
public static final String OUTPUT_DIR = "outputDir";
public static final String FRIEND_DIR = "friendDir";
public static final String SOURCES = "sources";
public static final String COMMON_SOURCES = "commonSources";
public static final String JAVA_SOURCE_ROOTS = "javaSourceRoots";
public static final String JAVA_SOURCE_PACKAGE_PREFIX = "packagePrefix";
public static final String PATH = "path";
@@ -159,6 +160,10 @@ public class ModuleXmlParser {
String path = getAttribute(attributes, PATH, qName);
moduleBuilder.addSourceFiles(path);
}
else if (COMMON_SOURCES.equalsIgnoreCase(qName)) {
String path = getAttribute(attributes, PATH, qName);
moduleBuilder.addCommonSourceFiles(path);
}
else if (FRIEND_DIR.equalsIgnoreCase(qName)) {
String path = getAttribute(attributes, PATH, qName);
moduleBuilder.addFriendDir(path);

View File

@@ -10,14 +10,18 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
interface ContentRoot
data class KotlinSourceRoot(val path: String): ContentRoot
/**
* @param isCommon whether this source root contains sources of a common module in a multi-platform project
*/
data class KotlinSourceRoot(val path: String, val isCommon: Boolean): ContentRoot
fun CompilerConfiguration.addKotlinSourceRoot(source: String) {
add(CLIConfigurationKeys.CONTENT_ROOTS, KotlinSourceRoot(source))
@JvmOverloads
fun CompilerConfiguration.addKotlinSourceRoot(path: String, isCommon: Boolean = false) {
add(CLIConfigurationKeys.CONTENT_ROOTS, KotlinSourceRoot(path, isCommon))
}
fun CompilerConfiguration.addKotlinSourceRoots(sources: List<String>): Unit =
sources.forEach(this::addKotlinSourceRoot)
sources.forEach { addKotlinSourceRoot(it) }
val CompilerConfiguration.kotlinSourceRoots: List<String>
get() = get(CLIConfigurationKeys.CONTENT_ROOTS)?.filterIsInstance<KotlinSourceRoot>()?.map { it.path }.orEmpty()
val CompilerConfiguration.kotlinSourceRoots: List<KotlinSourceRoot>
get() = get(CLIConfigurationKeys.CONTENT_ROOTS)?.filterIsInstance<KotlinSourceRoot>().orEmpty()

View File

@@ -26,6 +26,7 @@ import com.intellij.util.ExceptionUtil;
import com.intellij.util.SmartList;
import kotlin.collections.ArraysKt;
import kotlin.collections.CollectionsKt;
import kotlin.collections.SetsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
@@ -175,7 +176,12 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
configuration.put(JSConfigurationKeys.LIBRARIES, configureLibraries(arguments, paths, messageCollector));
ContentRootsKt.addKotlinSourceRoots(configuration, arguments.getFreeArgs());
String[] commonSourcesArray = arguments.getCommonSources();
Set<String> commonSources = commonSourcesArray == null ? Collections.emptySet() : SetsKt.setOf(commonSourcesArray);
for (String arg : arguments.getFreeArgs()) {
ContentRootsKt.addKotlinSourceRoot(configuration, arg, commonSources.contains(arg));
}
KotlinCoreEnvironment environmentForJS =
KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JS_CONFIG_FILES);

View File

@@ -77,13 +77,14 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
val pluginLoadResult = loadPlugins(arguments, configuration)
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult
val commonSources = arguments.commonSources?.toSet().orEmpty()
if (!arguments.script && arguments.buildFile == null) {
for (arg in arguments.freeArgs) {
val file = File(arg)
if (file.extension == JavaFileType.DEFAULT_EXTENSION) {
configuration.addJavaSourceRoot(file)
} else {
configuration.addKotlinSourceRoot(arg)
configuration.addKotlinSourceRoot(arg, isCommon = arg in commonSources)
if (file.isDirectory) {
configuration.addJavaSourceRoot(file)
}

View File

@@ -19,16 +19,23 @@ package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.SmartList
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.LOGGING
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.loadModuleMapping
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
import java.io.ByteArrayOutputStream
import java.io.EOFException
import java.io.PrintStream
class JvmPackagePartProvider(
languageVersionSettings: LanguageVersionSettings,
@@ -77,7 +84,7 @@ class JvmPackagePartProvider(
}.flatten()
}
fun addRoots(roots: List<JavaRoot>) {
fun addRoots(roots: List<JavaRoot>, messageCollector: MessageCollector) {
for ((root, type) in roots) {
if (type != JavaRoot.RootType.BINARY) continue
if (root !in scope) continue
@@ -86,12 +93,28 @@ class JvmPackagePartProvider(
for (moduleFile in metaInf.children) {
if (!moduleFile.name.endsWith(ModuleMapping.MAPPING_FILE_EXT)) continue
val mapping = try {
ModuleMapping.loadModuleMapping(moduleFile.contentsToByteArray(), moduleFile.toString(), deserializationConfiguration)
try {
val mapping = ModuleMapping.loadModuleMapping(
moduleFile.contentsToByteArray(), moduleFile.toString(), deserializationConfiguration
) { incompatibleVersion ->
messageCollector.report(
ERROR,
"Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is " +
"$incompatibleVersion, expected version is ${JvmMetadataVersion.INSTANCE}.",
CompilerMessageLocation.create(moduleFile.path)
)
}
loadedModules.add(ModuleMappingInfo(root, mapping, moduleFile.nameWithoutExtension))
} catch (e: EOFException) {
throw RuntimeException("Error on reading package parts from $moduleFile in $root", e)
messageCollector.report(
ERROR, "Error occurred when reading the module: ${e.message}", CompilerMessageLocation.create(moduleFile.path)
)
messageCollector.report(
LOGGING,
String(ByteArrayOutputStream().also { e.printStackTrace(PrintStream(it)) }.toByteArray()),
CompilerMessageLocation.create(moduleFile.path)
)
}
loadedModules.add(ModuleMappingInfo(root, mapping, moduleFile.nameWithoutExtension))
}
}
}

View File

@@ -69,6 +69,7 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
import org.jetbrains.kotlin.cli.common.config.ContentRoot
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
@@ -110,6 +111,7 @@ import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtens
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
import org.jetbrains.kotlin.script.ScriptReportSink
@@ -305,7 +307,7 @@ class KotlinCoreEnvironment private constructor(
fun createPackagePartProvider(scope: GlobalSearchScope): JvmPackagePartProvider {
return JvmPackagePartProvider(configuration.languageVersionSettings, scope).apply {
addRoots(initialRoots)
addRoots(initialRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
packagePartProviders += this
(ModuleAnnotationsResolver.getInstance(project) as CliModuleAnnotationsResolver).addPackagePartProvider(this)
}
@@ -363,7 +365,7 @@ class KotlinCoreEnvironment private constructor(
val newRoots = classpathRootsResolver.convertClasspathRoots(contentRoots).roots
for (packagePartProvider in packagePartProviders) {
packagePartProvider.addRoots(newRoots)
packagePartProvider.addRoots(newRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
}
return rootsIndex.addNewIndexForRoots(newRoots)?.let { newIndex ->
@@ -400,16 +402,18 @@ class KotlinCoreEnvironment private constructor(
private fun findJarRoot(file: File): VirtualFile? =
applicationEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
private fun getSourceRootsCheckingForDuplicates(): Collection<String> {
val uniqueSourceRoots = linkedSetOf<String>()
private fun getSourceRootsCheckingForDuplicates(): List<KotlinSourceRoot> {
val uniqueSourceRoots = hashSetOf<String>()
val result = mutableListOf<KotlinSourceRoot>()
configuration.kotlinSourceRoots.forEach { path ->
if (!uniqueSourceRoots.add(path)) {
report(STRONG_WARNING, "Duplicate source root: $path")
for (root in configuration.kotlinSourceRoots) {
if (!uniqueSourceRoots.add(root.path)) {
report(STRONG_WARNING, "Duplicate source root: ${root.path}")
}
result.add(root)
}
return uniqueSourceRoots
return result
}
fun getSourceFiles(): List<KtFile> = sourceFiles
@@ -425,7 +429,7 @@ class KotlinCoreEnvironment private constructor(
val virtualFileCreator = PreprocessedFileCreator(project)
for (sourceRootPath in sourceRoots) {
for ((sourceRootPath, isCommon) in sourceRoots) {
val vFile = localFileSystem.findFileByPath(sourceRootPath)
if (vFile == null) {
val message = "Source file or directory not found: $sourceRootPath"
@@ -452,6 +456,9 @@ class KotlinCoreEnvironment private constructor(
val psiFile = psiManager.findFile(virtualFile)
if (psiFile is KtFile) {
result.add(psiFile)
if (isCommon) {
psiFile.isCommonSource = true
}
}
}
}

View File

@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING
@@ -65,18 +65,6 @@ import java.lang.reflect.InvocationTargetException
import java.net.URLClassLoader
object KotlinToJVMBytecodeCompiler {
private fun getAbsoluteFiles(buildFile: File, module: Module): List<File> {
return module.getSourceFiles().map { sourceFile ->
val source = File(sourceFile)
if (!source.isAbsolute) {
File(buildFile.absoluteFile.parentFile, sourceFile)
} else {
source
}
}
}
private fun writeOutput(
configuration: CompilerConfiguration,
outputFiles: OutputFileCollection,
@@ -142,7 +130,7 @@ object KotlinToJVMBytecodeCompiler {
for (module in chunk) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
val moduleSourceFiles = getAbsoluteFiles(buildFile, module).map { file -> localFileSystem.findFileByPath(file.path) }
val moduleSourceFiles = getAbsolutePaths(buildFile, module.getSourceFiles()).map(localFileSystem::findFileByPath)
val ktFiles = environment.getSourceFiles().filter { file -> file.virtualFile in moduleSourceFiles }
if (!checkKotlinPackageUsage(environment, ktFiles)) return false
@@ -184,7 +172,11 @@ object KotlinToJVMBytecodeCompiler {
internal fun configureSourceRoots(configuration: CompilerConfiguration, chunk: List<Module>, buildFile: File) {
for (module in chunk) {
configuration.addKotlinSourceRoots(getAbsoluteFiles(buildFile, module).map(File::getPath))
val commonSources = getAbsolutePaths(buildFile, module.getCommonSourceFiles()).toSet()
for (path in getAbsolutePaths(buildFile, module.getSourceFiles())) {
configuration.addKotlinSourceRoot(path, isCommon = path in commonSources)
}
}
for (module in chunk) {
@@ -224,6 +216,11 @@ object KotlinToJVMBytecodeCompiler {
configuration.addAll(JVMConfigurationKeys.MODULES, chunk)
}
private fun getAbsolutePaths(buildFile: File, sourceFilePaths: List<String>): List<String> =
sourceFilePaths.map { path ->
(File(path).takeIf(File::isAbsolute) ?: buildFile.resolveSibling(path)).absolutePath
}
private fun findMainClass(generationState: GenerationState, files: List<KtFile>): FqName? {
val mainFunctionDetector = MainFunctionDetector(generationState.bindingContext)
return files.asSequence()

View File

@@ -60,7 +60,7 @@ class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult
for (arg in arguments.freeArgs) {
configuration.addKotlinSourceRoot(arg)
configuration.addKotlinSourceRoot(arg, isCommon = true)
}
if (arguments.classpath != null) {
configuration.addJvmClasspathRoots(arguments.classpath!!.split(File.pathSeparatorChar).map(::File))

View File

@@ -23,7 +23,9 @@ class IncrementalModuleInfo(
val projectRoot: File,
val dirToModule: Map<File, IncrementalModuleEntry>,
val nameToModules: Map<String, Set<IncrementalModuleEntry>>,
val jarToClassListFile: Map<File, File>
val jarToClassListFile: Map<File, File>,
// only for js
val jarToModule: Map<File, IncrementalModuleEntry>
) : Serializable {
companion object {
private const val serialVersionUID = 0L

View File

@@ -38,7 +38,6 @@ import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.report.CompileServicesFacadeMessageCollector
@@ -50,9 +49,10 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryAndroid
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJs
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
@@ -83,7 +83,7 @@ interface CompilerSelector {
}
interface EventManager {
fun onCompilationFinished(f : () -> Unit)
fun onCompilationFinished(f: () -> Unit)
}
private class EventManagerImpl : EventManager {
@@ -99,14 +99,14 @@ private class EventManagerImpl : EventManager {
}
class CompileServiceImpl(
val registry: Registry,
val compiler: CompilerSelector,
val compilerId: CompilerId,
val daemonOptions: DaemonOptions,
val daemonJVMOptions: DaemonJVMOptions,
val port: Int,
val timer: Timer,
val onShutdown: () -> Unit
val registry: Registry,
val compiler: CompilerSelector,
val compilerId: CompilerId,
val daemonOptions: DaemonOptions,
val daemonJVMOptions: DaemonJVMOptions,
val port: Int,
val timer: Timer,
val onShutdown: () -> Unit
) : CompileService {
private val log by lazy { Logger.getLogger("compiler") }
@@ -116,8 +116,14 @@ class CompileServiceImpl(
}
// wrapped in a class to encapsulate alive check logic
private class ClientOrSessionProxy<out T: Any>(val aliveFlagPath: String?, val data: T? = null, private var disposable: Disposable? = null) {
val isAlive: Boolean get() = aliveFlagPath?.let { File(it).exists() } ?: true // assuming that if no file was given, the client is alive
private class ClientOrSessionProxy<out T : Any>(
val aliveFlagPath: String?,
val data: T? = null,
private var disposable: Disposable? = null
) {
val isAlive: Boolean
get() = aliveFlagPath?.let { File(it).exists() } ?: true // assuming that if no file was given, the client is alive
fun dispose() {
disposable?.let {
Disposer.dispose(it)
@@ -132,7 +138,8 @@ class CompileServiceImpl(
enum class Aliveness {
// !!! ordering of values is used in state comparison
Dying, LastSession, Alive
Dying,
LastSession, Alive
}
private class SessionsContainer {
@@ -143,7 +150,7 @@ class CompileServiceImpl(
val lastSessionId get() = sessionsIdCounter.get()
fun<T: Any> leaseSession(session: ClientOrSessionProxy<T>): Int = lock.write {
fun <T : Any> leaseSession(session: ClientOrSessionProxy<T>): Int = lock.write {
val newId = getValidId(sessionsIdCounter) {
it != CompileService.NO_SESSION && !sessions.containsKey(it)
}
@@ -203,18 +210,22 @@ class CompileServiceImpl(
clientProxies.mapNotNull { it.aliveFlagPath }
}
fun cleanDeadClients(): Boolean = clientProxies.cleanMatching(clientsLock, { !it.isAlive }, { if (clientProxies.remove(it)) it.dispose() })
fun cleanDeadClients(): Boolean =
clientProxies.cleanMatching(clientsLock, { !it.isAlive }, { if (clientProxies.remove(it)) it.dispose() })
}
private fun Int.toAlivenessName(): String =
try {
Aliveness.values()[this].name
}
catch (_: Throwable) {
"invalid($this)"
}
try {
Aliveness.values()[this].name
} catch (_: Throwable) {
"invalid($this)"
}
private inline fun<T> Iterable<T>.cleanMatching(lock: ReentrantReadWriteLock, crossinline pred: (T) -> Boolean, crossinline clean: (T) -> Unit): Boolean {
private inline fun <T> Iterable<T>.cleanMatching(
lock: ReentrantReadWriteLock,
crossinline pred: (T) -> Boolean,
crossinline clean: (T) -> Unit
): Boolean {
var anyDead = false
lock.read {
val toRemove = filter(pred)
@@ -228,7 +239,8 @@ class CompileServiceImpl(
return anyDead
}
@Volatile private var _lastUsedSeconds = nowSeconds()
@Volatile
private var _lastUsedSeconds = nowSeconds()
val lastUsedSeconds: Long get() = if (rwlock.isWriteLocked || rwlock.readLockCount - rwlock.readHoldCount > 0) nowSeconds() else _lastUsedSeconds
private val rwlock = ReentrantReadWriteLock()
@@ -238,10 +250,14 @@ class CompileServiceImpl(
init {
val runFileDir = File(daemonOptions.runFilesPathOrDefault)
runFileDir.mkdirs()
runFile = File(runFileDir,
makeRunFilenameString(timestamp = "%tFT%<tH-%<tM-%<tS.%<tLZ".format(Calendar.getInstance(TimeZone.getTimeZone("Z"))),
digest = compilerId.compilerClasspath.map { File(it).absolutePath }.distinctStringsDigest().toHexString(),
port = port.toString()))
runFile = File(
runFileDir,
makeRunFilenameString(
timestamp = "%tFT%<tH-%<tM-%<tS.%<tLZ".format(Calendar.getInstance(TimeZone.getTimeZone("Z"))),
digest = compilerId.compilerClasspath.map { File(it).absolutePath }.distinctStringsDigest().toHexString(),
port = port.toString()
)
)
try {
if (!runFile.createNewFile()) throw Exception("createNewFile returned false")
} catch (e: Throwable) {
@@ -279,9 +295,9 @@ class CompileServiceImpl(
// TODO: consider tying a session to a client and use this info to cleanup
override fun leaseCompileSession(aliveFlagPath: String?): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
CompileService.CallResult.Good(
state.sessions.leaseSession(ClientOrSessionProxy<Any>(aliveFlagPath)).apply {
log.info("leased a new session $this, session alive file: $aliveFlagPath")
})
state.sessions.leaseSession(ClientOrSessionProxy<Any>(aliveFlagPath)).apply {
log.info("leased a new session $this, session alive file: $aliveFlagPath")
})
}
@@ -301,12 +317,12 @@ class CompileServiceImpl(
}
override fun checkCompilerId(expectedCompilerId: CompilerId): Boolean =
(compilerId.compilerVersion.isEmpty() || compilerId.compilerVersion == expectedCompilerId.compilerVersion) &&
(compilerId.compilerClasspath.all { expectedCompilerId.compilerClasspath.contains(it) }) &&
!classpathWatcher.isChanged
(compilerId.compilerVersion.isEmpty() || compilerId.compilerVersion == expectedCompilerId.compilerVersion) &&
(compilerId.compilerClasspath.all { expectedCompilerId.compilerClasspath.contains(it) }) &&
!classpathWatcher.isChanged
override fun getUsedMemory(): CompileService.CallResult<Long> =
ifAlive { CompileService.CallResult.Good(usedMemory(withGC = true)) }
ifAlive { CompileService.CallResult.Good(usedMemory(withGC = true)) }
override fun shutdown(): CompileService.CallResult<Nothing> = ifAliveExclusive(minAliveness = Aliveness.LastSession) {
shutdownWithDelay()
@@ -324,37 +340,55 @@ class CompileServiceImpl(
CompileService.CallResult.Good(res)
}
override fun remoteCompile(sessionId: Int,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
servicesFacade: CompilerCallbackServicesFacade,
compilerOutputStream: RemoteOutputStream,
outputFormat: CompileService.OutputFormat,
serviceOutputStream: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?
override fun remoteCompile(
sessionId: Int,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
servicesFacade: CompilerCallbackServicesFacade,
compilerOutputStream: RemoteOutputStream,
outputFormat: CompileService.OutputFormat,
serviceOutputStream: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?
): CompileService.CallResult<Int> =
doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler ->
when (outputFormat) {
CompileService.OutputFormat.PLAIN -> compiler[targetPlatform].exec(printStream, *args)
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(printStream, createCompileServices(servicesFacade, eventManager, profiler), *args)
}
doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler ->
when (outputFormat) {
CompileService.OutputFormat.PLAIN -> compiler[targetPlatform].exec(printStream, *args)
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(
printStream,
createCompileServices(
servicesFacade,
eventManager,
profiler
),
*args
)
}
}
override fun remoteIncrementalCompile(sessionId: Int,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
servicesFacade: CompilerCallbackServicesFacade,
compilerOutputStream: RemoteOutputStream,
compilerOutputFormat: CompileService.OutputFormat,
serviceOutputStream: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?
override fun remoteIncrementalCompile(
sessionId: Int,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
servicesFacade: CompilerCallbackServicesFacade,
compilerOutputStream: RemoteOutputStream,
compilerOutputFormat: CompileService.OutputFormat,
serviceOutputStream: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?
): CompileService.CallResult<Int> =
doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler ->
when (compilerOutputFormat) {
CompileService.OutputFormat.PLAIN -> throw NotImplementedError("Only XML output is supported in remote incremental compilation")
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(printStream, createCompileServices(servicesFacade, eventManager, profiler), *args)
}
doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler ->
when (compilerOutputFormat) {
CompileService.OutputFormat.PLAIN -> throw NotImplementedError("Only XML output is supported in remote incremental compilation")
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(
printStream,
createCompileServices(
servicesFacade,
eventManager,
profiler
),
*args
)
}
}
override fun classesFqNamesByFiles(
sessionId: Int, sourceFiles: Set<File>
@@ -366,11 +400,11 @@ class CompileServiceImpl(
}
override fun compile(
sessionId: Int,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBase,
compilationResults: CompilationResults?
sessionId: Int,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBase,
compilationResults: CompilationResults?
): CompileService.CallResult<Int> = ifAlive {
withValidClientOrSessionProxy(sessionId) {
val messageCollector = CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
@@ -391,8 +425,7 @@ class CompileServiceImpl(
if (argumentParseError != null) {
messageCollector.report(CompilerMessageSeverity.ERROR, argumentParseError)
CompileService.CallResult.Good(ExitCode.COMPILATION_ERROR.code)
}
else when (compilationOptions.compilerMode) {
} else when (compilationOptions.compilerMode) {
CompilerMode.JPS_COMPILER -> {
val jpsServicesFacade = servicesFacade as JpsCompilerServicesFacade
@@ -418,8 +451,10 @@ class CompileServiceImpl(
withIC {
doCompile(sessionId, daemonReporter, tracer = null) { _, _ ->
execIncrementalCompiler(k2jvmArgs, gradleIncrementalArgs, gradleIncrementalServicesFacade, compilationResults!!,
messageCollector, daemonReporter)
execIncrementalCompiler(
k2jvmArgs, gradleIncrementalArgs, gradleIncrementalServicesFacade, compilationResults!!,
messageCollector, daemonReporter
)
}
}
}
@@ -428,7 +463,13 @@ class CompileServiceImpl(
withJsIC {
doCompile(sessionId, daemonReporter, tracer = null) { _, _ ->
execJsIncrementalCompiler(k2jsArgs, gradleIncrementalArgs, gradleIncrementalServicesFacade, compilationResults!!, messageCollector)
execJsIncrementalCompiler(
k2jsArgs,
gradleIncrementalArgs,
gradleIncrementalServicesFacade,
compilationResults!!,
messageCollector
)
}
}
}
@@ -451,10 +492,9 @@ class CompileServiceImpl(
val allKotlinFiles = arrayListOf<File>()
val freeArgsWithoutKotlinFiles = arrayListOf<String>()
args.freeArgs.forEach {
if (it.endsWith(".kt") && File(it).exists()) {
if (it.endsWith(".kt") && File(it).exists()) {
allKotlinFiles.add(File(it))
}
else {
} else {
freeArgsWithoutKotlinFiles.add(it)
}
}
@@ -464,29 +504,36 @@ class CompileServiceImpl(
val changedFiles = if (incrementalCompilationOptions.areFileChangesKnown) {
ChangedFiles.Known(incrementalCompilationOptions.modifiedFiles!!, incrementalCompilationOptions.deletedFiles!!)
}
else {
} else {
ChangedFiles.Unknown()
}
val workingDir = incrementalCompilationOptions.workingDir
val versions = commonCacheVersions(workingDir, enabled = true) +
customCacheVersion(incrementalCompilationOptions.customCacheVersion,
incrementalCompilationOptions.customCacheVersionFileName,
workingDir,
enabled = true)
val compiler = IncrementalJsCompilerRunner(workingDir, versions, reporter)
val versionManagers = commonCacheVersionsManagers(workingDir, enabled = true) +
customCacheVersionManager(
incrementalCompilationOptions.customCacheVersion,
incrementalCompilationOptions.customCacheVersionFileName,
workingDir,
enabled = true
)
val modulesApiHistory = ModulesApiHistoryJs(incrementalCompilationOptions.modulesInfo)
val compiler = IncrementalJsCompilerRunner(
workingDir = workingDir,
cachesVersionManagers = versionManagers,
reporter = reporter,
buildHistoryFile = incrementalCompilationOptions.multiModuleICSettings.buildHistoryFile,
modulesApiHistory = modulesApiHistory
)
return compiler.compile(allKotlinFiles, args, compilerMessageCollector, changedFiles)
}
private fun execIncrementalCompiler(
k2jvmArgs: K2JVMCompilerArguments,
incrementalCompilationOptions: IncrementalCompilationOptions,
servicesFacade: IncrementalCompilerServicesFacade,
compilationResults: CompilationResults,
compilerMessageCollector: MessageCollector,
daemonMessageReporter: DaemonMessageReporter
k2jvmArgs: K2JVMCompilerArguments,
incrementalCompilationOptions: IncrementalCompilationOptions,
servicesFacade: IncrementalCompilerServicesFacade,
compilationResults: CompilationResults,
compilerMessageCollector: MessageCollector,
daemonMessageReporter: DaemonMessageReporter
): ExitCode {
val reporter = RemoteICReporter(servicesFacade, compilationResults, incrementalCompilationOptions)
@@ -509,22 +556,25 @@ class CompileServiceImpl(
it.getJavaSourceRoots().map { JvmSourceRoot(File(it.path), it.packagePrefix) }
}
k2jvmArgs.commonSources = parsedModule.modules.flatMap { it.getCommonSourceFiles() }.toTypedArray().takeUnless { it.isEmpty() }
val allKotlinFiles = parsedModule.modules.flatMap { it.getSourceFiles().map(::File) }
k2jvmArgs.friendPaths = parsedModule.modules.flatMap(Module::getFriendPaths).toTypedArray()
val changedFiles = if (incrementalCompilationOptions.areFileChangesKnown) {
ChangedFiles.Known(incrementalCompilationOptions.modifiedFiles!!, incrementalCompilationOptions.deletedFiles!!)
}
else {
} else {
ChangedFiles.Unknown()
}
val workingDir = incrementalCompilationOptions.workingDir
val versions = commonCacheVersions(workingDir, enabled = true) +
customCacheVersion(incrementalCompilationOptions.customCacheVersion,
incrementalCompilationOptions.customCacheVersionFileName,
workingDir,
enabled = true)
val versions = commonCacheVersionsManagers(workingDir, enabled = true) +
customCacheVersionManager(
incrementalCompilationOptions.customCacheVersion,
incrementalCompilationOptions.customCacheVersionFileName,
workingDir,
enabled = true
)
val modulesApiHistory = incrementalCompilationOptions.run {
if (!multiModuleICSettings.useModuleDetection) {
@@ -548,27 +598,34 @@ class CompileServiceImpl(
}
override fun leaseReplSession(
aliveFlagPath: String?,
targetPlatform: CompileService.TargetPlatform,
servicesFacade: CompilerCallbackServicesFacade,
templateClasspath: List<File>,
templateClassName: String,
scriptArgs: Array<out Any?>?,
scriptArgsTypes: Array<out Class<out Any>>?,
compilerMessagesOutputStream: RemoteOutputStream,
evalOutputStream: RemoteOutputStream?,
evalErrorStream: RemoteOutputStream?,
evalInputStream: RemoteInputStream?,
operationsTracer: RemoteOperationsTracer?
aliveFlagPath: String?,
targetPlatform: CompileService.TargetPlatform,
servicesFacade: CompilerCallbackServicesFacade,
templateClasspath: List<File>,
templateClassName: String,
scriptArgs: Array<out Any?>?,
scriptArgsTypes: Array<out Class<out Any>>?,
compilerMessagesOutputStream: RemoteOutputStream,
evalOutputStream: RemoteOutputStream?,
evalErrorStream: RemoteOutputStream?,
evalInputStream: RemoteInputStream?,
operationsTracer: RemoteOperationsTracer?
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
if (targetPlatform != CompileService.TargetPlatform.JVM)
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
else {
val disposable = Disposer.newDisposable()
val compilerMessagesStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(compilerMessagesOutputStream, DummyProfiler()), REMOTE_STREAM_BUFFER_SIZE))
val compilerMessagesStream = PrintStream(
BufferedOutputStream(
RemoteOutputStreamClient(compilerMessagesOutputStream, DummyProfiler()),
REMOTE_STREAM_BUFFER_SIZE
)
)
val messageCollector = KeepFirstErrorMessageCollector(compilerMessagesStream)
val repl = KotlinJvmReplService(disposable, port, templateClasspath, templateClassName,
messageCollector, operationsTracer)
val repl = KotlinJvmReplService(
disposable, port, templateClasspath, templateClassName,
messageCollector, operationsTracer
)
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
CompileService.CallResult.Good(sessionId)
@@ -579,42 +636,49 @@ class CompileServiceImpl(
override fun releaseReplSession(sessionId: Int): CompileService.CallResult<Nothing> = releaseCompileSession(sessionId)
override fun remoteReplLineCheck(sessionId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCheckResult> =
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
CompileService.CallResult.Good(check(codeLine))
}
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
CompileService.CallResult.Good(check(codeLine))
}
}
override fun remoteReplLineCompile(sessionId: Int, codeLine: ReplCodeLine, history: List<ReplCodeLine>?): CompileService.CallResult<ReplCompileResult> =
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
CompileService.CallResult.Good(compile(codeLine, history))
}
override fun remoteReplLineCompile(
sessionId: Int,
codeLine: ReplCodeLine,
history: List<ReplCodeLine>?
): CompileService.CallResult<ReplCompileResult> =
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
CompileService.CallResult.Good(compile(codeLine, history))
}
}
override fun remoteReplLineEval(
sessionId: Int,
codeLine: ReplCodeLine,
history: List<ReplCodeLine>?
sessionId: Int,
codeLine: ReplCodeLine,
history: List<ReplCodeLine>?
): CompileService.CallResult<ReplEvalResult> =
ifAlive(minAliveness = Aliveness.Alive) {
CompileService.CallResult.Error("Eval on daemon is not supported")
}
ifAlive(minAliveness = Aliveness.Alive) {
CompileService.CallResult.Error("Eval on daemon is not supported")
}
override fun leaseReplSession(aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBase,
templateClasspath: List<File>,
templateClassName: String
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
override fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBase,
templateClasspath: List<File>,
templateClassName: String
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
if (compilationOptions.targetPlatform != CompileService.TargetPlatform.JVM)
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
else {
val disposable = Disposer.newDisposable()
val messageCollector = CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
val repl = KotlinJvmReplService(disposable, port, templateClasspath, templateClassName,
messageCollector, null)
val repl = KotlinJvmReplService(
disposable, port, templateClasspath, templateClassName,
messageCollector, null
)
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
CompileService.CallResult.Good(sessionId)
@@ -622,29 +686,29 @@ class CompileServiceImpl(
}
override fun replCreateState(sessionId: Int): CompileService.CallResult<ReplStateFacade> =
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
CompileService.CallResult.Good(createRemoteState(port))
}
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
CompileService.CallResult.Good(createRemoteState(port))
}
}
override fun replCheck(sessionId: Int, replStateId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCheckResult> =
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
withValidReplState(replStateId) { state ->
check(state, codeLine)
}
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
withValidReplState(replStateId) { state ->
check(state, codeLine)
}
}
}
override fun replCompile(sessionId: Int, replStateId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCompileResult> =
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
withValidReplState(replStateId) { state ->
compile(state, codeLine)
}
ifAlive(minAliveness = Aliveness.Alive) {
withValidRepl(sessionId) {
withValidReplState(replStateId) { state ->
compile(state, codeLine)
}
}
}
// -----------------------------------------------------------------------
// internal implementation stuff
@@ -667,13 +731,17 @@ class CompileServiceImpl(
try {
// cleanup for the case of incorrect restart and many other situations
UnicastRemoteObject.unexportObject(this, false)
}
catch (e: NoSuchObjectException) {
} catch (e: NoSuchObjectException) {
// ignoring if object already exported
}
val stub = UnicastRemoteObject.exportObject(this, port, LoopbackNetworkInterface.clientLoopbackSocketFactory, LoopbackNetworkInterface.serverLoopbackSocketFactory) as CompileService
registry.rebind (COMPILER_SERVICE_RMI_NAME, stub)
val stub = UnicastRemoteObject.exportObject(
this,
port,
LoopbackNetworkInterface.clientLoopbackSocketFactory,
LoopbackNetworkInterface.serverLoopbackSocketFactory
) as CompileService
registry.rebind(COMPILER_SERVICE_RMI_NAME, stub)
timer.schedule(10) {
exceptionLoggingTimerThread { initiateElections() }
@@ -689,8 +757,7 @@ class CompileServiceImpl(
private inline fun exceptionLoggingTimerThread(body: () -> Unit) {
try {
body()
}
catch (e: Throwable) {
} catch (e: Throwable) {
System.err.println("Exception in timer thread: " + e.message)
e.printStackTrace(System.err)
log.log(Level.SEVERE, "Exception in timer thread", e)
@@ -760,12 +827,22 @@ class CompileServiceImpl(
ifAliveUnit {
log.info("initiate elections")
val aliveWithOpts = walkDaemons(File(daemonOptions.runFilesPathOrDefault), compilerId, runFile, filter = { _, p -> p != port }, report = { _, msg -> log.info(msg) }).toList()
val comparator = compareByDescending<DaemonWithMetadata, DaemonJVMOptions>(DaemonJVMOptionsMemoryComparator(), { it.jvmOptions })
val aliveWithOpts = walkDaemons(
File(daemonOptions.runFilesPathOrDefault),
compilerId,
runFile,
filter = { _, p -> p != port },
report = { _, msg -> log.info(msg) }).toList()
val comparator =
compareByDescending<DaemonWithMetadata, DaemonJVMOptions>(DaemonJVMOptionsMemoryComparator(), { it.jvmOptions })
.thenBy(FileAgeComparator()) { it.runFile }
aliveWithOpts.maxWith(comparator)?.let { bestDaemonWithMetadata ->
val fattestOpts = bestDaemonWithMetadata.jvmOptions
if (fattestOpts memorywiseFitsInto daemonJVMOptions && FileAgeComparator().compare(bestDaemonWithMetadata.runFile, runFile) < 0 ) {
if (fattestOpts memorywiseFitsInto daemonJVMOptions && FileAgeComparator().compare(
bestDaemonWithMetadata.runFile,
runFile
) < 0
) {
// all others are smaller that me, take overs' clients and shut them down
log.info("$LOG_PREFIX_ASSUMING_OTHER_DAEMONS_HAVE lower prio, taking clients from them and schedule them to shutdown: my runfile: ${runFile.name} (${runFile.lastModified()}) vs best other runfile: ${bestDaemonWithMetadata.runFile.name} (${bestDaemonWithMetadata.runFile.lastModified()})")
aliveWithOpts.forEach { (daemon, runFile, _) ->
@@ -774,8 +851,7 @@ class CompileServiceImpl(
it.get().forEach { clientAliveFile -> registerClient(clientAliveFile) }
}
daemon.scheduleShutdown(true)
}
catch (e: Throwable) {
} catch (e: Throwable) {
log.info("Cannot connect to a daemon, assuming dying ('${runFile.canonicalPath}'): ${e.message}")
}
}
@@ -795,15 +871,18 @@ class CompileServiceImpl(
// B performs election: (1) is false because neither A nor C does not fit into B, (2) is false because B does not fit into neither A nor C.
// C performs election: (1) is false because B is better than A and B does not fit into C, (2) is false C does not fit into neither A nor B.
// Result: all daemons are alive and well.
else if (daemonJVMOptions memorywiseFitsInto fattestOpts && FileAgeComparator().compare(bestDaemonWithMetadata.runFile, runFile) > 0) {
else if (daemonJVMOptions memorywiseFitsInto fattestOpts && FileAgeComparator().compare(
bestDaemonWithMetadata.runFile,
runFile
) > 0
) {
// there is at least one bigger, handover my clients to it and shutdown
log.info("$LOG_PREFIX_ASSUMING_OTHER_DAEMONS_HAVE higher prio, handover clients to it and schedule shutdown: my runfile: ${runFile.name} (${runFile.lastModified()}) vs best other runfile: ${bestDaemonWithMetadata.runFile.name} (${bestDaemonWithMetadata.runFile.lastModified()})")
getClients().takeIf { it.isGood }?.let {
it.get().forEach { bestDaemonWithMetadata.daemon.registerClient(it) }
}
scheduleShutdown(true)
}
else {
} else {
// undecided, do nothing
log.info("$LOG_PREFIX_ASSUMING_OTHER_DAEMONS_HAVE equal prio, continue: ${runFile.name} (${runFile.lastModified()}) vs best other runfile: ${bestDaemonWithMetadata.runFile.name} (${bestDaemonWithMetadata.runFile.lastModified()})")
// TODO: implement some behaviour here, e.g.:
@@ -817,7 +896,7 @@ class CompileServiceImpl(
private fun shutdownNow() {
log.info("Shutdown started")
fun Long.mb() = this / (1024 * 1024)
with (Runtime.getRuntime()) {
with(Runtime.getRuntime()) {
log.info("Memory stats: total: ${totalMemory().mb()}mb, free: ${freeMemory().mb()}mb, max: ${maxMemory().mb()}mb")
}
state.alive.set(Aliveness.Dying.ordinal)
@@ -838,14 +917,13 @@ class CompileServiceImpl(
state.delayedShutdownQueued.set(false)
if (currentClientsCount == state.clientsCounter &&
currentCompilationsCount == compilationsCounter.get() &&
currentSessionId == state.sessions.lastSessionId)
{
currentSessionId == state.sessions.lastSessionId
) {
ifAliveExclusiveUnit(minAliveness = Aliveness.LastSession) {
log.fine("Execute delayed shutdown")
shutdownNow()
}
}
else {
} else {
log.info("Cancel delayed shutdown due to a new activity")
}
}
@@ -856,7 +934,8 @@ class CompileServiceImpl(
fun shutdownIfIdle() = when {
state.sessions.isEmpty() -> shutdownWithDelay()
else -> {
daemonOptions.autoshutdownIdleSeconds = TimeUnit.MILLISECONDS.toSeconds(daemonOptions.forceShutdownTimeoutMilliseconds).toInt()
daemonOptions.autoshutdownIdleSeconds =
TimeUnit.MILLISECONDS.toSeconds(daemonOptions.forceShutdownTimeoutMilliseconds).toInt()
daemonOptions.autoshutdownUnusedSeconds = daemonOptions.autoshutdownIdleSeconds
log.info("Some sessions are active, waiting for them to finish")
log.info("Unused/idle timeouts are set to ${daemonOptions.autoshutdownUnusedSeconds}/${daemonOptions.autoshutdownIdleSeconds}s")
@@ -871,8 +950,7 @@ class CompileServiceImpl(
if (!onAnotherThread) {
shutdownIfIdle()
}
else {
} else {
timer.schedule(1) {
ifAliveExclusiveUnit(minAliveness = Aliveness.LastSession) {
shutdownIfIdle()
@@ -883,64 +961,79 @@ class CompileServiceImpl(
}
// todo: remove after remoteIncrementalCompile is removed
private fun doCompile(sessionId: Int,
args: Array<out String>,
compilerMessagesStreamProxy: RemoteOutputStream,
serviceOutputStreamProxy: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?,
body: (PrintStream, EventManager, Profiler) -> ExitCode): CompileService.CallResult<Int> =
ifAlive {
withValidClientOrSessionProxy(sessionId) {
operationsTracer?.before("compile")
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
val eventManger = EventManagerImpl()
val compilerMessagesStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(compilerMessagesStreamProxy, rpcProfiler), REMOTE_STREAM_BUFFER_SIZE))
val serviceOutputStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(serviceOutputStreamProxy, rpcProfiler), REMOTE_STREAM_BUFFER_SIZE))
try {
val compileServiceReporter = DaemonMessageReporterPrintStreamAdapter(serviceOutputStream)
if (args.none())
throw IllegalArgumentException("Error: empty arguments list.")
log.info("Starting compilation with args: " + args.joinToString(" "))
val exitCode = checkedCompile(compileServiceReporter, rpcProfiler) {
body(compilerMessagesStream, eventManger, rpcProfiler).code
}
CompileService.CallResult.Good(exitCode)
}
finally {
serviceOutputStream.flush()
compilerMessagesStream.flush()
eventManger.fireCompilationFinished()
operationsTracer?.after("compile")
private fun doCompile(
sessionId: Int,
args: Array<out String>,
compilerMessagesStreamProxy: RemoteOutputStream,
serviceOutputStreamProxy: RemoteOutputStream,
operationsTracer: RemoteOperationsTracer?,
body: (PrintStream, EventManager, Profiler) -> ExitCode
): CompileService.CallResult<Int> =
ifAlive {
withValidClientOrSessionProxy(sessionId) {
operationsTracer?.before("compile")
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
val eventManger = EventManagerImpl()
val compilerMessagesStream = PrintStream(
BufferedOutputStream(
RemoteOutputStreamClient(compilerMessagesStreamProxy, rpcProfiler),
REMOTE_STREAM_BUFFER_SIZE
)
)
val serviceOutputStream = PrintStream(
BufferedOutputStream(
RemoteOutputStreamClient(serviceOutputStreamProxy, rpcProfiler),
REMOTE_STREAM_BUFFER_SIZE
)
)
try {
val compileServiceReporter = DaemonMessageReporterPrintStreamAdapter(serviceOutputStream)
if (args.none())
throw IllegalArgumentException("Error: empty arguments list.")
log.info("Starting compilation with args: " + args.joinToString(" "))
val exitCode = checkedCompile(compileServiceReporter, rpcProfiler) {
body(compilerMessagesStream, eventManger, rpcProfiler).code
}
CompileService.CallResult.Good(exitCode)
} finally {
serviceOutputStream.flush()
compilerMessagesStream.flush()
eventManger.fireCompilationFinished()
operationsTracer?.after("compile")
}
}
}
private fun doCompile(sessionId: Int,
daemonMessageReporter: DaemonMessageReporter,
tracer: RemoteOperationsTracer?,
body: (EventManager, Profiler) -> ExitCode): CompileService.CallResult<Int> =
ifAlive {
withValidClientOrSessionProxy(sessionId) {
tracer?.before("compile")
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
val eventManger = EventManagerImpl()
try {
val exitCode = checkedCompile(daemonMessageReporter, rpcProfiler) {
body(eventManger, rpcProfiler).code
}
CompileService.CallResult.Good(exitCode)
}
finally {
eventManger.fireCompilationFinished()
tracer?.after("compile")
private fun doCompile(
sessionId: Int,
daemonMessageReporter: DaemonMessageReporter,
tracer: RemoteOperationsTracer?,
body: (EventManager, Profiler) -> ExitCode
): CompileService.CallResult<Int> =
ifAlive {
withValidClientOrSessionProxy(sessionId) {
tracer?.before("compile")
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
val eventManger = EventManagerImpl()
try {
val exitCode = checkedCompile(daemonMessageReporter, rpcProfiler) {
body(eventManger, rpcProfiler).code
}
CompileService.CallResult.Good(exitCode)
} finally {
eventManger.fireCompilationFinished()
tracer?.after("compile")
}
}
}
private fun createCompileServices(facade: CompilerCallbackServicesFacade, eventManager: EventManager, rpcProfiler: Profiler): Services {
val builder = Services.Builder()
if (facade.hasIncrementalCaches()) {
builder.register(IncrementalCompilationComponents::class.java, RemoteIncrementalCompilationComponentsClient(facade, eventManager, rpcProfiler))
builder.register(
IncrementalCompilationComponents::class.java,
RemoteIncrementalCompilationComponentsClient(facade, eventManager, rpcProfiler)
)
}
if (facade.hasLookupTracker()) {
builder.register(LookupTracker::class.java, RemoteLookupTrackerClient(facade, eventManager, rpcProfiler))
@@ -962,7 +1055,7 @@ class CompileServiceImpl(
}
private fun<R> checkedCompile(daemonMessageReporter: DaemonMessageReporter, rpcProfiler: Profiler, body: () -> R): R {
private fun <R> checkedCompile(daemonMessageReporter: DaemonMessageReporter, rpcProfiler: Profiler, body: () -> R): R {
try {
val profiler = if (daemonOptions.reportPerf) WallAndThreadAndMemoryTotalProfiler(withGC = false) else DummyProfiler()
@@ -978,7 +1071,9 @@ class CompileServiceImpl(
val pc = profiler.getTotalCounters()
val rpc = rpcProfiler.getTotalCounters()
"PERF: Compile on daemon: ${pc.time.ms()} ms; thread: user ${pc.threadUserTime.ms()} ms, sys ${(pc.threadTime - pc.threadUserTime).ms()} ms; rpc: ${rpc.count} calls, ${rpc.time.ms()} ms, thread ${rpc.threadTime.ms()} ms; memory: ${endMem.kb()} kb (${"%+d".format(pc.memory.kb())} kb)".let {
"PERF: Compile on daemon: ${pc.time.ms()} ms; thread: user ${pc.threadUserTime.ms()} ms, sys ${(pc.threadTime - pc.threadUserTime).ms()} ms; rpc: ${rpc.count} calls, ${rpc.time.ms()} ms, thread ${rpc.threadTime.ms()} ms; memory: ${endMem.kb()} kb (${"%+d".format(
pc.memory.kb()
)} kb)".let {
daemonMessageReporter.report(ReportSeverity.INFO, it)
log.info(it)
}
@@ -1001,7 +1096,8 @@ class CompileServiceImpl(
if (e.cause != null && e.cause != e) {
"\nCaused by: ${e.cause}\n ${e.cause!!.stackTrace.joinToString("\n ")}"
} else ""
}")
}"
)
throw e
}
}
@@ -1011,7 +1107,10 @@ class CompileServiceImpl(
(KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem as? CoreJarFileSystem)?.clearHandlersCache()
}
private inline fun<R> ifAlive(minAliveness: Aliveness = Aliveness.LastSession, body: () -> CompileService.CallResult<R>): CompileService.CallResult<R> = rwlock.read {
private inline fun <R> ifAlive(
minAliveness: Aliveness = Aliveness.LastSession,
body: () -> CompileService.CallResult<R>
): CompileService.CallResult<R> = rwlock.read {
ifAliveChecksImpl(minAliveness, body)
}
@@ -1022,7 +1121,10 @@ class CompileServiceImpl(
}
}
private inline fun<R> ifAliveExclusive(minAliveness: Aliveness = Aliveness.LastSession, body: () -> CompileService.CallResult<R>): CompileService.CallResult<R> = rwlock.write {
private inline fun <R> ifAliveExclusive(
minAliveness: Aliveness = Aliveness.LastSession,
body: () -> CompileService.CallResult<R>
): CompileService.CallResult<R> = rwlock.write {
ifAliveChecksImpl(minAliveness, body)
}
@@ -1033,7 +1135,10 @@ class CompileServiceImpl(
}
}
private inline fun<R> ifAliveChecksImpl(minAliveness: Aliveness = Aliveness.LastSession, body: () -> CompileService.CallResult<R>): CompileService.CallResult<R> {
private inline fun <R> ifAliveChecksImpl(
minAliveness: Aliveness = Aliveness.LastSession,
body: () -> CompileService.CallResult<R>
): CompileService.CallResult<R> {
val curState = state.alive.get()
return when {
curState < minAliveness.ordinal -> {
@@ -1043,8 +1148,7 @@ class CompileServiceImpl(
else -> {
try {
body()
}
catch (e: Throwable) {
} catch (e: Throwable) {
log.log(Level.SEVERE, "Exception", e)
CompileService.CallResult.Error(e.message ?: "unknown")
}
@@ -1052,31 +1156,34 @@ class CompileServiceImpl(
}
}
private inline fun<R> withValidClientOrSessionProxy(sessionId: Int,
body: (ClientOrSessionProxy<Any>?) -> CompileService.CallResult<R>
private inline fun <R> withValidClientOrSessionProxy(
sessionId: Int,
body: (ClientOrSessionProxy<Any>?) -> CompileService.CallResult<R>
): CompileService.CallResult<R> {
val session: ClientOrSessionProxy<Any>? =
if (sessionId == CompileService.NO_SESSION) null
else state.sessions[sessionId] ?: return CompileService.CallResult.Error("Unknown or invalid session $sessionId")
if (sessionId == CompileService.NO_SESSION) null
else state.sessions[sessionId] ?: return CompileService.CallResult.Error("Unknown or invalid session $sessionId")
try {
compilationsCounter.incrementAndGet()
return body(session)
}
finally {
} finally {
_lastUsedSeconds = nowSeconds()
}
}
private inline fun<R> withValidRepl(sessionId: Int, body: KotlinJvmReplService.() -> R): CompileService.CallResult<R> =
withValidClientOrSessionProxy(sessionId) { session ->
(session?.data as? KotlinJvmReplService?)?.let {
CompileService.CallResult.Good(it.body())
} ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
}
private inline fun <R> withValidRepl(sessionId: Int, body: KotlinJvmReplService.() -> R): CompileService.CallResult<R> =
withValidClientOrSessionProxy(sessionId) { session ->
(session?.data as? KotlinJvmReplService?)?.let {
CompileService.CallResult.Good(it.body())
} ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
}
@JvmName("withValidRepl1")
private inline fun<R> withValidRepl(sessionId: Int, body: KotlinJvmReplService.() -> CompileService.CallResult<R>): CompileService.CallResult<R> =
withValidClientOrSessionProxy(sessionId) { session ->
(session?.data as? KotlinJvmReplService?)?.body() ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
}
private inline fun <R> withValidRepl(
sessionId: Int,
body: KotlinJvmReplService.() -> CompileService.CallResult<R>
): CompileService.CallResult<R> =
withValidClientOrSessionProxy(sessionId) { session ->
(session?.data as? KotlinJvmReplService?)?.body() ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
}
}

View File

@@ -148,7 +148,7 @@ public class SingleAbstractMethodUtils {
// Otherwise android data binding can cause resolve re-entrance
// For details see KT-18687, KT-16149
// TODO: prevent resolve re-entrance on architecture level, or (alternatively) ask data binding owners not to do it
if (DescriptorUtilsKt.getFqNameSafe(klass).asString().equals("android.databinding.DataBindingComponent")) {
if (DescriptorUtilsKt.getFqNameSafe(klass).asString().endsWith(".databinding.DataBindingComponent")) {
return null;
}

View File

@@ -33,7 +33,10 @@ class IncrementalPackagePartProvider(
private val moduleMappings = storageManager.createLazyValue {
incrementalCaches.map { cache ->
ModuleMapping.loadModuleMapping(cache.getModuleMappingData(), "<incremental>", deserializationConfiguration)
ModuleMapping.loadModuleMapping(cache.getModuleMappingData(), "<incremental>", deserializationConfiguration) { version ->
// Incremental compilation should fall back to full rebuild if the minor component of the metadata version has changed
throw IllegalStateException("Version of the generated module should not be incompatible: $version")
}
}
}

View File

@@ -632,6 +632,7 @@ public interface Errors {
DiagnosticFactory0<PsiElement> OPTIONAL_EXPECTATION_NOT_ON_EXPECTED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE = DiagnosticFactory0.create(ERROR);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -289,6 +289,7 @@ public class DefaultErrorMessages {
MAP.put(OPTIONAL_EXPECTATION_NOT_ON_EXPECTED, "'@OptionalExpectation' can only be used on an expected annotation class");
MAP.put(OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY, "Declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry");
MAP.put(OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE, "Declaration annotated with '@OptionalExpectation' can only be used in common module sources");
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");

View File

@@ -247,7 +247,11 @@ class PSICallResolver(
tracingStrategy: TracingStrategy,
trace: BindingTrace
): ManyCandidates<D> {
val resolvedCalls = diagnostic.candidates.map { kotlinToResolvedCallTransformer.onlyTransform<D>(it.resolvedCall, emptyList()) }
val resolvedCalls = diagnostic.candidates.map {
kotlinToResolvedCallTransformer.onlyTransform<D>(
it.resolvedCall, it.diagnosticsFromResolutionParts + it.getSystem().diagnostics
)
}
if (diagnostic.candidates.areAllFailed()) {
if (diagnostic.candidates.areAllFailedWithInapplicableWrongReceiver()) {

View File

@@ -8,6 +8,11 @@ package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.getMultiTargetPlatform
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
class OptionalExpectationUsageChecker : ClassifierUsageChecker {
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
@@ -16,5 +21,11 @@ class OptionalExpectationUsageChecker : ClassifierUsageChecker {
if (!element.isUsageAsAnnotationOrImport()) {
context.trace.report(Errors.OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY.on(element))
}
val ktFile = element.containingFile as KtFile
// The first part is for the compiler, and the second one is for IDE
if (ktFile.isCommonSource != true && targetDescriptor.module.getMultiTargetPlatform() != MultiTargetPlatform.Common) {
context.trace.report(Errors.OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE.on(element))
}
}
}

View File

@@ -0,0 +1,16 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.multiplatform
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.UserDataProperty
/**
* Returns true if this file is a part of the common module in a multi-platform project.
* This setting only makes sense in the compiler, not in the IDE where sources from common modules are analyzed as common
*/
var KtFile.isCommonSource: Boolean? by UserDataProperty(Key.create("IS_COMMON_SOURCE"))

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.name.FqName
import java.io.File
class DirtyFilesContainer(
private val caches: IncrementalCachesManager<*>,
private val reporter: ICReporter
) {
private val myDirtyFiles = HashSet<File>()
fun toMutableList(): MutableList<File> =
ArrayList(myDirtyFiles)
fun add(files: Iterable<File>) {
val existingKotlinFiles = files.filter { it.isKotlinFile() }
if (existingKotlinFiles.isNotEmpty()) {
myDirtyFiles.addAll(existingKotlinFiles)
}
}
fun addByDirtySymbols(lookupSymbols: Collection<LookupSymbol>) {
if (lookupSymbols.isEmpty()) return
val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter)
add(dirtyFilesFromLookups)
}
fun addByDirtyClasses(dirtyClassesFqNames: Collection<FqName>) {
if (dirtyClassesFqNames.isEmpty()) return
val fqNamesWithSubtypes = dirtyClassesFqNames.flatMap {
withSubtypes(
it,
listOf(caches.platformCache)
)
}
val dirtyFilesFromFqNames =
mapClassesFqNamesToFiles(listOf(caches.platformCache), fqNamesWithSubtypes, reporter)
add(dirtyFilesFromFqNames)
}
}

View File

@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
import org.jetbrains.kotlin.incremental.storage.version.saveIfNeeded
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import java.io.File
@@ -37,10 +39,11 @@ abstract class IncrementalCompilerRunner<
Args : CommonCompilerArguments,
CacheManager : IncrementalCachesManager<*>
>(
workingDir: File,
cacheDirName: String,
protected val cacheVersions: List<CacheVersion>,
protected val reporter: ICReporter,
workingDir: File,
cacheDirName: String,
protected val cachesVersionManagers: List<CacheVersionManager>,
protected val reporter: ICReporter,
private val buildHistoryFile: File,
private val localStateDirs: Collection<File> = emptyList()
) {
@@ -117,11 +120,9 @@ abstract class IncrementalCompilerRunner<
protected abstract fun calculateSourcesToCompile(caches: CacheManager, changedFiles: ChangedFiles.Known, args: Args): CompilationMode
protected fun getDirtyFiles(changedFiles: ChangedFiles.Known): HashSet<File> {
val dirtyFiles = HashSet<File>(with(changedFiles) { modified.size + removed.size })
with(changedFiles) {
modified.asSequence() + removed.asSequence()
}.filterTo(dirtyFiles, File::isKotlinFile)
protected fun initDirtyFiles(dirtyFiles: DirtyFilesContainer, changedFiles: ChangedFiles.Known) {
dirtyFiles.add(changedFiles.modified)
dirtyFiles.add(changedFiles.removed)
if (dirtySourcesSinceLastTimeFile.exists()) {
val files = dirtySourcesSinceLastTimeFile.readLines().map(::File)
@@ -129,14 +130,12 @@ abstract class IncrementalCompilerRunner<
reporter.report { "Source files added since last compilation: ${reporter.pathsAsString(files)}" }
}
dirtyFiles.addAll(files)
dirtyFiles.add(files)
}
return dirtyFiles
}
protected sealed class CompilationMode {
class Incremental(val dirtyFiles: Set<File>) : CompilationMode()
class Incremental(val dirtyFiles: DirtyFilesContainer) : CompilationMode()
class Rebuild(getReason: () -> String = { "" }) : CompilationMode() {
val reason: String by lazy(getReason)
}
@@ -188,7 +187,7 @@ abstract class IncrementalCompilerRunner<
preBuildHook(args, compilationMode)
val dirtySources = when (compilationMode) {
is CompilationMode.Incremental -> ArrayList(compilationMode.dirtyFiles)
is CompilationMode.Incremental -> compilationMode.dirtyFiles.toMutableList()
is CompilationMode.Rebuild -> allKotlinSources.toMutableList()
}
@@ -271,7 +270,7 @@ abstract class IncrementalCompilerRunner<
processChangesAfterBuild(compilationMode, currentBuildInfo, dirtyData)
if (exitCode == ExitCode.OK) {
cacheVersions.forEach { it.saveIfNeeded() }
cachesVersionManagers.forEach { it.saveIfNeeded() }
}
return exitCode
@@ -303,11 +302,20 @@ abstract class IncrementalCompilerRunner<
open fun runWithNoDirtyKotlinSources(caches: CacheManager): Boolean = false
protected open fun processChangesAfterBuild(
private fun processChangesAfterBuild(
compilationMode: CompilationMode,
currentBuildInfo: BuildInfo,
dirtyData: DirtyData
) {
val prevDiffs = BuildDiffsStorage.readFromFile(buildHistoryFile, reporter)?.buildDiffs ?: emptyList()
val newDiff = if (compilationMode is CompilationMode.Incremental) {
BuildDifference(currentBuildInfo.startTS, true, dirtyData)
} else {
val emptyDirtyData = DirtyData()
BuildDifference(currentBuildInfo.startTS, false, emptyDirtyData)
}
BuildDiffsStorage.writeToFile(buildHistoryFile, BuildDiffsStorage(prevDiffs + newDiff), reporter)
}
companion object {

View File

@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.incremental
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.build.GeneratedFile
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
@@ -27,7 +26,9 @@ import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.js.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
import org.jetbrains.kotlin.incremental.multiproject.EmptyModulesApiHistory
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
import java.io.File
fun makeJsIncrementally(
@@ -37,13 +38,17 @@ fun makeJsIncrementally(
messageCollector: MessageCollector = MessageCollector.NONE,
reporter: ICReporter = EmptyICReporter
) {
val isIncremental = IncrementalCompilation.isEnabledForJs()
val versions = commonCacheVersions(cachesDir, isIncremental) + standaloneCacheVersion(cachesDir, isIncremental)
val allKotlinFiles = sourceRoots.asSequence().flatMap { it.walk() }
.filter { it.isFile && it.extension.equals("kt", ignoreCase = true) }.toList()
val buildHistoryFile = File(cachesDir, "build-history.bin")
withJsIC {
val compiler = IncrementalJsCompilerRunner(cachesDir, versions, reporter)
val versions = commonCacheVersionsManagers(cachesDir, true) + standaloneCacheVersionManager(cachesDir, true)
val compiler = IncrementalJsCompilerRunner(
cachesDir, versions, reporter,
buildHistoryFile = buildHistoryFile,
modulesApiHistory = EmptyModulesApiHistory)
compiler.compile(allKotlinFiles, args, messageCollector, providedChangedFiles = null)
}
}
@@ -60,14 +65,17 @@ inline fun <R> withJsIC(fn: () -> R): R {
}
class IncrementalJsCompilerRunner(
workingDir: File,
cacheVersions: List<CacheVersion>,
reporter: ICReporter
workingDir: File,
cachesVersionManagers: List<CacheVersionManager>,
reporter: ICReporter,
buildHistoryFile: File,
private val modulesApiHistory: ModulesApiHistory
) : IncrementalCompilerRunner<K2JSCompilerArguments, IncrementalJsCachesManager>(
workingDir,
"caches-js",
cacheVersions,
reporter
workingDir,
"caches-js",
cachesVersionManagers,
reporter,
buildHistoryFile = buildHistoryFile
) {
override fun isICEnabled(): Boolean =
IncrementalCompilation.isEnabledForJs()
@@ -79,39 +87,31 @@ class IncrementalJsCompilerRunner(
File(args.outputFile).parentFile
override fun calculateSourcesToCompile(caches: IncrementalJsCachesManager, changedFiles: ChangedFiles.Known, args: K2JSCompilerArguments): CompilationMode {
if (BuildInfo.read(lastBuildInfoFile) == null) return CompilationMode.Rebuild { "No information on previous build" }
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
?: return CompilationMode.Rebuild { "No information on previous build" }
val libs = (args.libraries ?: "").split(File.pathSeparator).mapTo(HashSet()) { File(it) }
val libsDirs = libs.filter { it.isDirectory }
val dirtyFiles = DirtyFilesContainer(caches, reporter)
initDirtyFiles(dirtyFiles, changedFiles)
val changedLib = changedFiles.allAsSequence.find { it in libs }
?: changedFiles.allAsSequence.find { changedFile ->
libsDirs.any { libDir -> FileUtil.isAncestor(libDir, changedFile, true) }
}
val libs = (args.libraries ?: "").split(File.pathSeparator).map { File(it) }
val classpathChanges = getClasspathChanges(libs, changedFiles, lastBuildInfo, modulesApiHistory, reporter)
if (changedLib != null) return CompilationMode.Rebuild { "Library has been changed: $changedLib" }
val dirtyFiles = getDirtyFiles(changedFiles)
// todo: unify with JVM calculateSourcesToCompile
fun markDirtyBy(lookupSymbols: Collection<LookupSymbol>) {
if (lookupSymbols.isEmpty()) return
val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter)
dirtyFiles.addAll(dirtyFilesFromLookups)
@Suppress("UNUSED_VARIABLE") // for sealed when
val unused = when (classpathChanges) {
is ChangesEither.Unknown -> return CompilationMode.Rebuild {
// todo: we can recompile all files incrementally (not cleaning caches), so rebuild won't propagate
"Could not get classpath's changes${classpathChanges.reason?.let { ": $it" }}"
}
is ChangesEither.Known -> {
dirtyFiles.addByDirtySymbols(classpathChanges.lookupSymbols)
dirtyFiles.addByDirtyClasses(classpathChanges.fqNames)
}
}
fun markDirtyBy(dirtyClassesFqNames: Collection<FqName>) {
if (dirtyClassesFqNames.isEmpty()) return
val fqNamesWithSubtypes = dirtyClassesFqNames.flatMap { withSubtypes(it, listOf(caches.platformCache)) }
val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.platformCache), fqNamesWithSubtypes, reporter)
dirtyFiles.addAll(dirtyFilesFromFqNames)
}
val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles)
markDirtyBy(removedClassesChanges.dirtyLookupSymbols)
markDirtyBy(removedClassesChanges.dirtyClassesFqNames)
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
return CompilationMode.Incremental(dirtyFiles)
}

View File

@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.multiproject.EmptyModulesApiHistory
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
import org.jetbrains.kotlin.incremental.util.Either
import org.jetbrains.kotlin.load.java.JavaClassesTracker
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -56,9 +57,6 @@ fun makeIncrementally(
messageCollector: MessageCollector = MessageCollector.NONE,
reporter: ICReporter = EmptyICReporter
) {
val isIncremental = IncrementalCompilation.isEnabledForJvm()
val versions = commonCacheVersions(cachesDir, isIncremental) + standaloneCacheVersion(cachesDir, isIncremental)
val kotlinExtensions = listOf("kt", "kts")
val allExtensions = kotlinExtensions + listOf("java")
val rootsWalk = sourceRoots.asSequence().flatMap { it.walk() }
@@ -67,6 +65,8 @@ fun makeIncrementally(
val buildHistoryFile = File(cachesDir, "build-history.bin")
withIC {
val versions = commonCacheVersionsManagers(cachesDir, true) + standaloneCacheVersionManager(cachesDir, true)
val compiler = IncrementalJvmCompilerRunner(
cachesDir,
sourceRoots.map { JvmSourceRoot(it, null) }.toSet(),
@@ -99,20 +99,21 @@ inline fun <R> withIC(enabled: Boolean = true, fn: ()->R): R {
}
class IncrementalJvmCompilerRunner(
workingDir: File,
private val javaSourceRoots: Set<JvmSourceRoot>,
cacheVersions: List<CacheVersion>,
reporter: ICReporter,
private val usePreciseJavaTracking: Boolean,
private val buildHistoryFile: File,
localStateDirs: Collection<File>,
private val modulesApiHistory: ModulesApiHistory
workingDir: File,
private val javaSourceRoots: Set<JvmSourceRoot>,
cachesVersionManagers: List<CacheVersionManager>,
reporter: ICReporter,
private val usePreciseJavaTracking: Boolean,
buildHistoryFile: File,
localStateDirs: Collection<File>,
private val modulesApiHistory: ModulesApiHistory
) : IncrementalCompilerRunner<K2JVMCompilerArguments, IncrementalJvmCachesManager>(
workingDir,
"caches-jvm",
cacheVersions,
reporter,
localStateDirs = localStateDirs
workingDir,
"caches-jvm",
cachesVersionManagers,
reporter,
localStateDirs = localStateDirs,
buildHistoryFile = buildHistoryFile
) {
override fun isICEnabled(): Boolean =
IncrementalCompilation.isEnabledForJvm()
@@ -144,27 +145,13 @@ class IncrementalJvmCompilerRunner(
changedFiles: ChangedFiles.Known,
args: K2JVMCompilerArguments
): CompilationMode {
val dirtyFiles = getDirtyFiles(changedFiles)
fun markDirtyBy(lookupSymbols: Collection<LookupSymbol>) {
if (lookupSymbols.isEmpty()) return
val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter)
dirtyFiles.addAll(dirtyFilesFromLookups)
}
fun markDirtyBy(dirtyClassesFqNames: Collection<FqName>) {
if (dirtyClassesFqNames.isEmpty()) return
val fqNamesWithSubtypes = dirtyClassesFqNames.flatMap { withSubtypes(it, listOf(caches.platformCache)) }
val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.platformCache), fqNamesWithSubtypes, reporter)
dirtyFiles.addAll(dirtyFilesFromFqNames)
}
val dirtyFiles = DirtyFilesContainer(caches, reporter)
initDirtyFiles(dirtyFiles, changedFiles)
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) ?: return CompilationMode.Rebuild { "No information on previous build" }
reporter.report { "Last Kotlin Build info -- $lastBuildInfo" }
val classpathChanges = getClasspathChanges(args.classpathAsList, changedFiles, lastBuildInfo)
val classpathChanges = getClasspathChanges(args.classpathAsList, changedFiles, lastBuildInfo, modulesApiHistory, reporter)
@Suppress("UNUSED_VARIABLE") // for sealed when
val unused = when (classpathChanges) {
@@ -173,8 +160,8 @@ class IncrementalJvmCompilerRunner(
"Could not get classpath's changes${classpathChanges.reason?.let { ": $it" }}"
}
is ChangesEither.Known -> {
markDirtyBy(classpathChanges.lookupSymbols)
markDirtyBy(classpathChanges.fqNames)
dirtyFiles.addByDirtySymbols(classpathChanges.lookupSymbols)
dirtyFiles.addByDirtyClasses(classpathChanges.fqNames)
}
}
@@ -184,9 +171,8 @@ class IncrementalJvmCompilerRunner(
is ChangesEither.Known -> javaFilesChanges.lookupSymbols
is ChangesEither.Unknown -> return CompilationMode.Rebuild { "Could not get changes for java files" }
}
markDirtyBy(affectedJavaSymbols)
}
else {
dirtyFiles.addByDirtySymbols(affectedJavaSymbols)
} else {
if (!processChangedJava(changedFiles, caches)) {
return CompilationMode.Rebuild { "Could not get changes for java files" }
}
@@ -195,9 +181,9 @@ class IncrementalJvmCompilerRunner(
val androidLayoutChanges = processLookupSymbolsForAndroidLayouts(changedFiles)
val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles)
markDirtyBy(androidLayoutChanges)
markDirtyBy(removedClassesChanges.dirtyLookupSymbols)
markDirtyBy(removedClassesChanges.dirtyClassesFqNames)
dirtyFiles.addByDirtySymbols(androidLayoutChanges)
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
return CompilationMode.Incremental(dirtyFiles)
}
@@ -257,58 +243,6 @@ class IncrementalJvmCompilerRunner(
return result
}
private fun getClasspathChanges(
classpath: List<File>,
changedFiles: ChangedFiles.Known,
lastBuildInfo: BuildInfo
): ChangesEither {
val classpathSet = HashSet<File>()
for (file in classpath) {
when {
file.isFile -> classpathSet.add(file)
file.isDirectory -> file.walk().filterTo(classpathSet) { it.isFile }
}
}
val modifiedClasspath = changedFiles.modified.filterTo(HashSet()) { it in classpathSet }
val removedClasspath = changedFiles.removed.filterTo(HashSet()) { it in classpathSet }
// todo: removed classes could be processed normally
if (removedClasspath.isNotEmpty()) return ChangesEither.Unknown("Some files are removed from classpath $removedClasspath")
if (modifiedClasspath.isEmpty()) return ChangesEither.Known()
val lastBuildTS = lastBuildInfo.startTS
val symbols = HashSet<LookupSymbol>()
val fqNames = HashSet<FqName>()
val historyFilesEither = modulesApiHistory.historyFilesForChangedFiles(modifiedClasspath)
val historyFiles = when (historyFilesEither) {
is Either.Success<Set<File>> -> historyFilesEither.value
is Either.Error -> return ChangesEither.Unknown(historyFilesEither.reason)
}
for (historyFile in historyFiles) {
val allBuilds = BuildDiffsStorage.readDiffsFromFile(historyFile, reporter = reporter)
?: return ChangesEither.Unknown("Could not read diffs from $historyFile")
val (knownBuilds, newBuilds) = allBuilds.partition { it.ts <= lastBuildTS }
if (knownBuilds.isEmpty()) {
return ChangesEither.Unknown("No previously known builds for $historyFile")
}
for (buildDiff in newBuilds) {
if (!buildDiff.isIncremental) return ChangesEither.Unknown("Non-incremental build from dependency $historyFile")
val dirtyData = buildDiff.dirtyData
symbols.addAll(dirtyData.dirtyLookupSymbols)
fqNames.addAll(dirtyData.dirtyClassesFqNames)
}
}
return ChangesEither.Known(symbols, fqNames)
}
override fun preBuildHook(args: K2JVMCompilerArguments, compilationMode: CompilationMode) {
if (compilationMode is CompilationMode.Incremental) {
val destinationDir = args.destinationAsFile
@@ -377,22 +311,6 @@ class IncrementalJvmCompilerRunner(
override fun additionalDirtyLookupSymbols(): Iterable<LookupSymbol> =
javaFilesProcessor?.allChangedSymbols ?: emptyList()
override fun processChangesAfterBuild(
compilationMode: CompilationMode,
currentBuildInfo: BuildInfo,
dirtyData: DirtyData
) {
val prevDiffs = BuildDiffsStorage.readFromFile(buildHistoryFile, reporter)?.buildDiffs ?: emptyList()
val newDiff = if (compilationMode is CompilationMode.Incremental) {
BuildDifference(currentBuildInfo.startTS, true, dirtyData)
} else {
val emptyDirtyData = DirtyData()
BuildDifference(currentBuildInfo.startTS, false, emptyDirtyData)
}
BuildDiffsStorage.writeToFile(buildHistoryFile, BuildDiffsStorage(prevDiffs + newDiff), reporter)
}
override fun makeServices(
args: K2JVMCompilerArguments,
lookupTracker: LookupTracker,
@@ -422,13 +340,16 @@ class IncrementalJvmCompilerRunner(
val compiler = K2JVMCompiler()
val outputDir = args.destinationAsFile
val classpath = args.classpathAsList
val moduleFile = makeModuleFile(args.moduleName!!,
isTest = false,
outputDir = outputDir,
sourcesToCompile = sourcesToCompile,
javaSourceRoots = javaSourceRoots,
classpath = classpath,
friendDirs = listOf())
val moduleFile = makeModuleFile(
args.moduleName!!,
isTest = false,
outputDir = outputDir,
sourcesToCompile = sourcesToCompile,
commonSources = args.commonSources?.map(::File).orEmpty(),
javaSourceRoots = javaSourceRoots,
classpath = classpath,
friendDirs = listOf()
)
val destination = args.destination
args.destination = null
args.buildFile = moduleFile.absolutePath

View File

@@ -16,21 +16,25 @@
package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
import org.jetbrains.kotlin.incremental.storage.version.localCacheVersionManager
import org.jetbrains.kotlin.incremental.storage.version.lookupsCacheVersionManager
import java.io.File
internal const val STANDALONE_CACHE_VERSION = 2
internal const val STANDALONE_VERSION_FILE_NAME = "standalone-ic-format-version.txt"
fun standaloneCacheVersion(dataRoot: File, enabled: Boolean): CacheVersion =
customCacheVersion(STANDALONE_CACHE_VERSION, STANDALONE_VERSION_FILE_NAME, dataRoot, enabled)
fun standaloneCacheVersionManager(dataRoot: File, enabled: Boolean): CacheVersionManager =
customCacheVersionManager(STANDALONE_CACHE_VERSION, STANDALONE_VERSION_FILE_NAME, dataRoot, enabled)
fun customCacheVersion(version: Int, fileName: String, dataRoot: File, enabled: Boolean): CacheVersion =
CacheVersion(ownVersion = version,
versionFile = File(dataRoot, fileName),
whenVersionChanged = CacheVersion.Action.REBUILD_ALL_KOTLIN,
whenTurnedOn = CacheVersion.Action.REBUILD_ALL_KOTLIN,
whenTurnedOff = CacheVersion.Action.REBUILD_ALL_KOTLIN,
isEnabled = enabled)
fun customCacheVersionManager(version: Int, fileName: String, dataRoot: File, enabled: Boolean): CacheVersionManager =
CacheVersionManager(
File(dataRoot, fileName),
if (enabled) version else null
)
fun commonCacheVersions(cachesDir: File, enabled: Boolean): List<CacheVersion> =
listOf(normalCacheVersion(cachesDir, enabled), dataContainerCacheVersion(cachesDir, enabled))
fun commonCacheVersionsManagers(cachesDir: File, enabled: Boolean): List<CacheVersionManager> =
listOf(
localCacheVersionManager(cachesDir, enabled),
lookupsCacheVersionManager(cachesDir, enabled)
)

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
import org.jetbrains.kotlin.incremental.util.Either
import org.jetbrains.kotlin.name.FqName
import java.io.File
internal fun getClasspathChanges(
classpath: List<File>,
changedFiles: ChangedFiles.Known,
lastBuildInfo: BuildInfo,
modulesApiHistory: ModulesApiHistory,
reporter: ICReporter?
): ChangesEither {
val classpathSet = HashSet<File>()
for (file in classpath) {
when {
file.isFile -> classpathSet.add(file)
file.isDirectory -> file.walk().filterTo(classpathSet) { it.isFile }
}
}
val modifiedClasspath = changedFiles.modified.filterTo(HashSet()) { it in classpathSet }
val removedClasspath = changedFiles.removed.filterTo(HashSet()) { it in classpathSet }
// todo: removed classes could be processed normally
if (removedClasspath.isNotEmpty()) return ChangesEither.Unknown("Some files are removed from classpath $removedClasspath")
if (modifiedClasspath.isEmpty()) return ChangesEither.Known()
val lastBuildTS = lastBuildInfo.startTS
val symbols = HashSet<LookupSymbol>()
val fqNames = HashSet<FqName>()
val historyFilesEither = modulesApiHistory.historyFilesForChangedFiles(modifiedClasspath)
val historyFiles = when (historyFilesEither) {
is Either.Success<Set<File>> -> historyFilesEither.value
is Either.Error -> return ChangesEither.Unknown(historyFilesEither.reason)
}
for (historyFile in historyFiles) {
val allBuilds = BuildDiffsStorage.readDiffsFromFile(historyFile, reporter = reporter)
?: return ChangesEither.Unknown("Could not read diffs from $historyFile")
val (knownBuilds, newBuilds) = allBuilds.partition { it.ts <= lastBuildTS }
if (knownBuilds.isEmpty()) {
return ChangesEither.Unknown("No previously known builds for $historyFile")
}
for (buildDiff in newBuilds) {
if (!buildDiff.isIncremental) return ChangesEither.Unknown("Non-incremental build from dependency $historyFile")
val dirtyData = buildDiff.dirtyData
symbols.addAll(dirtyData.dirtyLookupSymbols)
fqNames.addAll(dirtyData.dirtyClassesFqNames)
}
}
return ChangesEither.Known(symbols, fqNames)
}

View File

@@ -22,7 +22,7 @@ object EmptyModulesApiHistory : ModulesApiHistory {
Either.Error("Multi-module IC is not configured")
}
open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory {
abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory {
protected val projectRootPath: Path = Paths.get(modulesInfo.projectRoot.absolutePath)
private val dirToHistoryFileCache = HashMap<File, Set<File>>()
@@ -86,7 +86,11 @@ open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo
return Either.Success(history)
}
protected open fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
protected abstract fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>>
}
class ModulesApiHistoryJvm(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
override fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
val classListFile = modulesInfo.jarToClassListFile[jar] ?: return Either.Error("Unknown jar: $jar")
if (!classListFile.isFile) return Either.Error("Class list file does not exist $classListFile")
@@ -109,7 +113,18 @@ open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo
}
}
class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryJvm(modulesInfo) {
class ModulesApiHistoryJs(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
override fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
val moduleEntry = modulesInfo.jarToModule[jar]
return when {
moduleEntry != null -> Either.Success(setOf(moduleEntry.buildHistoryFile))
else -> Either.Error("No module is found for jar $jar")
}
}
}
class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
private val delegate = ModulesApiHistoryJvm(modulesInfo)
override fun historyFilesForChangedFiles(changedFiles: Set<File>): Either<Set<File>> {

View File

@@ -361,6 +361,11 @@ public class IncrementalJsCompilerRunnerTestGenerated extends AbstractIncrementa
runTest("jps-plugin/testData/incremental/pureKotlin/ourClassReferenced/");
}
@TestMetadata("overloadInlined")
public void testOverloadInlined() throws Exception {
runTest("jps-plugin/testData/incremental/pureKotlin/overloadInlined/");
}
@TestMetadata("packageConstantChanged")
public void testPackageConstantChanged() throws Exception {
runTest("jps-plugin/testData/incremental/pureKotlin/packageConstantChanged/");
@@ -551,6 +556,11 @@ public class IncrementalJsCompilerRunnerTestGenerated extends AbstractIncrementa
runTest("jps-plugin/testData/incremental/pureKotlin/returnTypeChanged/");
}
@TestMetadata("secondaryConstructorInlined")
public void testSecondaryConstructorInlined() throws Exception {
runTest("jps-plugin/testData/incremental/pureKotlin/secondaryConstructorInlined/");
}
@TestMetadata("simpleClassDependency")
public void testSimpleClassDependency() throws Exception {
runTest("jps-plugin/testData/incremental/pureKotlin/simpleClassDependency/");

View File

@@ -361,6 +361,11 @@ public class IncrementalJvmCompilerRunnerTestGenerated extends AbstractIncrement
runTest("jps-plugin/testData/incremental/pureKotlin/ourClassReferenced/");
}
@TestMetadata("overloadInlined")
public void testOverloadInlined() throws Exception {
runTest("jps-plugin/testData/incremental/pureKotlin/overloadInlined/");
}
@TestMetadata("packageConstantChanged")
public void testPackageConstantChanged() throws Exception {
runTest("jps-plugin/testData/incremental/pureKotlin/packageConstantChanged/");
@@ -551,6 +556,11 @@ public class IncrementalJvmCompilerRunnerTestGenerated extends AbstractIncrement
runTest("jps-plugin/testData/incremental/pureKotlin/returnTypeChanged/");
}
@TestMetadata("secondaryConstructorInlined")
public void testSecondaryConstructorInlined() throws Exception {
runTest("jps-plugin/testData/incremental/pureKotlin/secondaryConstructorInlined/");
}
@TestMetadata("simpleClassDependency")
public void testSimpleClassDependency() throws Exception {
runTest("jps-plugin/testData/incremental/pureKotlin/simpleClassDependency/");

View File

@@ -58,7 +58,8 @@ class ModulesApiHistoryAndroidTest {
projectRoot = projectRoot,
dirToModule = mapOf(appKotlinDestination to appEntry, libKotlinDestination to libEntry),
nameToModules = mapOf("app" to setOf(appEntry), "lib" to setOf(libEntry)),
jarToClassListFile = mapOf()
jarToClassListFile = mapOf(),
jarToModule = mapOf()
)
androidHistory = ModulesApiHistoryAndroid(info)

View File

@@ -716,6 +716,9 @@ public final class String : kotlin.Comparable<kotlin.String>, kotlin.CharSequenc
public open override /*1*/ fun compareTo(/*0*/ other: kotlin.String): kotlin.Int
public open override /*1*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
public final operator fun plus(/*0*/ other: kotlin.Any?): kotlin.String
@kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public open fun strip(): kotlin.String!
@kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public open fun stripLeading(): kotlin.String!
@kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public open fun stripTrailing(): kotlin.String!
public open override /*1*/ fun subSequence(/*0*/ startIndex: kotlin.Int, /*1*/ endIndex: kotlin.Int): kotlin.CharSequence
public companion object Companion {

View File

@@ -4,6 +4,8 @@ where advanced options include:
-Xfriend-modules-disabled Disable internal declaration export
-Xtyped-arrays Translate primitive arrays to JS typed arrays
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
-Xcommon-sources=<path> Sources of the common module that need to be compiled together with this module in the multi-platform mode.
Should be a subset of sources passed as free arguments
-Xcoroutines={enable|warn|error}
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
-Xdump-perf=<path> Dump detailed performance statistics to the specified file

View File

@@ -60,6 +60,8 @@ where advanced options include:
-Xuse-old-class-files-reading Use old class files reading implementation (may slow down the build and should be used in case of problems with the new implementation)
-Xuse-type-table Use type table in metadata serialization
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
-Xcommon-sources=<path> Sources of the common module that need to be compiled together with this module in the multi-platform mode.
Should be a subset of sources passed as free arguments
-Xcoroutines={enable|warn|error}
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
-Xdump-perf=<path> Dump detailed performance statistics to the specified file

View File

@@ -1,4 +1,5 @@
error: incompatible classes were found in dependencies. Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors
compiler/testData/cli/jvm/wrongAbiVersionLib/bin/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$.
compiler/testData/cli/jvm/wrongAbiVersion.kt:3:12: error: class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$.
The class is loaded from $TESTDATA_DIR$/wrongAbiVersionLib/bin/ClassWithWrongAbiVersion.class
fun foo(x: ClassWithWrongAbiVersion) {
@@ -10,4 +11,4 @@ compiler/testData/cli/jvm/wrongAbiVersion.kt:6:7: error: unresolved reference. N
public fun String.replaceIndent(newIndent: String = ...): String defined in kotlin.text
1.replaceIndent(2, 3)
^
COMPILATION_ERROR
COMPILATION_ERROR

View File

@@ -1,5 +0,0 @@
$TESTDATA_DIR$/wrongAbiVersionNoErrors.kt
-classpath
$TESTDATA_DIR$/wrongAbiVersionLib/bin
-d
$TEMP_DIR$

View File

@@ -1,7 +0,0 @@
// This should not compile because there are usages of symbols with the wrong ABI version!
import wrong.ClassWithInnerLambda
fun happy(): Int {
return 2 + 2
}

View File

@@ -1,6 +0,0 @@
error: incompatible classes were found in dependencies. Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors
compiler/testData/cli/jvm/wrongAbiVersionNoErrors.kt:3:14: error: class 'wrong.ClassWithInnerLambda' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$.
The class is loaded from $TESTDATA_DIR$/wrongAbiVersionLib/bin/wrong/ClassWithInnerLambda.class
import wrong.ClassWithInnerLambda
^
COMPILATION_ERROR

View File

@@ -23,6 +23,8 @@ actual annotation class A(actual val x: Int)
// MODULE: main(library)
// FILE: main.kt
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
package usage
import a.A

View File

@@ -9,6 +9,8 @@ expect annotation class Anno(val s: String)
// FILE: jvm.kt
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
import java.lang.reflect.AnnotatedElement
@Anno("Foo")

View File

@@ -0,0 +1,17 @@
// FILE: 1.kt
var result = ""
inline var apx:Int
get() = 0
set(value) { result = if (value == 1) "OK" else "fail" }
// FILE: 2.kt
fun test(s: Int?) {
apx = s!!
}
fun box() : String {
test(1)
return result
}

View File

@@ -3,6 +3,8 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
@OptionalExpectation
expect annotation class Anno(val s: String)

View File

@@ -1,4 +1,5 @@
error: incompatible classes were found in dependencies. Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors
$TMP_DIR$/library-after.jar!/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:5:16: error: class 'a.A' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
The class is loaded from $TMP_DIR$/library-after.jar!/a/A.class
fun baz(param: A, nested: A.Nested) {

View File

@@ -1,3 +1,4 @@
$TMP_DIR$/library-after.jar!/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMetadata/source.kt:12:13: error: unresolved reference: foo
val x = foo()
^
@@ -10,4 +11,4 @@ compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMeta
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMetadata/source.kt:15:12: error: unresolved reference: TA
val z: TA = ""
^
COMPILATION_ERROR
COMPILATION_ERROR

View File

@@ -1,3 +1,4 @@
$TMP_DIR$/library-after.jar!/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMetadata2/source.kt:12:13: error: unresolved reference: foo
val x = foo()
^
@@ -10,4 +11,4 @@ compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMeta
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMetadata2/source.kt:15:12: error: unresolved reference: TA
val z: TA = ""
^
COMPILATION_ERROR
COMPILATION_ERROR

View File

@@ -14,6 +14,9 @@ expect annotation class B(val s: String)
actual annotation class A(actual val x: Int)
// FILE: B.kt
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
import a.A
import a.B
import java.lang.reflect.Modifier

View File

@@ -0,0 +1,11 @@
// !CHECK_TYPE
// SKIP_TXT
fun foo(s: String) {
s.isBlank()
s.lines().checkType { _<List<String>>() }
s.repeat(1)
// We don't have `strip` extension, so leave it for a while in gray list
s.<!DEPRECATION!>strip<!>()
}

View File

@@ -0,0 +1,19 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_VARIABLE
import kotlin.reflect.KProperty
object Foo
object Bar
object Baz
operator fun Foo.provideDelegate(receiver: Any?, property: KProperty<*>) = this
operator fun Bar.provideDelegate(receiver: Any?, property: KProperty<*>) = this
operator fun Foo.getValue(nothing: Any?, property: KProperty<*>): Any = TODO()
operator fun Bar.getValue(nothing: Any?, property: KProperty<*>): Any = TODO()
operator fun Baz.getValue(nothing: Any?, property: KProperty<*>): Any = TODO()
fun test() {
val bar by Baz
}

View File

@@ -0,0 +1,29 @@
package
public fun test(): kotlin.Unit
public operator fun Bar.getValue(/*0*/ nothing: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.Any
public operator fun Baz.getValue(/*0*/ nothing: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.Any
public operator fun Foo.getValue(/*0*/ nothing: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.Any
public operator fun Bar.provideDelegate(/*0*/ receiver: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): Bar
public operator fun Foo.provideDelegate(/*0*/ receiver: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): Foo
public object Bar {
private constructor Bar()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public object Baz {
private constructor Baz()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public object Foo {
private constructor Foo()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}

View File

@@ -1,10 +1,9 @@
// !WITH_NEW_INFERENCE
// !DIAGNOSTICS: -UNUSED_PARAMETER
import kotlin.reflect.KProperty
class A {
val c: Int by <!NI;DELEGATE_SPECIAL_FUNCTION_AMBIGUITY, OI;DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>Delegate()<!>
val c: Int by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>Delegate()<!>
}
class Delegate {

View File

@@ -0,0 +1,9 @@
const val myPi = kotlin.math.PI
annotation class Anno(val d: Double)
@Anno(kotlin.math.PI)
fun f() {}
@Anno(myPi)
fun g() {}

View File

@@ -0,0 +1,13 @@
package
public const val myPi: kotlin.Double = 3.141592653589793.toDouble()
@Anno(d = 3.141592653589793.toDouble()) public fun f(): kotlin.Unit
@Anno(d = 3.141592653589793.toDouble()) public fun g(): kotlin.Unit
public final annotation class Anno : kotlin.Annotation {
public constructor Anno(/*0*/ d: kotlin.Double)
public final val d: kotlin.Double
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}

Binary file not shown.

View File

@@ -39,11 +39,20 @@ compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:19:20:
@InOtherAnnotation(A())
^
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:1:24: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
fun useInReturnType(): A? = null
^
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:1:24: error: declaration annotated with '@OptionalExpectation' can only be used in common module sources
fun useInReturnType(): A? = null
^
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:3:43: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
annotation class AnotherAnnotation(val a: A)
^
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:3:43: error: declaration annotated with '@OptionalExpectation' can only be used in common module sources
annotation class AnotherAnnotation(val a: A)
^
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:5:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
@AnotherAnnotation(A())
^
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:5:20: error: declaration annotated with '@OptionalExpectation' can only be used in common module sources
@AnotherAnnotation(A())
^

View File

@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
@@ -610,11 +611,11 @@ public class KotlinTestUtils {
}
public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
List<String> paths = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (paths.isEmpty()) return;
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (roots.isEmpty()) return;
List<KtFile> ktFiles = new ArrayList<>();
for (String path : paths) {
File file = new File(path);
for (KotlinSourceRoot root : roots) {
File file = new File(root.getPath());
if (file.isFile()) {
ktFiles.add(loadJetFile(environment.getProject(), file));
}

View File

@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
@@ -609,11 +610,11 @@ public class KotlinTestUtils {
}
public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
List<String> paths = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (paths.isEmpty()) return;
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (roots.isEmpty()) return;
List<KtFile> ktFiles = new ArrayList<>();
for (String path : paths) {
File file = new File(path);
for (KotlinSourceRoot root : roots) {
File file = new File(root.getPath());
if (file.isFile()) {
ktFiles.add(loadJetFile(environment.getProject(), file));
}

View File

@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
@@ -609,11 +610,11 @@ public class KotlinTestUtils {
}
public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
List<String> paths = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (paths.isEmpty()) return;
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (roots.isEmpty()) return;
List<KtFile> ktFiles = new ArrayList<>();
for (String path : paths) {
File file = new File(path);
for (KotlinSourceRoot root : roots) {
File file = new File(root.getPath());
if (file.isFile()) {
ktFiles.add(loadJetFile(environment.getProject(), file));
}

View File

@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
@@ -609,11 +610,11 @@ public class KotlinTestUtils {
}
public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
List<String> paths = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (paths.isEmpty()) return;
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (roots.isEmpty()) return;
List<KtFile> ktFiles = new ArrayList<>();
for (String path : paths) {
File file = new File(path);
for (KotlinSourceRoot root : roots) {
File file = new File(root.getPath());
if (file.isFile()) {
ktFiles.add(loadJetFile(environment.getProject(), file));
}

View File

@@ -20,6 +20,7 @@ public enum TestJdkKind {
MOCK_JDK,
// Differs from common mock JDK only by one additional 'nonExistingMethod' in Collection and constructor from Double in Throwable
// It's needed to test the way we load additional built-ins members that neither in black nor white lists
// Also, now it contains new methods in java.lang.String introduced in JDK 11
MODIFIED_MOCK_JDK,
// JDK found at $JDK_16
FULL_JDK_6,

View File

@@ -57,8 +57,13 @@ class AdditionalBuiltInsMembersSignatureListsTest : KotlinTestWithEnvironment()
val scope = classDescriptor.unsubstitutedMemberScope
val lateJdkSignatures = LATE_JDK_SIGNATURES[internalName] ?: emptySet()
jvmDescriptors.forEach {
jvmDescriptor ->
if (jvmDescriptor in lateJdkSignatures) return@forEach
val stringName = jvmDescriptor.split("(")[0]
val functions =
if (stringName == "<init>")
@@ -72,4 +77,8 @@ class AdditionalBuiltInsMembersSignatureListsTest : KotlinTestWithEnvironment()
}
}
}
private val LATE_JDK_SIGNATURES = mapOf(
"java/lang/String" to setOf("isBlank()Z", "lines()Ljava/util/stream/Stream;", "repeat(I)Ljava/lang/String;")
)
}

View File

@@ -29,6 +29,11 @@ public class DiagnosticsWithModifiedMockJdkTestGenerated extends AbstractDiagnos
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testWithModifiedMockJdk"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("newStringMethods.kt")
public void testNewStringMethods() throws Exception {
runTest("compiler/testData/diagnostics/testWithModifiedMockJdk/newStringMethods.kt");
}
@TestMetadata("notConsideredMethod.kt")
public void testNotConsideredMethod() throws Exception {
runTest("compiler/testData/diagnostics/testWithModifiedMockJdk/notConsideredMethod.kt");

View File

@@ -5683,6 +5683,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/noOperatorModifierOnProvideDelegate.kt");
}
@TestMetadata("overloadResolutionForSeveralProvideDelegates.kt")
public void testOverloadResolutionForSeveralProvideDelegates() throws Exception {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/overloadResolutionForSeveralProvideDelegates.kt");
}
@TestMetadata("provideDelegateOperatorDeclaration.kt")
public void testProvideDelegateOperatorDeclaration() throws Exception {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateOperatorDeclaration.kt");

View File

@@ -2765,6 +2765,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt2082.kt");
}
@TestMetadata("kt26806.kt")
public void testKt26806() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt26806.kt");
}
@TestMetadata("kt9345.kt")
public void testKt9345() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt9345.kt");

View File

@@ -2765,6 +2765,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt2082.kt");
}
@TestMetadata("kt26806.kt")
public void testKt26806() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt26806.kt");
}
@TestMetadata("kt9345.kt")
public void testKt9345() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt9345.kt");

View File

@@ -5683,6 +5683,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/noOperatorModifierOnProvideDelegate.kt");
}
@TestMetadata("overloadResolutionForSeveralProvideDelegates.kt")
public void testOverloadResolutionForSeveralProvideDelegates() throws Exception {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/overloadResolutionForSeveralProvideDelegates.kt");
}
@TestMetadata("provideDelegateOperatorDeclaration.kt")
public void testProvideDelegateOperatorDeclaration() throws Exception {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateOperatorDeclaration.kt");

View File

@@ -586,11 +586,6 @@ public class CliTestGenerated extends AbstractCliTest {
runTest("compiler/testData/cli/jvm/wrongAbiVersion.args");
}
@TestMetadata("wrongAbiVersionNoErrors.args")
public void testWrongAbiVersionNoErrors() throws Exception {
runTest("compiler/testData/cli/jvm/wrongAbiVersionNoErrors.args");
}
@TestMetadata("wrongArgument.args")
public void testWrongArgument() throws Exception {
runTest("compiler/testData/cli/jvm/wrongArgument.args");

View File

@@ -2410,6 +2410,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/property/augAssignmentAndIncViaConvention.kt");
}
@TestMetadata("kt22649.kt")
public void testKt22649() throws Exception {
runTest("compiler/testData/codegen/boxInline/property/kt22649.kt");
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
runTest("compiler/testData/codegen/boxInline/property/property.kt");

View File

@@ -2410,6 +2410,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/property/augAssignmentAndIncViaConvention.kt");
}
@TestMetadata("kt22649.kt")
public void testKt22649() throws Exception {
runTest("compiler/testData/codegen/boxInline/property/kt22649.kt");
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
runTest("compiler/testData/codegen/boxInline/property/property.kt");

View File

@@ -50,7 +50,8 @@ class JvmModuleProtoBufTest : KtUsefulTestCase() {
File(tmpdir, "META-INF/$moduleName.${ModuleMapping.MAPPING_FILE_EXT}").readBytes(), "test",
CompilerDeserializationConfiguration(
LanguageVersionSettingsImpl(loadWith, ApiVersion.createByLanguageVersion(loadWith))
)
),
::error
)
val result = buildString {
for (annotationClassId in mapping.moduleData.annotations) {

View File

@@ -2410,6 +2410,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/property/augAssignmentAndIncViaConvention.kt");
}
@TestMetadata("kt22649.kt")
public void testKt22649() throws Exception {
runTest("compiler/testData/codegen/boxInline/property/kt22649.kt");
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
runTest("compiler/testData/codegen/boxInline/property/property.kt");

View File

@@ -55,24 +55,24 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
val result = buildString {
appendln("-- Common --")
appendln(K2MetadataCompiler().compile(listOf(commonSrc), "-d", commonDest, *optionalStdlibCommon))
appendln(K2MetadataCompiler().compile(commonSrc, null, "-d", commonDest, *optionalStdlibCommon))
if (jvmSrc != null) {
appendln()
appendln("-- JVM --")
appendln(K2JVMCompiler().compileBothWays(commonSrc, jvmSrc, "-d", jvmDest!!))
appendln(K2JVMCompiler().compile(jvmSrc, commonSrc, "-d", jvmDest!!))
}
if (jsSrc != null) {
appendln()
appendln("-- JS --")
appendln(K2JSCompiler().compileBothWays(commonSrc, jsSrc, "-output", jsDest!!))
appendln(K2JSCompiler().compile(jsSrc, commonSrc, "-output", jsDest!!))
}
if (common2Src != null) {
appendln()
appendln("-- Common (2) --")
appendln(K2MetadataCompiler().compile(listOf(common2Src), "-d", common2Dest!!, "-cp", commonDest, *optionalStdlibCommon))
appendln(K2MetadataCompiler().compile(common2Src, null, "-d", common2Dest!!, "-cp", commonDest, *optionalStdlibCommon))
}
if (jvm2Src != null) {
@@ -80,7 +80,7 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
appendln("-- JVM (2) --")
appendln(
K2JVMCompiler().compile(
listOf(jvm2Src), "-d", jvm2Dest!!,
jvm2Src, common2Src, "-d", jvm2Dest!!,
"-cp", listOfNotNull(commonDest, common2Dest, jvmDest).joinToString(File.pathSeparator)
)
)
@@ -100,28 +100,12 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
}?.toFile() ?: error("kotlin-stdlib-common is not found in $stdlibCommonLibsDir")
}
private fun CLICompiler<*>.compileBothWays(commonSource: File, platformSource: File, vararg mainArguments: String): String {
val configurations = listOf(
listOf(platformSource, commonSource),
listOf(commonSource, platformSource)
)
val (platformFirst, commonFirst) = configurations.map { compile(it, *mainArguments) }
if (platformFirst != commonFirst) {
assertEquals(
"Compilation results are different when compiling [platform-specific, common] compared to when compiling [common, platform-specific]",
"// Compiling [platform-specific, common]\n\n$platformFirst",
"// Compiling [common, platform-specific]\n\n$commonFirst"
)
}
return platformFirst
}
private fun CLICompiler<*>.compile(sources: List<File>, vararg mainArguments: String): String = buildString {
private fun CLICompiler<*>.compile(sources: File, commonSources: File?, vararg mainArguments: String): String = buildString {
val (output, exitCode) = AbstractCliTest.executeCompilerGrabOutput(
this@compile,
sources.map(File::getAbsolutePath) + listOf("-Xmulti-platform") + mainArguments + loadExtraArguments(sources)
listOfNotNull(sources.absolutePath, commonSources?.absolutePath, commonSources?.absolutePath?.let("-Xcommon-sources="::plus)) +
"-Xmulti-platform" + mainArguments +
loadExtraArguments(listOfNotNull(sources, commonSources))
)
appendln("Exit code: $exitCode")
appendln("Output:")

View File

@@ -17,7 +17,7 @@ dependencies {
sourceSets {
"main" {
projectDefault()
resources.srcDir(File(rootDir, "resources")).apply { include("**") }
resources.srcDir(File(rootDir, "resources"))
}
"test" {}
}

View File

@@ -27,6 +27,8 @@ interface Module {
fun getSourceFiles(): List<String>
fun getCommonSourceFiles(): List<String>
fun getClasspathRoots(): List<String>
fun getJavaSourceRoots(): List<JavaRootPath>

View File

@@ -371,7 +371,8 @@ open class JvmBuiltInsSettings(
"startsWith(Ljava/lang/String;I)Z", "startsWith(Ljava/lang/String;)Z", "substring(II)Ljava/lang/String;",
"substring(I)Ljava/lang/String;", "toCharArray()[C", "toLowerCase()Ljava/lang/String;",
"toLowerCase(Ljava/util/Locale;)Ljava/lang/String;", "toUpperCase()Ljava/lang/String;",
"toUpperCase(Ljava/util/Locale;)Ljava/lang/String;", "trim()Ljava/lang/String;"
"toUpperCase(Ljava/util/Locale;)Ljava/lang/String;", "trim()Ljava/lang/String;",
"isBlank()Z", "lines()Ljava/util/stream/Stream;", "repeat(I)Ljava/lang/String;"
) +
inJavaLang("Double", "isInfinite()Z", "isNaN()Z") +

View File

@@ -5,17 +5,20 @@
package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
fun ModuleMapping.Companion.loadModuleMapping(
bytes: ByteArray?,
debugName: String,
configuration: DeserializationConfiguration
configuration: DeserializationConfiguration,
reportIncompatibleVersionError: (JvmMetadataVersion) -> Unit
): ModuleMapping =
loadModuleMapping(
bytes,
debugName,
configuration.skipMetadataVersionCheck,
configuration.isJvmPackageNameSupported
configuration.isJvmPackageNameSupported,
reportIncompatibleVersionError
)

View File

@@ -18,6 +18,7 @@ package kotlin.reflect.jvm.internal.components
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.loadModuleMapping
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
@@ -45,11 +46,20 @@ class RuntimePackagePartProvider(private val classLoader: ClassLoader) : Package
for (resource in resources) {
try {
resource.openStream()?.use { stream ->
val mapping = ModuleMapping.loadModuleMapping(stream.readBytes(), resourcePath, DeserializationConfiguration.Default)
val mapping = ModuleMapping.loadModuleMapping(
stream.readBytes(), resourcePath, DeserializationConfiguration.Default
) { version ->
throw UnsupportedOperationException(
"Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is $version, " +
"expected version is ${JvmMetadataVersion.INSTANCE}. Please update Kotlin to the latest version"
)
}
for ((packageFqName, parts) in mapping.packageFqName2Parts) {
packageParts.getOrPut(packageFqName) { linkedSetOf() }.addAll(parts.parts)
}
}
} catch (e: UnsupportedOperationException) {
throw e
} catch (e: Exception) {
// TODO: do not swallow this exception?
}

View File

@@ -102,12 +102,13 @@ object JvmProtoBufUtil {
typeTable: TypeTable
): JvmMemberSignature.Field? {
val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature) ?: return null
val field = if (signature.hasField()) signature.field else return null
val field =
if (signature.hasField()) signature.field else null
val name = if (field.hasName()) field.name else proto.name
val name = if (field != null && field.hasName()) field.name else proto.name
val desc =
if (field.hasDesc()) nameResolver.getString(field.desc)
else mapTypeDefault(proto.returnType(typeTable), nameResolver) ?: return null
if (field != null && field.hasDesc()) nameResolver.getString(field.desc)
else mapTypeDefault(proto.returnType(typeTable), nameResolver) ?: return null
return JvmMemberSignature.Field(nameResolver.getString(name), desc)
}

View File

@@ -33,7 +33,8 @@ class ModuleMapping private constructor(
bytes: ByteArray?,
debugName: String,
skipMetadataVersionCheck: Boolean,
isJvmPackageNameSupported: Boolean
isJvmPackageNameSupported: Boolean,
reportIncompatibleVersionError: (JvmMetadataVersion) -> Unit
): ModuleMapping {
if (bytes == null) {
return EMPTY
@@ -47,47 +48,47 @@ class ModuleMapping private constructor(
return CORRUPTED
}
if (skipMetadataVersionCheck || JvmMetadataVersion(*versionNumber).isCompatible()) {
val moduleProto = JvmModuleProtoBuf.Module.parseFrom(stream) ?: return EMPTY
val result = linkedMapOf<String, PackageParts>()
for (proto in moduleProto.packagePartsList) {
val packageFqName = proto.packageFqName
val packageParts = result.getOrPut(packageFqName) { PackageParts(packageFqName) }
for ((index, partShortName) in proto.shortClassNameList.withIndex()) {
val multifileFacadeId = proto.multifileFacadeShortNameIdList.getOrNull(index)?.minus(1)
val facadeShortName = multifileFacadeId?.let(proto.multifileFacadeShortNameList::getOrNull)
val facadeInternalName = facadeShortName?.let { internalNameOf(packageFqName, it) }
packageParts.addPart(internalNameOf(packageFqName, partShortName), facadeInternalName)
}
if (isJvmPackageNameSupported) {
for ((index, partShortName) in proto.classWithJvmPackageNameShortNameList.withIndex()) {
val packageId = proto.classWithJvmPackageNamePackageIdList.getOrNull(index)
?: proto.classWithJvmPackageNamePackageIdList.lastOrNull()
?: continue
val jvmPackageName = moduleProto.jvmPackageNameList.getOrNull(packageId) ?: continue
packageParts.addPart(internalNameOf(jvmPackageName, partShortName), null)
}
}
}
for (proto in moduleProto.metadataPartsList) {
val packageParts = result.getOrPut(proto.packageFqName) { PackageParts(proto.packageFqName) }
proto.shortClassNameList.forEach(packageParts::addMetadataPart)
}
// TODO: read arguments of module annotations
val nameResolver = NameResolverImpl(moduleProto.stringTable, moduleProto.qualifiedNameTable)
val annotations = moduleProto.annotationList.map { proto -> nameResolver.getQualifiedClassName(proto.id) }
return ModuleMapping(result, BinaryModuleData(annotations), debugName)
} else {
// TODO: consider reporting "incompatible ABI version" error for package parts
val version = JvmMetadataVersion(*versionNumber)
if (!skipMetadataVersionCheck && !version.isCompatible()) {
reportIncompatibleVersionError(version)
return EMPTY
}
return EMPTY
val moduleProto = JvmModuleProtoBuf.Module.parseFrom(stream) ?: return EMPTY
val result = linkedMapOf<String, PackageParts>()
for (proto in moduleProto.packagePartsList) {
val packageFqName = proto.packageFqName
val packageParts = result.getOrPut(packageFqName) { PackageParts(packageFqName) }
for ((index, partShortName) in proto.shortClassNameList.withIndex()) {
val multifileFacadeId = proto.multifileFacadeShortNameIdList.getOrNull(index)?.minus(1)
val facadeShortName = multifileFacadeId?.let(proto.multifileFacadeShortNameList::getOrNull)
val facadeInternalName = facadeShortName?.let { internalNameOf(packageFqName, it) }
packageParts.addPart(internalNameOf(packageFqName, partShortName), facadeInternalName)
}
if (isJvmPackageNameSupported) {
for ((index, partShortName) in proto.classWithJvmPackageNameShortNameList.withIndex()) {
val packageId = proto.classWithJvmPackageNamePackageIdList.getOrNull(index)
?: proto.classWithJvmPackageNamePackageIdList.lastOrNull()
?: continue
val jvmPackageName = moduleProto.jvmPackageNameList.getOrNull(packageId) ?: continue
packageParts.addPart(internalNameOf(jvmPackageName, partShortName), null)
}
}
}
for (proto in moduleProto.metadataPartsList) {
val packageParts = result.getOrPut(proto.packageFqName) { PackageParts(proto.packageFqName) }
proto.shortClassNameList.forEach(packageParts::addMetadataPart)
}
// TODO: read arguments of module annotations
val nameResolver = NameResolverImpl(moduleProto.stringTable, moduleProto.qualifiedNameTable)
val annotations = moduleProto.annotationList.map { proto -> nameResolver.getQualifiedClassName(proto.id) }
return ModuleMapping(result, BinaryModuleData(annotations), debugName)
}
}
}

View File

@@ -7,17 +7,21 @@ package org.jetbrains.kotlin.idea.formatter
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import com.intellij.psi.codeStyle.PredefinedCodeStyle
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
class KotlinObsoleteCodeStyle : PredefinedCodeStyle(CODE_STYLE_TITLE, KotlinLanguage.INSTANCE) {
class KotlinObsoleteCodeStyle : KotlinPredefinedCodeStyle(CODE_STYLE_TITLE, KotlinLanguage.INSTANCE) {
override val codeStyleId: String = CODE_STYLE_ID
override fun apply(settings: CodeStyleSettings) {
Companion.apply(settings)
}
companion object {
val INSTANCE = KotlinObsoleteCodeStyle()
const val CODE_STYLE_ID = "KOTLIN_OLD_DEFAULTS"
const val CODE_STYLE_SETTING = "obsolete"
const val CODE_STYLE_TITLE = "Kotlin obsolete IntelliJ IDEA codestyle"
fun apply(settings: CodeStyleSettings) {

View File

@@ -0,0 +1,13 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.lang.Language
import com.intellij.psi.codeStyle.PredefinedCodeStyle
abstract class KotlinPredefinedCodeStyle(name: String, language: Language) : PredefinedCodeStyle(name, language) {
abstract val codeStyleId: String
}

View File

@@ -18,17 +18,21 @@ package org.jetbrains.kotlin.idea.formatter
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import com.intellij.psi.codeStyle.PredefinedCodeStyle
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
class KotlinStyleGuideCodeStyle : PredefinedCodeStyle("Kotlin style guide", KotlinLanguage.INSTANCE) {
class KotlinStyleGuideCodeStyle : KotlinPredefinedCodeStyle("Kotlin style guide", KotlinLanguage.INSTANCE) {
override val codeStyleId: String = CODE_STYLE_ID
override fun apply(settings: CodeStyleSettings) {
Companion.apply(settings)
}
companion object {
val INSTANCE = KotlinStyleGuideCodeStyle()
const val CODE_STYLE_ID = "KOTLIN_OFFICIAL"
const val CODE_STYLE_SETTING = "official"
const val CODE_STYLE_TITLE = "Kotlin Coding Conventions"
fun apply(settings: CodeStyleSettings) {
@@ -36,7 +40,10 @@ class KotlinStyleGuideCodeStyle : PredefinedCodeStyle("Kotlin style guide", Kotl
applyToCommonSettings(settings.kotlinCommonSettings)
}
fun applyToKotlinCustomSettings(kotlinCustomSettings: KotlinCodeStyleSettings, modifyCodeStyle: Boolean = true) {
fun applyToKotlinCustomSettings(
kotlinCustomSettings: KotlinCodeStyleSettings,
modifyCodeStyle: Boolean = true
) {
kotlinCustomSettings.apply {
if (modifyCodeStyle) {
CODE_STYLE_DEFAULTS = CODE_STYLE_ID

View File

@@ -44,4 +44,8 @@ val CodeStyleSettings.kotlinCommonSettings: KotlinCommonCodeStyleSettings
get() = getCommonSettings(KotlinLanguage.INSTANCE) as KotlinCommonCodeStyleSettings
val CodeStyleSettings.kotlinCustomSettings: KotlinCodeStyleSettings
get() = getCustomSettings(KotlinCodeStyleSettings::class.java)
get() = getCustomSettings(KotlinCodeStyleSettings::class.java)
fun CodeStyleSettings.kotlinCodeStyleDefaults(): String? {
return kotlinCustomSettings.CODE_STYLE_DEFAULTS ?: kotlinCommonSettings.CODE_STYLE_DEFAULTS
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.openapi.project.Project
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
object ProjectCodeStyleImporter {
fun apply(project: Project, codeStyleStr: String?): Boolean {
return when (codeStyleStr) {
KotlinObsoleteCodeStyle.CODE_STYLE_SETTING -> {
ProjectCodeStyleImporter.apply(project, KotlinObsoleteCodeStyle.INSTANCE)
true
}
KotlinStyleGuideCodeStyle.CODE_STYLE_SETTING -> {
ProjectCodeStyleImporter.apply(project, KotlinStyleGuideCodeStyle.INSTANCE)
true
}
else -> false
}
}
fun apply(project: Project, predefinedCodeStyle: KotlinPredefinedCodeStyle) {
val settingsManager = CodeStyleSettingsManager.getInstance(project)
val currentSettings = settingsManager.currentSettings
if (predefinedCodeStyle.codeStyleId == currentSettings.kotlinCodeStyleDefaults()) {
// Don't bother user that already have correct code style
return
}
val projectSettingsUpdated: CodeStyleSettings = if (settingsManager.USE_PER_PROJECT_SETTINGS) {
settingsManager.currentSettings.clone()
} else {
CodeStyleSettings()
}
settingsManager.USE_PER_PROJECT_SETTINGS = true
predefinedCodeStyle.apply(projectSettingsUpdated)
settingsManager.mainProjectCodeStyle = projectSettingsUpdated
}
}

View File

@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea
import com.intellij.ide.IconProvider
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.openapi.util.Iconable
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
@@ -52,7 +53,15 @@ class KotlinIconProvider : IconProvider(), DumbAware {
val result = psiElement.getBaseIcon()
if (flags and Iconable.ICON_FLAG_VISIBILITY > 0 && result != null && (psiElement is KtModifierListOwner && psiElement !is KtClassInitializer)) {
val list = psiElement.modifierList
return createRowIcon(result.addExpectActualMarker(psiElement), getVisibilityIcon(list))
val visibilityIcon = getVisibilityIcon(list)
val withExpectedActual: Icon = try {
result.addExpectActualMarker(psiElement)
} catch (indexNotReady: IndexNotReadyException) {
result
}
createRowIcon(withExpectedActual, visibilityIcon)
}
return result
}

View File

@@ -0,0 +1,322 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.caches
import com.intellij.ProjectTopics
import com.intellij.openapi.Disposable
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.fileTypes.FileTypeRegistry
import com.intellij.openapi.module.Module
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.rootManager
import com.intellij.openapi.roots.ModuleRootEvent
import com.intellij.openapi.roots.ModuleRootListener
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.BulkFileListener
import com.intellij.openapi.vfs.newvfs.events.*
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.PsiTreeChangeEventImpl
import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.FULL_DROP_THRESHOLD
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfoByVirtualFile
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
import org.jetbrains.kotlin.idea.util.getSourceRoot
import org.jetbrains.kotlin.idea.util.sourceRoot
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPackageDirective
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
class KotlinPackageContentModificationListener(private val project: Project) {
init {
val connection = project.messageBus.connect()
connection.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener {
override fun before(events: MutableList<out VFileEvent>) = onEvents(events)
override fun after(events: List<VFileEvent>) = onEvents(events)
private fun isRelevant(it: VFileEvent): Boolean =
it is VFileMoveEvent || it is VFileCreateEvent || it is VFileCopyEvent || it is VFileDeleteEvent
fun onEvents(events: List<VFileEvent>) {
val service = PerModulePackageCacheService.getInstance(project)
if (events.size >= FULL_DROP_THRESHOLD) {
service.onTooComplexChange()
} else {
events
.asSequence()
.filter { it.isValid }
.filter { it.file != null }
.filter(::isRelevant)
.filter {
val vFile = it.file!!
vFile.isDirectory || FileTypeRegistry.getInstance().getFileTypeByFileName(vFile.name) == KotlinFileType.INSTANCE
}
.forEach { event -> service.notifyPackageChange(event) }
}
}
})
connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
override fun rootsChanged(event: ModuleRootEvent) {
PerModulePackageCacheService.getInstance(project).onTooComplexChange()
}
})
}
}
class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Project) : PsiTreeChangePreprocessor {
override fun treeChanged(event: PsiTreeChangeEventImpl) {
val file = event.file as? KtFile ?: return
when (event.code) {
PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> {
val child = event.child ?: return
if (child.getParentOfType<KtPackageDirective>(false) != null)
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
}
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED -> {
val parent = event.parent ?: return
if (parent.getChildrenOfType<KtPackageDirective>().any())
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
}
else -> {
}
}
}
}
private typealias ImplicitPackageData = MutableMap<FqName, MutableList<VirtualFile>>
class ImplicitPackagePrefixCache(private val project: Project) {
private val implicitPackageCache = ConcurrentHashMap<VirtualFile, ImplicitPackageData>()
fun getPrefix(sourceRoot: VirtualFile): FqName {
val implicitPackageMap = implicitPackageCache.getOrPut(sourceRoot) { analyzeImplicitPackagePrefixes(sourceRoot) }
return implicitPackageMap.keys.singleOrNull() ?: FqName.ROOT
}
internal fun clear() {
implicitPackageCache.clear()
}
private fun analyzeImplicitPackagePrefixes(sourceRoot: VirtualFile): MutableMap<FqName, MutableList<VirtualFile>> {
val result = mutableMapOf<FqName, MutableList<VirtualFile>>()
val ktFiles = sourceRoot.children.filter { it.fileType == KotlinFileType.INSTANCE }
for (ktFile in ktFiles) {
result.addFile(ktFile)
}
return result
}
private fun ImplicitPackageData.addFile(ktFile: VirtualFile) {
synchronized(this) {
val psiFile = PsiManager.getInstance(project).findFile(ktFile) as? KtFile ?: return
addPsiFile(psiFile, ktFile)
}
}
private fun ImplicitPackageData.addPsiFile(
psiFile: KtFile,
ktFile: VirtualFile
) = getOrPut(psiFile.packageFqName) { mutableListOf() }.add(ktFile)
private fun ImplicitPackageData.removeFile(file: VirtualFile) {
synchronized(this) {
for ((key, value) in this) {
if (value.remove(file)) {
if (value.isEmpty()) remove(key)
break
}
}
}
}
private fun ImplicitPackageData.updateFile(file: KtFile) {
synchronized(this) {
removeFile(file.virtualFile)
addPsiFile(file, file.virtualFile)
}
}
internal fun update(event: VFileEvent) {
when (event) {
is VFileCreateEvent -> checkNewFileInSourceRoot(event.file)
is VFileDeleteEvent -> checkDeletedFileInSourceRoot(event.file)
is VFileCopyEvent -> {
val newParent = event.newParent
if (newParent.isValid) {
checkNewFileInSourceRoot(newParent.findChild(event.newChildName))
}
}
is VFileMoveEvent -> {
checkNewFileInSourceRoot(event.file)
if (event.oldParent.getSourceRoot(project) == event.oldParent) {
implicitPackageCache[event.oldParent]?.removeFile(event.file)
}
}
}
}
private fun checkNewFileInSourceRoot(file: VirtualFile?) {
if (file == null) return
if (file.getSourceRoot(project) == file.parent) {
implicitPackageCache[file.parent]?.addFile(file)
}
}
private fun checkDeletedFileInSourceRoot(file: VirtualFile?) {
val directory = file?.parent
if (directory == null || !directory.isValid) return
if (directory.getSourceRoot(project) == directory) {
implicitPackageCache[directory]?.removeFile(file)
}
}
internal fun update(ktFile: KtFile) {
val parent = ktFile.virtualFile.parent
if (ktFile.sourceRoot == parent) {
implicitPackageCache[parent]?.updateFile(ktFile)
}
}
}
class PerModulePackageCacheService(private val project: Project) {
/*
* Disposal of entries handled by Module child Disposable registered in packageExists
* Actually an StrongMap<Module, SoftMap<ModuleSourceInfo, SoftMap<FqName, Boolean>>>
*/
private val cache = ConcurrentHashMap<Module, ConcurrentMap<ModuleSourceInfo, ConcurrentMap<FqName, Boolean>>>()
private val implicitPackagePrefixCache = ImplicitPackagePrefixCache(project)
private val pendingVFileChanges: MutableSet<VFileEvent> = mutableSetOf()
private val pendingKtFileChanges: MutableSet<KtFile> = mutableSetOf()
private val projectScope = GlobalSearchScope.projectScope(project)
internal fun onTooComplexChange(): Unit = synchronized(this) {
pendingVFileChanges.clear()
pendingKtFileChanges.clear()
cache.clear()
implicitPackagePrefixCache.clear()
}
internal fun notifyPackageChange(file: VFileEvent): Unit = synchronized(this) {
pendingVFileChanges += file
}
internal fun notifyPackageChange(file: KtFile): Unit = synchronized(this) {
pendingKtFileChanges += file
}
private fun invalidateCacheForModuleSourceInfo(moduleSourceInfo: ModuleSourceInfo) {
val perSourceInfoData = cache[moduleSourceInfo.module] ?: return
val dataForSourceInfo = perSourceInfoData[moduleSourceInfo] ?: return
dataForSourceInfo.clear()
}
private fun checkPendingChanges() = synchronized(this) {
if (pendingVFileChanges.size + pendingKtFileChanges.size >= FULL_DROP_THRESHOLD) {
onTooComplexChange()
} else {
pendingVFileChanges.processPending { event ->
val vfile = event.file ?: return@processPending
// When VirtualFile !isValid (deleted for example), it impossible to use getModuleInfoByVirtualFile
// For directory we must check both is it in some sourceRoot, and is it contains some sourceRoot
if (vfile.isDirectory || !vfile.isValid) {
for ((module, data) in cache) {
val sourceRootUrls = module.rootManager.sourceRootUrls
if (sourceRootUrls.any { url ->
vfile.containedInOrContains(url)
}) {
data.clear()
}
}
} else {
(getModuleInfoByVirtualFile(project, vfile) as? ModuleSourceInfo)?.let {
invalidateCacheForModuleSourceInfo(it)
}
}
implicitPackagePrefixCache.update(event)
}
pendingKtFileChanges.processPending { file ->
if (file.virtualFile != null && file.virtualFile !in projectScope) {
return@processPending
}
(file.getNullableModuleInfo() as? ModuleSourceInfo)?.let { invalidateCacheForModuleSourceInfo(it) }
implicitPackagePrefixCache.update(file)
}
}
}
private inline fun <T> MutableCollection<T>.processPending(crossinline body: (T) -> Unit) {
this.removeIf { value ->
try {
body(value)
} catch (pce: ProcessCanceledException) {
throw pce
} catch (exc: Exception) {
// Log and proceed. Otherwise pending object processing won't be cleared and exception will be thrown forever.
LOG.error(exc)
}
return@removeIf true
}
}
private fun VirtualFile.containedInOrContains(root: String) =
(VfsUtilCore.isEqualOrAncestor(url, root)
|| isDirectory && VfsUtilCore.isEqualOrAncestor(root, url))
fun packageExists(packageFqName: FqName, moduleInfo: ModuleSourceInfo): Boolean {
val module = moduleInfo.module
checkPendingChanges()
val perSourceInfoCache = cache.getOrPut(module) {
Disposer.register(module, Disposable { cache.remove(module) })
ContainerUtil.createConcurrentSoftMap()
}
val cacheForCurrentModuleInfo = perSourceInfoCache.getOrPut(moduleInfo) {
ContainerUtil.createConcurrentSoftMap()
}
return cacheForCurrentModuleInfo.getOrPut(packageFqName) {
PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project)
}
}
fun getImplicitPackagePrefix(sourceRoot: VirtualFile): FqName {
checkPendingChanges()
return implicitPackagePrefixCache.getPrefix(sourceRoot)
}
companion object {
const val FULL_DROP_THRESHOLD = 1000
private val LOG = Logger.getInstance(this::class.java)
fun getInstance(project: Project): PerModulePackageCacheService =
ServiceManager.getService(project, PerModulePackageCacheService::class.java)
}
}

View File

@@ -16,6 +16,7 @@ import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.util.ModificationTracker
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.ResolveScopeEnlarger
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.CachedValueProvider
import com.intellij.util.PathUtil
@@ -58,6 +59,14 @@ interface IdeaModuleInfo : org.jetbrains.kotlin.idea.caches.resolve.IdeaModuleIn
override fun dependencies(): List<IdeaModuleInfo>
}
private fun enlargedSearchScope(searchScope: GlobalSearchScope, moduleFile: VirtualFile?): GlobalSearchScope {
if (moduleFile == null) return searchScope
return ResolveScopeEnlarger.EP_NAME.extensions.fold(searchScope) { scope, enlarger ->
val extra = enlarger.getAdditionalResolveScope(moduleFile, scope.project)
if (extra != null) scope.union(extra) else scope
}
}
private fun orderEntryToModuleInfo(project: Project, orderEntry: OrderEntry, forProduction: Boolean): List<IdeaModuleInfo> {
fun Module.toInfos() = correspondingModuleInfos().filter { !forProduction || it is ModuleProductionSourceInfo }
@@ -161,7 +170,7 @@ data class ModuleProductionSourceInfo internal constructor(
override val stableName: Name = module.getStableName()
override fun contentScope(): GlobalSearchScope = ModuleProductionSourceScope(module)
override fun contentScope(): GlobalSearchScope = enlargedSearchScope(ModuleProductionSourceScope(module), module.moduleFile)
override fun <T> createCachedValueProvider(f: () -> CachedValueProvider.Result<T>) = CachedValueProvider { f() }
}
@@ -177,7 +186,7 @@ data class ModuleTestSourceInfo internal constructor(override val module: Module
override val displayedName get() = module.name + " (test)"
override fun contentScope(): GlobalSearchScope = ModuleTestSourceScope(module)
override fun contentScope(): GlobalSearchScope = enlargedSearchScope(ModuleTestSourceScope(module), module.moduleFile)
override fun modulesWhoseInternalsAreVisible() = module.cached(CachedValueProvider {
val list = SmartList<ModuleInfo>()
@@ -433,4 +442,4 @@ data class PlatformModuleInfo(
}
fun IdeaModuleInfo.projectSourceModules(): List<ModuleSourceInfo>? =
(this as? ModuleSourceInfo)?.let(::listOf) ?: (this as? PlatformModuleInfo)?.containedModules
(this as? ModuleSourceInfo)?.let(::listOf) ?: (this as? PlatformModuleInfo)?.containedModules

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