Compare commits

...

32 Commits

Author SHA1 Message Date
Yan Zhulanow
6fd4b0d4ab Update changelog for Kotlin 1.2.40 2018-03-23 21:13:25 +03:00
Natalia Selezneva
44ab7c49af Fix compatibility with LivePlugin
^KT-23371 Fixed

(cherry picked from commit c7513b5)
2018-03-22 17:23:09 +03:00
Yan Zhulanow
f0433b7ec1 Android modules should not be imported as common modules (#KT-23367) 2018-03-22 04:54:09 +03:00
Yan Zhulanow
a96e61c96c Minor: Add Android Studio platform prefix in Android patchset branches to fix 'runIde' task for them 2018-03-22 04:54:02 +03:00
Yan Zhulanow
73e255c97c Minor: Fix bundled Kotlin plugin removal in Android Studio bundle for macOS 2018-03-22 04:53:56 +03:00
Natalia Selezneva
3559ed669d Set FATAL severity for errors from GradleScriptTemplateProvider
(cherry picked from commit 3b11b89)
2018-03-21 19:38:13 +03:00
Alexander Podkhalyuzin
089a7eed11 Fixed broken exception reporter
(cherry picked from commit 7d72fe0)
2018-03-21 17:40:37 +03:00
Denis Zharkov
fdb7995a3f Avoid retaining whole KotlinClassHeader in IDEKotlinBinaryClassCache
Before this change there was a retention chain
VirtualFile -> KotlinBinaryData -> KotlinBinaryHeaderData -> KotlinClassHeader

The latter one contains all binary metadata (a lot of String[])
while only a small part of it is used.

The used parts are moved straight to KotlinBinaryClassHeaderData
in this change.

 #KT-19484 Fixed
2018-03-20 10:46:44 +03:00
Alexey Tsvetkov
fb8759dc8c Set up idea.home.path in :incremental-compilation-impl
To avoid warnings in stderr
2018-03-19 19:01:13 +03:00
Alexey Tsvetkov
dad2274ff1 Report correct source to output mapping for kjsm files
Now IC can correctly remove kjsm files when source files are changed
2018-03-19 19:01:08 +03:00
Alexey Tsvetkov
e1e139fb02 Remove all kjsm files before writing new ones 2018-03-19 19:01:03 +03:00
Alexey Tsvetkov
1b699c5039 Compare diverged .meta.js files in a human readable way 2018-03-19 19:00:59 +03:00
Alexey Tsvetkov
fda9d5d5bb Fix comparing directories after IC test
A directory-after-rebuild should correspond to expectedDir parameter,
a directory-after-IC should correspond to actualDir parameter.
Also we should not forgive extra directories.
2018-03-19 19:00:55 +03:00
Alexey Tsvetkov
bf5e67cad3 Generate meta info in JS IC tests 2018-03-19 19:00:50 +03:00
Alexey Tsvetkov
4def41144b Avoid serializing JS metadata twice per compilation 2018-03-19 19:00:45 +03:00
Alexey Tsvetkov
d9191a0ace Sort package fragments by fq-name for JS serialization 2018-03-19 19:00:41 +03:00
Alexey Tsvetkov
4092608ff6 Optimize serializing JS metadata
This makes JS IC tests twice as fast
2018-03-19 19:00:37 +03:00
Alexey Tsvetkov
f711fc8406 Avoid reading JS libraries twice per compilation 2018-03-19 19:00:33 +03:00
Alexey Tsvetkov
355a0f8859 Improve JS inliner performance 2018-03-19 19:00:29 +03:00
Alexey Tsvetkov
eb01d9aaaf Ensure all output directories are cleared on IC rebuild
In some cases IC needs to perform a rebuild.
Before this change IC was not clearing output directories
besides destination dir for classes, so for example
kapt stubs were not cleared.

Stalled stubs might lead to compile errors.
For example:
1. foo/XGen.java is generated from annotated class foo/X (XGen also
references X).
2. foo/X is moved to bar/X and some other change forces IC to rebuild.
3. kapt generates bar/X stub, but foo/X stub
was not removed because stubs dir is not cleared.
4. kapt runs annotation processors, foo/XGen.java is generated from
foo/X stub, bar/XGen.java is generated from bar/X stub.
5. kotlinc rebuilds. Since destination dir is cleared properly,
only bar/X.class exists.
6. javac tries to compile foo/XGen and fails, because it
compiles against actual Kotlin classes, not stubs.

This commit fixes the issue by passing all output directories
of a task from Gradle to Kotlin IC.

   #KT-21735 fixed
2018-03-19 17:43:53 +03:00
Alexey Tsvetkov
3cbd842b8b Fix unresolved references in kotlin-gradle-plugin in Idea 2018-03-19 17:43:48 +03:00
Ilya Chernikov
f960ca38eb Implement support for additional compiler arguments for scripts in IDE
fixes #KT-19120
2018-03-19 11:51:14 +01:00
Ilya Chernikov
dff4cfd1fc Refactor language feature settings processing for exposing it outside of the CLI compiler 2018-03-19 11:50:50 +01:00
Natalia Selezneva
1a2f4223c3 Add test for fatal severity in scripts
(cherry picked from commit 58edab3)
2018-03-19 12:55:04 +03:00
Natalia Selezneva
7c8dcdee62 Add FATAL severity to ScriptExternalHighlightingPass
(cherry picked from commit f957b30)
2018-03-19 12:54:42 +03:00
Natalia Selezneva
b3af085cfd Add FATAL severity to script dependencies resolve result
(cherry picked from commit dcea9d0)
2018-03-19 12:54:14 +03:00
Natalia Selezneva
4844176f49 Restore old package for ScriptTemplatesProvider.
Note that this is EP used in another plugins (ex. LivePlugin https://plugins.jetbrains.com/plugin/7282-liveplugin)

(cherry picked from commit 82481b4)
2018-03-19 12:53:53 +03:00
Natalia Selezneva
0bcb6851e9 Don't highlight gradle scripts during gradle import.
Show warning on the top panel for these files

(cherry picked from commit 1f75eae)
2018-03-19 12:52:05 +03:00
Natalia Selezneva
4645884785 Don't highlight scripts if resolver returns Failure.
Note that we don't highlight script when ScriptDependenciesFileAttribute is not set.

(cherry picked from commit 5f1118e)
2018-03-19 12:49:59 +03:00
Natalia Selezneva
576974f7ad Scripts: display errors from external resolver in panel if text range is empty
(cherry picked from commit 4b4acfe)
2018-03-19 12:49:33 +03:00
Natalia Selezneva
923716e38f Introduce default ScriptTemplate for Gradle scripts
^KT-23228 Fixed

(cherry picked from commit 26a4b67)
2018-03-19 12:49:09 +03:00
Natalia Selezneva
41dc8b6263 Minor: reformat
(cherry picked from commit 9f02664)
2018-03-19 12:47:04 +03:00
67 changed files with 929 additions and 392 deletions

View File

@@ -1,5 +1,184 @@
# CHANGELOG
## 1.2.40
### Compiler
#### New Features
- [`KT-22703`](https://youtrack.jetbrains.com/issue/KT-22703) Allow expect/actual annotation constructors to have default values
- [`KT-19159`](https://youtrack.jetbrains.com/issue/KT-19159) Support crossinline lambda parameters of suspend function type
- [`KT-21913`](https://youtrack.jetbrains.com/issue/KT-21913) Support default arguments for expected declarations
- [`KT-19120`](https://youtrack.jetbrains.com/issue/KT-19120) Provide extra compiler arguments in ScriptTemplateDefinition
#### Performance Improvements
- [`KT-10057`](https://youtrack.jetbrains.com/issue/KT-10057) Use `lcmp` instruction instead of `kotlin/jvm/internal/Intrinsics.compare`
- [`KT-14258`](https://youtrack.jetbrains.com/issue/KT-14258) Suboptimal codegen for private fieldaccess to private field in companion object
- [`KT-18731`](https://youtrack.jetbrains.com/issue/KT-18731) `==` between enums should use reference equality, not `Intrinsics.areEqual()`.
- [`KT-22714`](https://youtrack.jetbrains.com/issue/KT-22714) Unnecessary checkcast to array of object from an array of specific type
#### Fixes
- [`KT-16424`](https://youtrack.jetbrains.com/issue/KT-16424) Fix broken bytecode for nullable generic method
- [`KT-17171`](https://youtrack.jetbrains.com/issue/KT-17171) Fix `ClassCaseException` in case of SAM conversion with `out` variance
- [`KT-19399`](https://youtrack.jetbrains.com/issue/KT-19399) Incorrect bytecode generated for inline functions in some complex cases
- [`KT-21696`](https://youtrack.jetbrains.com/issue/KT-21696) Incorrect warning for use-site target on extension function
- [`KT-22031`](https://youtrack.jetbrains.com/issue/KT-22031) Non-`abstract` expect classes should not have `abstract` members
- [`KT-22260`](https://youtrack.jetbrains.com/issue/KT-22260) Never flag `inline suspend fun` with `NOTHING_TO_INLINE`
- [`KT-22352`](https://youtrack.jetbrains.com/issue/KT-22352) Expect/actual checker can't handle properties and functions with the same name
- [`KT-22652`](https://youtrack.jetbrains.com/issue/KT-22652) Interface with default overrides is not perceived as a SAM
- [`KT-22904`](https://youtrack.jetbrains.com/issue/KT-22904) Incorrect bytecode generated for withIndex iteration on `Array<Int>`
- [`KT-22906`](https://youtrack.jetbrains.com/issue/KT-22906) Invalid class name generated for lambda created from method reference in anonymous object
- [`KT-23044`](https://youtrack.jetbrains.com/issue/KT-23044) Overriden public property with internal setter cannot be found in runtime
- [`KT-23104`](https://youtrack.jetbrains.com/issue/KT-23104) Incorrect code generated for LHS of an intrinsified `in` operator in case of generic type substituted with `Character`
- [`KT-23309`](https://youtrack.jetbrains.com/issue/KT-23309) Minor spelling errors in jvm internal error message
### IDE
#### New Features
- [`KT-10368`](https://youtrack.jetbrains.com/issue/KT-10368) Run Action for Kotlin Scratch Files
- [`KT-16892`](https://youtrack.jetbrains.com/issue/KT-16892) Shortcut to navigate between header and impl
- [`KT-23005`](https://youtrack.jetbrains.com/issue/KT-23005) Support `prefix`/`suffix` attributes for language injection in Kotlin with annotations and comments
#### Performance Improvements
- [`KT-19484`](https://youtrack.jetbrains.com/issue/KT-19484) KotlinBinaryClassCache retains a lot of memory
- [`KT-23183`](https://youtrack.jetbrains.com/issue/KT-23183) `ConfigureKotlinNotification.getNotificationString()` scans modules with Kotlin files twice
- [`KT-23380`](https://youtrack.jetbrains.com/issue/KT-23380) Improve IDE performance when working with Spring projects
#### Fixes
- [`KT-15482`](https://youtrack.jetbrains.com/issue/KT-15482) `KotlinNullPointerException` in IDE from expected class with nested class
- [`KT-15739`](https://youtrack.jetbrains.com/issue/KT-15739) Internal visibility across common and platform-dependent modules
- [`KT-19025`](https://youtrack.jetbrains.com/issue/KT-19025) Not imported build.gradle.kts is red
- [`KT-19165`](https://youtrack.jetbrains.com/issue/KT-19165) IntelliJ should suggest to reload Gradle projects when Kotlin build scripts change
- [`KT-20282`](https://youtrack.jetbrains.com/issue/KT-20282) 'Move statement up' works incorrectly for statement after 'finally' block if 'try' block contains closure
- [`KT-20521`](https://youtrack.jetbrains.com/issue/KT-20521) Kotlin Gradle script: valid `build.gradle.kts` is red and becomes normal only after reopening the project
- [`KT-20592`](https://youtrack.jetbrains.com/issue/KT-20592) `KotlinNullPointerException`: nested class inside expect / actual interface
- [`KT-21013`](https://youtrack.jetbrains.com/issue/KT-21013) "Move statement up/down" fails for multiline declarations
- [`KT-21420`](https://youtrack.jetbrains.com/issue/KT-21420) .gradle.kts editor should do no semantic highlighting until the first successful dependency resolver response
- [`KT-21683`](https://youtrack.jetbrains.com/issue/KT-21683) Language injection: JPAQL. Injection should be present for "query" parameter of `@NamedNativeQueries`
- [`KT-21745`](https://youtrack.jetbrains.com/issue/KT-21745) Warning and quickfix about kotlin-stdlib-jre7/8 -> kotlin-stdlib-jdk7/8 in Maven
- [`KT-21746`](https://youtrack.jetbrains.com/issue/KT-21746) Warning and quickfix about kotlin-stdlib-jre7/8 -> kotlin-stdlib-jdk7/8 in Gradle
- [`KT-21753`](https://youtrack.jetbrains.com/issue/KT-21753) Language injection: SpEL. Not injected for key in `@Caching`
- [`KT-21771`](https://youtrack.jetbrains.com/issue/KT-21771) All annotations in Annotations.kt from kotlin-test-js module wrongly have ACTUAL_MISSING
- [`KT-21831`](https://youtrack.jetbrains.com/issue/KT-21831) Opening class from `kotlin-stdlib-jdk8.jar` fails with EE: "Stub list in ... length differs from PSI"
- [`KT-22229`](https://youtrack.jetbrains.com/issue/KT-22229) Kotlin local delegated property Import auto-removed with "Java: Optimize imports on the fly"
- [`KT-22724`](https://youtrack.jetbrains.com/issue/KT-22724) ISE: "psiFile must not be null" at KotlinNodeJsRunConfigurationProducer.setupConfigurationFromContext()
- [`KT-22817`](https://youtrack.jetbrains.com/issue/KT-22817) Hitting 'Propagate Parameters' in Change Signature throws UnsupportedOperationException
- [`KT-22851`](https://youtrack.jetbrains.com/issue/KT-22851) Apply button is always active on Kotlin compiler settings tab
- [`KT-22858`](https://youtrack.jetbrains.com/issue/KT-22858) Multiplatform: String constructor parameter is reported in Java file of jvm module on creation of a new instance of a class from common module
- [`KT-22865`](https://youtrack.jetbrains.com/issue/KT-22865) Support multiple expectedBy dependencies when importing project from gradle or maven
- [`KT-22873`](https://youtrack.jetbrains.com/issue/KT-22873) Common module-based light classes do not see JDK
- [`KT-22874`](https://youtrack.jetbrains.com/issue/KT-22874) Exception on surround with "if else" when resulting if should be wrapped with ()
- [`KT-22925`](https://youtrack.jetbrains.com/issue/KT-22925) Unable to view Type Hierarchy from constructor call in expression
- [`KT-22926`](https://youtrack.jetbrains.com/issue/KT-22926) Confusing behavior of Type Hierarchy depending on the caret position at superclass constructor
- [`KT-23097`](https://youtrack.jetbrains.com/issue/KT-23097) Enhance multiplatform project wizard
- [`KT-23271`](https://youtrack.jetbrains.com/issue/KT-23271) Warn about using kotlin-stdlib-jre* libs in `dependencyManagement` section in Maven with `eap` and `dev` Kotlin versions
### IDE. Gradle. Script
- [`KT-23228`](https://youtrack.jetbrains.com/issue/KT-23228) Do not highlight `.gradle.kts` files in non-Gradle projects
### IDE. Inspections and Intentions
#### New Features
- [`KT-16382`](https://youtrack.jetbrains.com/issue/KT-16382) Intention to convert `expr.unsafeCast<Type>()` to `expr as Type` and vice versa
- [`KT-20439`](https://youtrack.jetbrains.com/issue/KT-20439) Add intentions to add/remove labeled return to last expression in a lambda
- [`KT-22011`](https://youtrack.jetbrains.com/issue/KT-22011) Inspection to report the usage of Java Collections methods on immutable Kotlin Collections
- [`KT-22933`](https://youtrack.jetbrains.com/issue/KT-22933) Add intention/inspection to convert Pair constructor to `to` function
#### Fixes
- [`KT-12226`](https://youtrack.jetbrains.com/issue/KT-12226) "Convert concatenation to template" does not process dollar sign as a Char
- [`KT-15858`](https://youtrack.jetbrains.com/issue/KT-15858) "Replace with a 'foreach' function call" intention breaks code
- [`KT-16332`](https://youtrack.jetbrains.com/issue/KT-16332) Add braces to 'if' statement intention does not put end-of-line comment properly into braces
- [`KT-17058`](https://youtrack.jetbrains.com/issue/KT-17058) Create implementations from headers: each implementation gets own file
- [`KT-17306`](https://youtrack.jetbrains.com/issue/KT-17306) Don't report package name mismatch if there's no Java code in the module
- [`KT-19730`](https://youtrack.jetbrains.com/issue/KT-19730) Quickfix for delegated properties boilerplate generation doesn't work on locals
- [`KT-21005`](https://youtrack.jetbrains.com/issue/KT-21005) Missing KDoc inspection seems to have broken in 1.1.60 EAP
- [`KT-21082`](https://youtrack.jetbrains.com/issue/KT-21082) Create actual declaration of top-level subclass of expected sealed class in the same file as actual declaration of sealed class present
- [`KT-22110`](https://youtrack.jetbrains.com/issue/KT-22110) "Can be joined with assignment" inspection underlining extends into comment
- [`KT-22329`](https://youtrack.jetbrains.com/issue/KT-22329) "Create class" quickfix is not suggested in when branch
- [`KT-22428`](https://youtrack.jetbrains.com/issue/KT-22428) Create member function from usage shouldn't present type parameters as options
- [`KT-22492`](https://youtrack.jetbrains.com/issue/KT-22492) "Specify explicit lambda signature" intention is available only on lambda braces
- [`KT-22719`](https://youtrack.jetbrains.com/issue/KT-22719) Incorrect warning 'Redundant semicolon' when having method call before lambda expression
- [`KT-22861`](https://youtrack.jetbrains.com/issue/KT-22861) "Add annotation target" quick fix is not available on annotation with use site target
- [`KT-22862`](https://youtrack.jetbrains.com/issue/KT-22862) "Add annotation target" quick fix does not process existent annotations with use site target
- [`KT-22917`](https://youtrack.jetbrains.com/issue/KT-22917) Update order of containers for `create class` quickfix
- [`KT-22949`](https://youtrack.jetbrains.com/issue/KT-22949) NPE on conversion of `run`/`apply` with explicit lambda signature to `let`/`also`
- [`KT-22950`](https://youtrack.jetbrains.com/issue/KT-22950) Convert stdlib extension function to scoping function works incorrectly in case of explicit lambda signature
- [`KT-22954`](https://youtrack.jetbrains.com/issue/KT-22954) "Sort modifiers" quick fix works incorrectly when method is annotated
- [`KT-22970`](https://youtrack.jetbrains.com/issue/KT-22970) Add explicit this intention/inspection missing for lambda invocation
- [`KT-23109`](https://youtrack.jetbrains.com/issue/KT-23109) "Remove redundant 'if' statement" inspection breaks code with labeled return
- [`KT-23215`](https://youtrack.jetbrains.com/issue/KT-23215) "Add function to supertype" quick fix works incorrectly
### IDE. Refactorings
#### Fixes
- [`KT-13255`](https://youtrack.jetbrains.com/issue/KT-13255) Refactor / Rename: renaming local variable or class to existing name gives no warning
- [`KT-13284`](https://youtrack.jetbrains.com/issue/KT-13284) Refactor / Rename: superfluous imports and FQNs in Java using `@JvmOverloads` functions
- [`KT-13907`](https://youtrack.jetbrains.com/issue/KT-13907) Rename refactoring warns about name conflict if there is function with different signature but the same name
- [`KT-13986`](https://youtrack.jetbrains.com/issue/KT-13986) Full qualified names of classes in comments should be changed after class Move, if comment contains backquotes
- [`KT-14671`](https://youtrack.jetbrains.com/issue/KT-14671) typealias: refactor/rename should propose to rename occurrences in comments
- [`KT-15039`](https://youtrack.jetbrains.com/issue/KT-15039) Extra usage is found for a parameter in data class in destructuring construction
- [`KT-15228`](https://youtrack.jetbrains.com/issue/KT-15228) Extract function from inline function should create public function
- [`KT-15302`](https://youtrack.jetbrains.com/issue/KT-15302) Reference to typealias in SAM conversion is not found
- [`KT-16510`](https://youtrack.jetbrains.com/issue/KT-16510) Can't rename quoted identifier `is`
- [`KT-17827`](https://youtrack.jetbrains.com/issue/KT-17827) Refactor / Move corrupts bound references when containing class of member element is changed
- [`KT-19561`](https://youtrack.jetbrains.com/issue/KT-19561) Name conflict warning when renaming method to a name matching an extension method with the same name exists
- [`KT-20178`](https://youtrack.jetbrains.com/issue/KT-20178) Refactor → Rename can't make companion object name empty
- [`KT-22282`](https://youtrack.jetbrains.com/issue/KT-22282) Moving a Kotlin file to another package does not change imports in itself
- [`KT-22482`](https://youtrack.jetbrains.com/issue/KT-22482) Rename refactoring insert qualifier for non related property call
- [`KT-22661`](https://youtrack.jetbrains.com/issue/KT-22661) Refactor/Move: top level field reference is not imported automatically after move to the source root
- [`KT-22678`](https://youtrack.jetbrains.com/issue/KT-22678) Refactor / Copy: "Class uses constructor which will be inaccessible after move" when derived class has a protected constructor
- [`KT-22692`](https://youtrack.jetbrains.com/issue/KT-22692) Refactor/Move: unnecessary curly braces added on moving to a separate file a top level function with a top level field usage
- [`KT-22745`](https://youtrack.jetbrains.com/issue/KT-22745) Refactor/Move inserts FQ function name at the call site if there is a field same named as the function
- [`KT-22747`](https://youtrack.jetbrains.com/issue/KT-22747) Moving top-level function to a different (existing) file doesn't update references from Java
- [`KT-22751`](https://youtrack.jetbrains.com/issue/KT-22751) Refactor/Rename: type alias name clash is not reported
- [`KT-22769`](https://youtrack.jetbrains.com/issue/KT-22769) Refactor/Move: there is no warning on moving sealed class or its inheritors to another file
- [`KT-22771`](https://youtrack.jetbrains.com/issue/KT-22771) Refactor/Move: there is no warning on moving nested class to another class with stricter visibility
- [`KT-22812`](https://youtrack.jetbrains.com/issue/KT-22812) Refactor/Rename extension functions incorrectly conflicts with other extension functions
- [`KT-23065`](https://youtrack.jetbrains.com/issue/KT-23065) Refactor/Move: Specify the warning message on moving sealed class inheritors without moving the sealed class itself
### IDE. Script
- [`KT-22647`](https://youtrack.jetbrains.com/issue/KT-22647) Run script Action in IDE should use Kotlin compiler from the IDE plugin
### JavaScript
- [`KT-22019`](https://youtrack.jetbrains.com/issue/KT-22019) Fix wrong list sorting order
### Language design
- [`KT-21515`](https://youtrack.jetbrains.com/issue/KT-21515) Restrict visibility of classifiers inside companion objects
### Tools. CLI
- [`KT-22777`](https://youtrack.jetbrains.com/issue/KT-22777) Unstable language version setting has no effect when attached runtime has lower version
### Tools. Gradle
- [`KT-22824`](https://youtrack.jetbrains.com/issue/KT-22824) `expectedBy` dependency should be expressed as `compile` dependency in POM
- [`KT-15371`](https://youtrack.jetbrains.com/issue/KT-15371) Multiplatform: setting free compiler args can break build
- [`KT-22864`](https://youtrack.jetbrains.com/issue/KT-22864) Allow multiple expectedBy configuration dependencies in Gradle
- [`KT-22895`](https://youtrack.jetbrains.com/issue/KT-22895) 'kotlin-runtime' library is missing in the compiler classpath sometimes
- [`KT-23085`](https://youtrack.jetbrains.com/issue/KT-23085) Use proper names for the Gradle task inputs/outputs added at runtime
### Tools. Incremental Compile
- [`KT-20516`](https://youtrack.jetbrains.com/issue/KT-20516) "Unresolved reference" when project declares same class as its dependency
- [`KT-22542`](https://youtrack.jetbrains.com/issue/KT-22542) "Source file or directory not found" for incremental compilation with Kobalt
### Tools. JPS
- [`KT-16091`](https://youtrack.jetbrains.com/issue/KT-16091) Incremental compilation ignores changes in Java static field
- [`KT-22995`](https://youtrack.jetbrains.com/issue/KT-22995) EA-91869 - NA: `LookupStorage.<init>`
### Tools. kapt
- [`KT-21735`](https://youtrack.jetbrains.com/issue/KT-21735) Kapt cache was not cleared sometimes
## 1.2.30
### Android

View File

@@ -20,9 +20,13 @@ import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.incremental.LocalFileKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.DebugProtoBuf
import org.jetbrains.kotlin.metadata.js.DebugJsProtoBuf
import org.jetbrains.kotlin.metadata.jvm.DebugJvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.BitEncoding
import org.jetbrains.kotlin.protobuf.ExtensionRegistry
import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.util.TraceClassVisitor
@@ -34,6 +38,8 @@ import java.io.PrintWriter
import java.io.StringWriter
import java.util.*
import java.util.zip.CRC32
import java.util.zip.GZIPInputStream
import kotlin.comparisons.compareBy
// Set this to true if you want to dump all bytecode (test will fail in this case)
private val DUMP_ALL = System.getProperty("comparison.dump.all") == "true"
@@ -162,6 +168,24 @@ private fun classFileToString(classFile: File): String {
return out.toString()
}
private fun metaJsToString(metaJsFile: File): String {
val out = StringWriter()
val metadataList = arrayListOf<KotlinJavascriptMetadata>()
KotlinJavascriptMetadataUtils.parseMetadata(metaJsFile.readText(), metadataList)
for (metadata in metadataList) {
val (header, content) = GZIPInputStream(ByteArrayInputStream(metadata.body)).use { stream ->
DebugJsProtoBuf.Header.parseDelimitedFrom(stream, JsSerializerProtocol.extensionRegistry) to
DebugJsProtoBuf.Library.parseFrom(stream, JsSerializerProtocol.extensionRegistry)
}
out.write("\n------ header -----\n$header")
out.write("\n------ library -----\n$content")
}
return out.toString()
}
private fun getExtensionRegistry(): ExtensionRegistry {
val registry = ExtensionRegistry.newInstance()!!
DebugJvmProtoBuf.registerAllExtensions(registry)
@@ -173,6 +197,9 @@ private fun fileToStringRepresentation(file: File): String {
file.name.endsWith(".class") -> {
classFileToString(file)
}
file.name.endsWith(KotlinJavascriptMetadataUtils.META_JS_SUFFIX) -> {
metaJsToString(file)
}
else -> {
file.readText()
}

View File

@@ -123,6 +123,9 @@ fun removePathPrefix(path: String): String {
val unzipIntellijSdk by tasks.creating {
configureExtractFromConfigurationTask(intellij, pathRemap = { removePathPrefix(it) }) {
zipTree(it.singleFile).matching {
if (OperatingSystem.current().isMacOsX && androidStudioRelease != null) {
exclude("Android Studio*.app/Contents/plugins/Kotlin/**")
}
exclude("plugins/Kotlin/**")
}
}

View File

@@ -141,6 +141,10 @@ fun Project.runIdeTask(name: String, ideaPluginDir: File, ideaSandboxDir: File,
"-Didea.additional.classpath=../idea-kotlin-runtime/kotlin-runtime.jar,../idea-kotlin-runtime/kotlin-reflect.jar"
)
if (rootProject.findProperty("versions.androidStudioRelease") != null) {
jvmArgs("-Didea.platform.prefix=AndroidStudio")
}
if (project.hasProperty("noPCE")) {
jvmArgs("-Didea.ProcessCanceledException=disabled")
}

View File

@@ -17,8 +17,9 @@
package org.jetbrains.kotlin.cli.common.arguments
import com.intellij.util.xmlb.annotations.Transient
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.*
import java.util.*
@SuppressWarnings("WeakerAccess")
@@ -164,9 +165,89 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
put(AnalysisFlag.allowKotlinPackage, allowKotlinPackage)
put(AnalysisFlag.experimental, experimental?.toList().orEmpty())
put(AnalysisFlag.useExperimental, useExperimental?.toList().orEmpty())
put(AnalysisFlag.explicitApiVersion, apiVersion != null)
}
}
open fun configureLanguageFeatures(collector: MessageCollector): MutableMap<LanguageFeature, LanguageFeature.State> =
HashMap<LanguageFeature, LanguageFeature.State>().apply {
if (multiPlatform) {
put(LanguageFeature.MultiPlatformProjects, LanguageFeature.State.ENABLED)
}
when (coroutinesState) {
CommonCompilerArguments.ERROR -> put(LanguageFeature.Coroutines, LanguageFeature.State.ENABLED_WITH_ERROR)
CommonCompilerArguments.ENABLE -> put(LanguageFeature.Coroutines, LanguageFeature.State.ENABLED)
CommonCompilerArguments.WARN -> {}
else -> {
val message = "Invalid value of -Xcoroutines (should be: enable, warn or error): " + coroutinesState
collector.report(CompilerMessageSeverity.ERROR, message, null)
}
}
if (newInference) {
put(LanguageFeature.NewInference, LanguageFeature.State.ENABLED)
}
if (legacySmartCastAfterTry) {
put(LanguageFeature.SoundSmartCastsAfterTry, LanguageFeature.State.DISABLED)
}
if (effectSystem) {
put(LanguageFeature.UseCallsInPlaceEffect, LanguageFeature.State.ENABLED)
put(LanguageFeature.UseReturnsEffect, LanguageFeature.State.ENABLED)
}
if (readDeserializedContracts) {
put(LanguageFeature.ReadDeserializedContracts, LanguageFeature.State.ENABLED)
}
if (properIeee754Comparisons) {
put(LanguageFeature.ProperIeee754Comparisons, LanguageFeature.State.ENABLED)
}
}
fun configureLanguageVersionSettings(collector: MessageCollector): LanguageVersionSettings {
// If only "-api-version" is specified, language version is assumed to be the latest stable
val languageVersion = parseVersion(collector, languageVersion, "language") ?: LanguageVersion.LATEST_STABLE
// If only "-language-version" is specified, API version is assumed to be equal to the language version
// (API version cannot be greater than the language version)
val apiVersion = parseVersion(collector, apiVersion, "API") ?: languageVersion
if (apiVersion > languageVersion) {
collector.report(
CompilerMessageSeverity.ERROR,
"-api-version (${apiVersion.versionString}) cannot be greater than -language-version (${languageVersion.versionString})"
)
}
if (!languageVersion.isStable) {
collector.report(
CompilerMessageSeverity.STRONG_WARNING,
"Language version ${languageVersion.versionString} is experimental, there are no backwards compatibility guarantees for new language and library features"
)
}
return LanguageVersionSettingsImpl(
languageVersion,
ApiVersion.createByLanguageVersion(apiVersion),
configureAnalysisFlags(collector),
configureLanguageFeatures(collector)
)
}
private fun parseVersion(collector: MessageCollector, value: String?, versionOf: String): LanguageVersion? =
if (value == null) null
else LanguageVersion.fromVersionString(value)
?: run {
val versionStrings = LanguageVersion.values().map(LanguageVersion::description)
val message = "Unknown $versionOf version: $value\nSupported $versionOf versions: ${versionStrings.joinToString(", ")}"
collector.report(CompilerMessageSeverity.ERROR, message, null)
null
}
// Used only for serialize and deserialize settings. Don't use in other places!
class DummyImpl : CommonCompilerArguments()
}

View File

@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageFeature
class K2JVMCompilerArguments : CommonCompilerArguments() {
companion object {
@@ -235,4 +236,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
)
return result
}
override fun configureLanguageFeatures(collector: MessageCollector): MutableMap<LanguageFeature, LanguageFeature.State> {
val result = super.configureLanguageFeatures(collector)
if (strictJavaNullabilityAssertions) {
result[LanguageFeature.StrictJavaNullabilityAssertions] = LanguageFeature.State.ENABLED
}
return result
}
}

View File

@@ -41,7 +41,6 @@ import org.jetbrains.kotlin.utils.StringsKt;
import java.io.File;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -162,89 +161,10 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
}
private void setupLanguageVersionSettings(@NotNull CompilerConfiguration configuration, @NotNull A arguments) {
LanguageVersion languageVersion = parseVersion(configuration, arguments.getLanguageVersion(), "language");
LanguageVersion apiVersion = parseVersion(configuration, arguments.getApiVersion(), "API");
if (languageVersion != null || apiVersion != null) {
configuration.put(CLIConfigurationKeys.IS_API_VERSION_EXPLICIT, true);
}
if (languageVersion == null) {
// If no "-language-version" is specified, language version is assumed to be the latest stable
languageVersion = LanguageVersion.LATEST_STABLE;
}
if (apiVersion == null) {
// If no "-api-version" is specified, API version is assumed to be equal to the language version
// (API version cannot be greater than the language version)
apiVersion = languageVersion;
}
MessageCollector collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
if (apiVersion.compareTo(languageVersion) > 0) {
collector.report(
ERROR,
"-api-version (" + apiVersion.getVersionString() + ") cannot be greater than " +
"-language-version (" + languageVersion.getVersionString() + ")",
null
);
}
if (!languageVersion.isStable()) {
collector.report(
STRONG_WARNING,
"Language version " + languageVersion.getVersionString() + " is experimental, there are " +
"no backwards compatibility guarantees for new language and library features",
null
);
}
Map<LanguageFeature, LanguageFeature.State> extraLanguageFeatures = new HashMap<>(0);
if (arguments.getMultiPlatform()) {
extraLanguageFeatures.put(LanguageFeature.MultiPlatformProjects, LanguageFeature.State.ENABLED);
}
LanguageFeature.State coroutinesState = chooseCoroutinesApplicabilityLevel(configuration, arguments);
if (coroutinesState != null) {
extraLanguageFeatures.put(LanguageFeature.Coroutines, coroutinesState);
}
if (arguments.getNewInference()) {
extraLanguageFeatures.put(LanguageFeature.NewInference, LanguageFeature.State.ENABLED);
}
if (arguments.getLegacySmartCastAfterTry()) {
extraLanguageFeatures.put(LanguageFeature.SoundSmartCastsAfterTry, LanguageFeature.State.DISABLED);
}
if (arguments.getEffectSystem()) {
extraLanguageFeatures.put(LanguageFeature.UseCallsInPlaceEffect, LanguageFeature.State.ENABLED);
extraLanguageFeatures.put(LanguageFeature.UseReturnsEffect, LanguageFeature.State.ENABLED);
}
if (arguments.getReadDeserializedContracts()) {
extraLanguageFeatures.put(LanguageFeature.ReadDeserializedContracts, LanguageFeature.State.ENABLED);
}
if (arguments.getProperIeee754Comparisons()) {
extraLanguageFeatures.put(LanguageFeature.ProperIeee754Comparisons, LanguageFeature.State.ENABLED);
}
setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, arguments);
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, new LanguageVersionSettingsImpl(
languageVersion,
ApiVersion.createByLanguageVersion(apiVersion),
arguments.configureAnalysisFlags(collector),
extraLanguageFeatures
));
}
protected void setupPlatformSpecificLanguageFeatureSettings(
@NotNull Map<LanguageFeature, LanguageFeature.State> extraLanguageFeatures,
@NotNull A commandLineArguments
) {
// do nothing
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, arguments.configureLanguageVersionSettings(collector));
}
private static final String kotlinHomeEnvVar = System.getenv(KOTLIN_HOME_ENV_VAR);
@@ -299,43 +219,6 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
return null;
}
@Nullable
private static LanguageFeature.State chooseCoroutinesApplicabilityLevel(
@NotNull CompilerConfiguration configuration,
@NotNull CommonCompilerArguments arguments
) {
switch (arguments.getCoroutinesState()) {
case CommonCompilerArguments.ERROR:
return LanguageFeature.State.ENABLED_WITH_ERROR;
case CommonCompilerArguments.ENABLE:
return LanguageFeature.State.ENABLED;
case CommonCompilerArguments.WARN:
return null;
default:
String message = "Invalid value of -Xcoroutines (should be: enable, warn or error): " + arguments.getCoroutinesState();
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(ERROR, message, null);
return null;
}
}
@Nullable
private static LanguageVersion parseVersion(
@NotNull CompilerConfiguration configuration, @Nullable String value, @NotNull String versionOf
) {
if (value == null) return null;
LanguageVersion version = LanguageVersion.fromVersionString(value);
if (version != null) {
return version;
}
List<String> versionStrings = ArraysKt.map(LanguageVersion.values(), LanguageVersion::getDescription);
String message = "Unknown " + versionOf + " version: " + value + "\n" +
"Supported " + versionOf + " versions: " + StringsKt.join(versionStrings, ", ");
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(ERROR, message, null);
return null;
}
protected abstract void setupPlatformSpecificArgumentsAndServices(
@NotNull CompilerConfiguration configuration, @NotNull A arguments, @NotNull Services services
);

View File

@@ -29,8 +29,6 @@ public class CLIConfigurationKeys {
CompilerConfigurationKey.create("allow kotlin package");
public static final CompilerConfigurationKey<Boolean> REPORT_PERF =
CompilerConfigurationKey.create("report performance information");
public static final CompilerConfigurationKey<Boolean> IS_API_VERSION_EXPLICIT =
CompilerConfigurationKey.create("is API version explicit");
// Used in Eclipse plugin (see KotlinCLICompiler)
public static final CompilerConfigurationKey<String> INTELLIJ_PLUGIN_ROOT =

View File

@@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.script.ScriptContentLoader
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
import org.jetbrains.kotlin.script.adjustByDefinition
import java.io.File
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
@@ -48,7 +49,9 @@ class CliScriptDependenciesProvider(
else {
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file)
if (scriptDef != null) {
val deps = scriptContentLoader.loadContentsAndResolveDependencies(scriptDef, file)
val deps = scriptContentLoader
.loadContentsAndResolveDependencies(scriptDef, file)
.dependencies?.adjustByDefinition(scriptDef)
if (deps != null) {
log.info("[kts] new cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}")

View File

@@ -37,6 +37,7 @@ class CliScriptReportSink(private val messageCollector: MessageCollector) : Scri
}
private fun ScriptReport.Severity.convertSeverity(): CompilerMessageSeverity = when(this) {
ScriptReport.Severity.FATAL -> CompilerMessageSeverity.ERROR
ScriptReport.Severity.ERROR -> CompilerMessageSeverity.ERROR
ScriptReport.Severity.WARNING -> CompilerMessageSeverity.WARNING
ScriptReport.Severity.INFO -> CompilerMessageSeverity.INFO

View File

@@ -65,10 +65,7 @@ import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.serialization.js.ModuleKind;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import org.jetbrains.kotlin.utils.KotlinPaths;
import org.jetbrains.kotlin.utils.PathUtil;
import org.jetbrains.kotlin.utils.StringsKt;
import org.jetbrains.kotlin.utils.*;
import java.io.File;
import java.io.IOException;

View File

@@ -129,7 +129,7 @@ object JvmRuntimeVersionsConsistencyChecker {
val actualApi = ApiVersion.parse(actualRuntimeVersion.toString())
if (actualApi == null) {
messageCollector.issue(null, "Could not parse runtime JAR version: $actualRuntimeVersion")
} else if (!configuration.getBoolean(CLIConfigurationKeys.IS_API_VERSION_EXPLICIT) && actualApi < currentApi) {
} else if (!languageVersionSettings.getFlag(AnalysisFlag.explicitApiVersion) && actualApi < currentApi) {
// If there's no explicit "-api-version" AND there's an old stdlib in the classpath (older than the default value of API),
// we infer API = the version of that stdlib.
// Note that "no explicit -api-version" requirement is necessary because for example, in

View File

@@ -227,17 +227,6 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
}
override fun setupPlatformSpecificLanguageFeatureSettings(
extraLanguageFeatures: MutableMap<LanguageFeature, LanguageFeature.State>,
commandLineArguments: K2JVMCompilerArguments
) {
if (commandLineArguments.strictJavaNullabilityAssertions) {
extraLanguageFeatures[LanguageFeature.StrictJavaNullabilityAssertions] = LanguageFeature.State.ENABLED
}
super.setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, commandLineArguments)
}
private fun registerJavacIfNeeded(
environment: KotlinCoreEnvironment,
arguments: K2JVMCompilerArguments

View File

@@ -62,7 +62,11 @@ class IncrementalCompilationOptions(
requestedCompilationResults: Array<Int>,
val resultDifferenceFile: File? = null,
val friendDifferenceFile: File? = null,
val usePreciseJavaTracking: Boolean
val usePreciseJavaTracking: Boolean,
/**
* Directories that should be cleared when IC decides to rebuild
*/
val localStateDirs: List<File>
) : CompilationOptions(compilerMode, targetPlatform, reportCategories, reportSeverity, requestedCompilationResults) {
companion object {
const val serialVersionUID: Long = 0
@@ -80,6 +84,7 @@ class IncrementalCompilationOptions(
"resultDifferenceFile=$resultDifferenceFile, " +
"friendDifferenceFile=$friendDifferenceFile, " +
"usePreciseJavaTracking=$usePreciseJavaTracking" +
"localStateDirs=$localStateDirs" +
")"
}
}

View File

@@ -522,7 +522,8 @@ class CompileServiceImpl(
artifactChanges, changesRegistry,
buildHistoryFile = incrementalCompilationOptions.resultDifferenceFile,
friendBuildHistoryFile = incrementalCompilationOptions.friendDifferenceFile,
usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking
usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking,
localStateDirs = incrementalCompilationOptions.localStateDirs
)
return compiler.compile(allKotlinFiles, k2jvmArgs, compilerMessageCollector, changedFiles)
}

View File

@@ -28,21 +28,22 @@ import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.KParameter
import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.primaryConstructor
import kotlin.script.dependencies.ScriptDependenciesResolver
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.templates.AcceptedAnnotations
import kotlin.script.templates.*
open class KotlinScriptDefinitionFromAnnotatedTemplate(
template: KClass<out Any>,
val environment: Map<String, Any?>? = null,
val templateClasspath: List<File> = emptyList()
) : KotlinScriptDefinition(template) {
val scriptFilePattern by lazy {
val pattern =
takeUnlessError {
template.annotations.firstIsInstanceOrNull<kotlin.script.templates.ScriptTemplateDefinition>()?.scriptFilePattern
val ann = template.annotations.firstIsInstanceOrNull<kotlin.script.templates.ScriptTemplateDefinition>()
ann?.scriptFilePattern
}
?: takeUnlessError { template.annotations.firstIsInstanceOrNull<ScriptTemplateDefinition>()?.scriptFilePattern }
?: DEFAULT_SCRIPT_FILE_PATTERN
@@ -144,6 +145,15 @@ open class KotlinScriptDefinitionFromAnnotatedTemplate(
override val annotationsForSamWithReceivers: List<String>
get() = samWithReceiverAnnotations ?: super.annotationsForSamWithReceivers
override val additionalCompilerArguments: Iterable<String>? by lazy {
takeUnlessError {
template.annotations.firstIsInstanceOrNull<kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments>()?.let {
val res = it.provider.primaryConstructor?.call(it.arguments.asIterable())
res
}
}?.getAdditionalCompilerArguments(environment)
}
private inline fun<T> takeUnlessError(reportError: Boolean = true, body: () -> T?): T? =
try {
body()

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.script
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
@@ -25,8 +26,9 @@ import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtFile
import java.io.File
import kotlin.reflect.KClass
import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult.Failure
import kotlin.script.dependencies.ScriptContents
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult.Failure
import kotlin.script.experimental.dependencies.ScriptDependencies
import kotlin.script.experimental.dependencies.ScriptReport
@@ -37,13 +39,15 @@ class ScriptContentLoader(private val project: Project) {
private fun loadAnnotations(scriptDefinition: KotlinScriptDefinition, file: VirtualFile): List<Annotation> {
val classLoader = scriptDefinition.template.java.classLoader
// TODO_R: report error on failure to load annotation class
return getAnnotationEntries(file, project)
return ApplicationManager.getApplication().runReadAction<List<Annotation>> {
getAnnotationEntries(file, project)
.mapNotNull { psiAnn ->
// TODO: consider advanced matching using semantic similar to actual resolving
scriptDefinition.acceptedAnnotations.find { ann ->
psiAnn.typeName.let { it == ann.simpleName || it == ann.qualifiedName }
}?.let { constructAnnotation(psiAnn, classLoader.loadClass(it.qualifiedName).kotlin as KClass<out Annotation>) }
}
}
}
private fun getAnnotationEntries(file: VirtualFile, project: Project): Iterable<KtAnnotationEntry> {
@@ -62,7 +66,7 @@ class ScriptContentLoader(private val project: Project) {
fun loadContentsAndResolveDependencies(
scriptDef: KotlinScriptDefinition,
file: VirtualFile
): ScriptDependencies? {
): DependenciesResolver.ResolveResult {
val scriptContents = getScriptContents(scriptDef, file)
val environment = getEnvironment(scriptDef)
val result = try {
@@ -75,7 +79,7 @@ class ScriptContentLoader(private val project: Project) {
e.asResolveFailure(scriptDef)
}
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
return result.dependencies?.adjustByDefinition(scriptDef)
return result
}
fun getEnvironment(scriptDef: KotlinScriptDefinition) =
@@ -92,5 +96,5 @@ fun ScriptDependencies.adjustByDefinition(
fun Throwable.asResolveFailure(scriptDef: KotlinScriptDefinition): Failure {
val prefix = "${scriptDef.dependencyResolver::class.simpleName} threw exception ${this::class.simpleName}:\n "
return Failure(ScriptReport(prefix + (message ?: "<no message>")))
return Failure(ScriptReport(prefix + (message ?: "<no message>"), ScriptReport.Severity.FATAL))
}

View File

@@ -32,6 +32,9 @@ sourceSets {
projectTest {
workingDir = rootDir
doFirst {
systemProperty("idea.home.path", intellijRootDir().canonicalPath)
}
}
testsJar()

View File

@@ -43,7 +43,8 @@ abstract class IncrementalCompilerRunner<
protected val cacheVersions: List<CacheVersion>,
protected val reporter: ICReporter,
protected val artifactChangesProvider: ArtifactChangesProvider?,
protected val changesRegistry: ChangesRegistry?
protected val changesRegistry: ChangesRegistry?,
private val localStateDirs: Collection<File> = emptyList()
) {
protected val cacheDirectory = File(workingDir, cacheDirName)
@@ -70,7 +71,15 @@ abstract class IncrementalCompilerRunner<
caches.clean()
dirtySourcesSinceLastTimeFile.delete()
destinationDir(args).deleteRecursively()
reporter.report { "Deleting output directories on rebuild:" }
for (dir in sequenceOf(destinationDir(args)) + localStateDirs.asSequence()) {
if (!dir.isDirectory) continue
dir.deleteRecursively()
dir.mkdirs()
reporter.report { "deleted $dir" }
}
caches = createCacheManager(args)
if (providedChangedFiles == null) {

View File

@@ -71,7 +71,8 @@ fun makeIncrementally(
sourceRoots.map { JvmSourceRoot(it, null) }.toSet(),
versions, reporter,
// Use precise setting in case of non-Gradle build
usePreciseJavaTracking = true
usePreciseJavaTracking = true,
localStateDirs = emptyList()
)
compiler.compile(sourceFiles, args, messageCollector, providedChangedFiles = null)
}
@@ -104,14 +105,16 @@ class IncrementalJvmCompilerRunner(
changesRegistry: ChangesRegistry? = null,
private val buildHistoryFile: File? = null,
private val friendBuildHistoryFile: File? = null,
private val usePreciseJavaTracking: Boolean
private val usePreciseJavaTracking: Boolean,
localStateDirs: Collection<File>
) : IncrementalCompilerRunner<K2JVMCompilerArguments, IncrementalJvmCachesManager>(
workingDir,
"caches-jvm",
cacheVersions,
reporter,
artifactChangesProvider,
changesRegistry
changesRegistry,
localStateDirs = localStateDirs
) {
override fun isICEnabled(): Boolean =
IncrementalCompilation.isEnabled()

View File

@@ -101,7 +101,7 @@ abstract class AbstractIncrementalCompilerRunnerTestBase<Args : CommonCompilerAr
Assert.assertEquals("Rebuild exit code differs from incremental exit code", rebuildExpectedToSucceed, rebuildSucceeded)
if (rebuildSucceeded) {
assertEqualDirectories(outDir, rebuildOutDir, forgiveExtraFiles = rebuildSucceeded)
assertEqualDirectories(rebuildOutDir, outDir, forgiveExtraFiles = false)
}
}
}

View File

@@ -38,5 +38,6 @@ abstract class AbstractIncrementalJsCompilerRunnerTest : AbstractIncrementalComp
K2JSCompilerArguments().apply {
outputFile = File(destinationDir, "${testDir.name}.js").path
sourceMap = true
metaInfo = true
}
}

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.script
import com.intellij.openapi.fileTypes.LanguageFileType
import com.intellij.openapi.util.UserDataHolderBase
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils
@@ -26,7 +27,7 @@ import kotlin.reflect.KClass
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.templates.standard.ScriptTemplateWithArgs
open class KotlinScriptDefinition(val template: KClass<out Any>) {
open class KotlinScriptDefinition(val template: KClass<out Any>) : UserDataHolderBase() {
open val name: String = "Kotlin Script"
@@ -45,6 +46,9 @@ open class KotlinScriptDefinition(val template: KClass<out Any>) {
open val dependencyResolver: DependenciesResolver get() = DependenciesResolver.NoDependencies
open val acceptedAnnotations: List<KClass<out Annotation>> get() = emptyList()
@Deprecated("temporary workaround for missing functionality, will be replaced by the new API soon")
open val additionalCompilerArguments: Iterable<String>? = null
}
object StandardScriptDefinition : KotlinScriptDefinition(ScriptTemplateWithArgs::class)

View File

@@ -79,9 +79,10 @@ class KotlinJavascriptSerializerTest : TestCaseWithTmpdir() {
imported = listOf(),
data = analysisResult.moduleDescriptor
)
FileUtil.writeToFile(metaFile, KotlinJavascriptSerializationUtil.metadataAsString(
val serializedMetadata = KotlinJavascriptSerializationUtil.serializeMetadata(
analysisResult.bindingContext, description, configuration.languageVersionSettings
))
)
FileUtil.writeToFile(metaFile, serializedMetadata.asString())
}
finally {
Disposer.dispose(rootDisposable)

View File

@@ -66,5 +66,8 @@ class AnalysisFlag<out T> internal constructor(
@JvmStatic
val useExperimental by Flag.ListOfStrings
@JvmStatic
val explicitApiVersion by Flag.Boolean
}
}

View File

@@ -49,7 +49,7 @@ interface DependenciesResolver : ScriptDependenciesResolver {
data class ScriptReport(val message: String, val severity: Severity = Severity.ERROR, val position: Position? = null) {
data class Position(val startLine: Int, val startColumn: Int, val endLine: Int? = null, val endColumn: Int? = null)
enum class Severity { ERROR, WARNING, INFO, DEBUG }
enum class Severity { FATAL, ERROR, WARNING, INFO, DEBUG }
}
fun ScriptDependencies.asSuccess(): ResolveResult.Success = ResolveResult.Success(this)

View File

@@ -0,0 +1,28 @@
/*
* 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.
*/
/*
* 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 kotlin.script.templates
import kotlin.reflect.KClass
import kotlin.script.dependencies.Environment
@Deprecated("temporary workaround for missing functionality, will be replaced by the new API soon")
// Note: all subclasses should provide the same constructor
open class ScriptTemplateAdditionalCompilerArgumentsProvider(val arguments: Iterable<String> = emptyList()) {
open fun getAdditionalCompilerArguments(@Suppress("UNUSED_PARAMETER") environment: Environment?): Iterable<String> = arguments
}
// Should be deprecated as well, but since we don't have replacement as of yet, leaving it as is
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class ScriptTemplateAdditionalCompilerArguments(
val arguments: Array<String> = [],
val provider: KClass<out ScriptTemplateAdditionalCompilerArgumentsProvider> = ScriptTemplateAdditionalCompilerArgumentsProvider::class
)

View File

@@ -22,14 +22,22 @@ import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId
import com.intellij.reference.SoftReference
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.name.ClassId
object IDEKotlinBinaryClassCache {
data class KotlinBinaryHeaderData(val classHeader: KotlinClassHeader, val classId: ClassId)
data class KotlinBinaryData(val isKotlinBinary: Boolean, val timestamp: Long, val headerData: KotlinBinaryHeaderData?)
class KotlinBinaryClassHeaderData(
val classId: ClassId,
val kind: KotlinClassHeader.Kind,
val metadataVersion: JvmMetadataVersion,
val partNamesIfMultifileFacade: List<String>,
val packageName: String?
)
data class KotlinBinaryData(val isKotlinBinary: Boolean, val timestamp: Long, val headerData: KotlinBinaryClassHeaderData?)
/**
* Checks if this file is a compiled Kotlin class file (not necessarily ABI-compatible with the current plugin)
@@ -67,7 +75,7 @@ object IDEKotlinBinaryClassCache {
return kotlinBinaryClass
}
fun getKotlinBinaryClassHeaderData(file: VirtualFile, fileContent: ByteArray? = null): KotlinBinaryHeaderData? {
fun getKotlinBinaryClassHeaderData(file: VirtualFile, fileContent: ByteArray? = null): KotlinBinaryClassHeaderData? {
val cached = getKotlinBinaryFromCache(file)
if (cached != null) {
if (!cached.isKotlinBinary) {
@@ -84,13 +92,17 @@ object IDEKotlinBinaryClassCache {
private val attributeService = ServiceManager.getService(FileAttributeService::class.java)
private fun createHeaderInfo(kotlinBinaryClass: KotlinJvmBinaryClass?): KotlinBinaryHeaderData? {
val header = kotlinBinaryClass?.classHeader
val classId = kotlinBinaryClass?.classId
private fun createHeaderInfo(kotlinBinaryClass: KotlinJvmBinaryClass?): KotlinBinaryClassHeaderData? {
val classId = kotlinBinaryClass?.classId ?: return null
return if (header != null && classId != null) KotlinBinaryHeaderData(header, classId) else null
return kotlinBinaryClass.classHeader.toLightHeader(classId)
}
private fun KotlinClassHeader.toLightHeader(classId: ClassId) =
KotlinBinaryClassHeaderData(
classId, kind, metadataVersion, multifilePartNames, packageName
)
private val KOTLIN_IS_COMPILED_FILE_ATTRIBUTE: String = "kotlin-is-binary-compiled".apply {
ServiceManager.getService(FileAttributeService::class.java)?.register(this, 1)
}
@@ -120,4 +132,4 @@ object IDEKotlinBinaryClassCache {
return null
}
}
}

View File

@@ -18,10 +18,16 @@ package org.jetbrains.kotlin.idea.compiler
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.openapi.util.Key
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.cli.common.arguments.Jsr305Parser
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider
@@ -29,15 +35,18 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.TargetPlatformVersion
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.ScriptModuleInfo
import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.targetPlatform
import org.jetbrains.kotlin.script.KotlinScriptDefinition
object IDELanguageSettingsProvider : LanguageSettingsProvider {
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings =
when (moduleInfo) {
is ModuleSourceInfo -> moduleInfo.module.languageVersionSettings
is LibraryInfo -> project.getLanguageVersionSettings(extraAnalysisFlags = getExtraAnalysisFlags(project))
is ScriptModuleInfo -> getVersionLanguageSettingsForScripts(project, moduleInfo.scriptDefinition)
else -> project.getLanguageVersionSettings()
}
@@ -60,3 +69,33 @@ object IDELanguageSettingsProvider : LanguageSettingsProvider {
return (moduleInfo as? ModuleSourceInfo)?.module?.targetPlatform?.version ?: TargetPlatformVersion.NoVersion
}
}
private val LANGUAGE_VERSION_SETTINGS = Key.create<CachedValue<LanguageVersionSettings>>("LANGUAGE_VERSION_SETTINGS")
private fun getVersionLanguageSettingsForScripts(project: Project, scriptDefinition: KotlinScriptDefinition): LanguageVersionSettings {
val args = scriptDefinition.additionalCompilerArguments
return if (args == null || args.none()) {
project.getLanguageVersionSettings()
} else {
val settings = scriptDefinition.getUserData(LANGUAGE_VERSION_SETTINGS) ?: createCachedValue(project) {
val compilerArguments = K2JVMCompilerArguments()
parseCommandLineArguments(args.toList(), compilerArguments)
// TODO: reporting
compilerArguments.configureLanguageVersionSettings(MessageCollector.NONE)
}.also { scriptDefinition.putUserData(LANGUAGE_VERSION_SETTINGS, it) }
settings.value
}
}
private fun createCachedValue(project: Project, body: () -> LanguageVersionSettings): CachedValue<LanguageVersionSettings> {
return CachedValuesManager
.getManager(project)
.createCachedValue(
{
CachedValueProvider.Result(
body(),
ProjectRootModificationTracker.getInstance(project)
)
}, false
)
}

View File

@@ -42,7 +42,7 @@ fun isKotlinWithCompatibleAbiVersion(file: VirtualFile): Boolean {
if (!IDEKotlinBinaryClassCache.isKotlinJvmCompiledFile(file)) return false
val kotlinClass = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)
return kotlinClass != null && kotlinClass.classHeader.metadataVersion.isCompatible()
return kotlinClass != null && kotlinClass.metadataVersion.isCompatible()
}
/**
@@ -69,18 +69,18 @@ fun isKotlinInternalCompiledFile(file: VirtualFile, fileContent: ByteArray? = nu
return true
}
val (header, classId) = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file, fileContent) ?: return false
if (classId.isLocal) return true
val header = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file, fileContent) ?: return false
if (header.classId.isLocal) return true
return header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS ||
header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART
}
fun findMultifileClassParts(file: VirtualFile, classId: ClassId, header: KotlinClassHeader): List<KotlinJvmBinaryClass> {
fun findMultifileClassParts(file: VirtualFile, classId: ClassId, partNames: List<String>): List<KotlinJvmBinaryClass> {
val packageFqName = classId.packageFqName
val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
val partNames = header.data ?: return emptyList()
return partNames.mapNotNull {
partsFinder.findKotlinClass(ClassId(packageFqName, Name.identifier(it.substringAfterLast('/'))))
}
}
}

View File

@@ -67,9 +67,11 @@ fun buildDecompiledTextForClassFile(
classFile: VirtualFile,
resolver: ResolverForDecompiler = DeserializerForClassfileDecompiler(classFile)
): DecompiledText {
val (classHeader, classId) = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(classFile)
val classHeader = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(classFile)
?: error("Decompiled data factory shouldn't be called on an unsupported file: " + classFile)
val classId = classHeader.classId
if (!classHeader.metadataVersion.isCompatible()) {
return createIncompatibleAbiVersionDecompiledText(JvmMetadataVersion.INSTANCE, classHeader.metadataVersion)
}
@@ -85,7 +87,7 @@ fun buildDecompiledTextForClassFile(
buildText(listOfNotNull(resolver.resolveTopLevelClass(classId)))
}
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
val partClasses = findMultifileClassParts(classFile, classId, classHeader)
val partClasses = findMultifileClassParts(classFile, classId, classHeader.partNamesIfMultifileFacade)
val partMembers = partClasses.flatMap { partClass ->
resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName())
}

View File

@@ -64,7 +64,7 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
val components = createStubBuilderComponents(file, packageFqName, fileContent)
if (header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS) {
val partFiles = findMultifileClassParts(file, classId, header)
val partFiles = findMultifileClassParts(file, classId, header.multifilePartNames)
return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components)
}

View File

@@ -32,13 +32,14 @@ import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.actions.internal.KotlinInternalMode
import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink
import org.jetbrains.kotlin.psi.KtFile
import kotlin.script.experimental.dependencies.ScriptReport
class ScriptExternalHighlightingPass(
private val file: KtFile,
document: Document
private val file: KtFile,
document: Document
) : TextEditorHighlightingPass(file.project, document), DumbAware {
override fun doCollectInformation(progress: ProgressIndicator) = Unit
@@ -48,60 +49,64 @@ class ScriptExternalHighlightingPass(
val reports = file.virtualFile.getUserData(IdeScriptReportSink.Reports) ?: return
val annotations = reports.mapNotNull { (message, severity, position) ->
val (startOffset, endOffset) = computeOffsets(document, position) ?: return@mapNotNull null
Annotation(
startOffset,
endOffset,
severity.convertSeverity() ?: return@mapNotNull null,
message,
message
val (startOffset, endOffset) = position?.let { computeOffsets(document, position) } ?: 0 to 0
val annotation = Annotation(
startOffset,
endOffset,
severity.convertSeverity() ?: return@mapNotNull null,
message,
message
)
// if range is empty, show notification panel in editor
annotation.isFileLevelAnnotation = startOffset == endOffset
annotation
}
val infos = annotations.map { HighlightInfo.fromAnnotation(it) }
UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id)
}
private fun computeOffsets(document: Document, position: ScriptReport.Position?): Pair<Int, Int>? {
if (position == null) {
// TODO: better presentation of those errors
// if no position was specified, mark first two lines as an error
return computeOffsets(document, ScriptReport.Position(0, 0, 1))
}
private fun computeOffsets(document: Document, position: ScriptReport.Position): Pair<Int, Int> {
val startLine = position.startLine.coerceLineIn(document)
val startOffset = document.offsetBy(startLine, position.startColumn)
val endLine = position.endLine?.coerceAtLeast(startLine)?.coerceLineIn(document) ?: startLine
val endOffset = document.offsetBy(
endLine,
position.endColumn ?: document.getLineEndOffset(endLine)
endLine,
position.endColumn ?: document.getLineEndOffset(endLine)
).coerceAtLeast(startOffset)
// TODO: presentation when range is empty?
return startOffset to endOffset
}
private fun Int.coerceLineIn(document: Document) = coerceIn(0, document.lineCount - 1)
private fun Document.offsetBy(line: Int, col: Int): Int {
return (getLineStartOffset(line) + col).
coerceIn(getLineStartOffset(line), getLineEndOffset(line))
return (getLineStartOffset(line) + col).coerceIn(getLineStartOffset(line), getLineEndOffset(line))
}
private fun ScriptReport.Severity.convertSeverity(): HighlightSeverity? {
return when (this) {
ScriptReport.Severity.FATAL -> ERROR
ScriptReport.Severity.ERROR -> ERROR
ScriptReport.Severity.WARNING -> WARNING
ScriptReport.Severity.INFO -> INFORMATION
else -> null
ScriptReport.Severity.DEBUG -> if (KotlinInternalMode.enabled) INFORMATION else null
}
}
class Factory(project: Project, registrar: TextEditorHighlightingPassRegistrar)
: AbstractProjectComponent(project), TextEditorHighlightingPassFactory {
class Factory(project: Project, registrar: TextEditorHighlightingPassRegistrar) : AbstractProjectComponent(project),
TextEditorHighlightingPassFactory {
init {
registrar.registerTextEditorHighlightingPass(this, TextEditorHighlightingPassRegistrar.Anchor.BEFORE, Pass.UPDATE_FOLDING, false, false)
registrar.registerTextEditorHighlightingPass(
this,
TextEditorHighlightingPassRegistrar.Anchor.BEFORE,
Pass.UPDATE_FOLDING,
false,
false
)
}
override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? {

View File

@@ -93,7 +93,7 @@ object KotlinClassFileIndex : KotlinFileIndexBase<KotlinClassFileIndex>(KotlinCl
private val INDEXER = indexer { fileContent ->
val headerInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(fileContent.file, fileContent.content)
if (headerInfo != null && headerInfo.classHeader.metadataVersion.isCompatible()) headerInfo.classId.asSingleFqName() else null
if (headerInfo != null && headerInfo.metadataVersion.isCompatible()) headerInfo.classId.asSingleFqName() else null
}
}

View File

@@ -27,6 +27,7 @@ import com.intellij.openapi.projectRoots.ex.PathUtilEx
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
import org.jetbrains.kotlin.script.ScriptTemplatesProvider
import org.jetbrains.kotlin.utils.PathUtil
import org.jetbrains.kotlin.utils.addToStdlib.flattenTo
import java.io.File
@@ -46,9 +47,6 @@ class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionPr
private var definitionsByContributor = mutableMapOf<ScriptDefinitionContributor, List<KotlinScriptDefinition>>()
private var definitions: List<KotlinScriptDefinition> = emptyList()
var hasFailedDefinitions = false
private set
fun reloadDefinitionsBy(contributor: ScriptDefinitionContributor) = lock.write {
val notLoadedYet = definitions.isEmpty()
if (notLoadedYet) return
@@ -57,8 +55,6 @@ class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionPr
definitionsByContributor[contributor] = contributor.safeGetDefinitions()
hasFailedDefinitions = getContributors().any { it.isError() }
updateDefinitions()
}
@@ -68,7 +64,6 @@ class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionPr
if (contributor !in definitionsByContributor) error("Unknown contributor: ${contributor.id}")
if (contributor.isError()) return emptyList()
return definitionsByContributor[contributor] ?: emptyList()
}
@@ -105,8 +100,6 @@ class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionPr
definitionsByContributor[contributor] = definitions
}
hasFailedDefinitions = getContributors().any { it.isError() }
updateDefinitions()
}
@@ -170,8 +163,6 @@ interface ScriptDefinitionContributor {
fun getDefinitions(): List<KotlinScriptDefinition>
fun isError(): Boolean = false
companion object {
val EP_NAME: ExtensionPointName<ScriptDefinitionContributor> =
ExtensionPointName.create<ScriptDefinitionContributor>("org.jetbrains.kotlin.scriptDefinitionContributor")

View File

@@ -30,7 +30,7 @@ import kotlin.reflect.KProperty
import kotlin.script.experimental.dependencies.ScriptDependencies
var VirtualFile.scriptDependencies: ScriptDependencies? by ScriptDependenciesProperty()
private val scriptDependencies = FileAttribute("kotlin-script-dependencies", 2, false)
private val scriptDependencies = FileAttribute("kotlin-script-dependencies", 3, false)
private class ScriptDependenciesProperty {

View File

@@ -41,7 +41,6 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.idea.core.util.EDT
import org.jetbrains.kotlin.idea.core.util.cancelOnDisposal
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
import org.jetbrains.kotlin.script.*
@@ -50,6 +49,7 @@ import java.util.concurrent.Executors
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.dependencies.ScriptDependencies
import kotlin.script.experimental.dependencies.ScriptReport
class ScriptDependenciesUpdater(
private val project: Project,
@@ -127,10 +127,6 @@ class ScriptDependenciesUpdater(
}
private fun performUpdate(file: VirtualFile) {
if (ScriptDefinitionsManager.getInstance(project).hasFailedDefinitions && !ProjectRootsUtil.isProjectSourceFile(project, file)) {
return
}
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) ?: return
when (scriptDef.dependencyResolver) {
is AsyncDependenciesResolver, is LegacyResolverWrapper -> {
@@ -211,7 +207,7 @@ class ScriptDependenciesUpdater(
requests.replace(file.path, lastRequest, ModStampedRequest(lastRequest.modificationStamp, job = null))
}
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
val resultingDependencies = (result.dependencies ?: ScriptDependencies.Empty).adjustByDefinition(scriptDef)
val resultingDependencies = result.dependencies?.adjustByDefinition(scriptDef) ?: return
if (saveNewDependencies(resultingDependencies, file)) {
notifyRootsChanged()
}
@@ -220,14 +216,14 @@ class ScriptDependenciesUpdater(
fun updateSync(file: VirtualFile, scriptDef: KotlinScriptDefinition): Boolean {
val newDeps = contentLoader.loadContentsAndResolveDependencies(scriptDef, file) ?: ScriptDependencies.Empty
val result = contentLoader.loadContentsAndResolveDependencies(scriptDef, file)
if (result.reports.any { it.severity == ScriptReport.Severity.FATAL }) return false
val newDeps = result.dependencies?.adjustByDefinition(scriptDef) ?: ScriptDependencies.Empty
return saveNewDependencies(newDeps, file)
}
private fun saveNewDependencies(
new: ScriptDependencies,
file: VirtualFile
): Boolean {
private fun saveNewDependencies(new: ScriptDependencies, file: VirtualFile): Boolean {
val rootsChanged = cache.hasNotCachedRoots(new)
if (cache.save(file, new)) {
file.scriptDependencies = new

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.core.script
@file:Suppress("PackageDirectoryMismatch")
package org.jetbrains.kotlin.script
import com.intellij.openapi.extensions.ExtensionPointName
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import java.io.File
import kotlin.script.experimental.dependencies.DependenciesResolver
@@ -59,13 +59,3 @@ interface ScriptTemplatesProvider {
}
}
class ScriptTemplatesProviderAdapter(private val templatesProvider: ScriptTemplatesProvider) : ScriptDefinitionContributor {
override val id: String
get() = templatesProvider.id
override fun getDefinitions(): List<KotlinScriptDefinition> {
return loadDefinitionsFromTemplates(
templatesProvider.templateClassNames.toList(), templatesProvider.templateClasspath,
templatesProvider.environment.orEmpty(), templatesProvider.additionalResolverClasspath)
}
}

View File

@@ -0,0 +1,22 @@
/*
* 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.core.script
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.script.ScriptTemplatesProvider
class ScriptTemplatesProviderAdapter(private val templatesProvider: ScriptTemplatesProvider) :
ScriptDefinitionContributor {
override val id: String
get() = templatesProvider.id
override fun getDefinitions(): List<KotlinScriptDefinition> {
return loadDefinitionsFromTemplates(
templatesProvider.templateClassNames.toList(), templatesProvider.templateClasspath,
templatesProvider.environment.orEmpty(), templatesProvider.additionalResolverClasspath
)
}
}

View File

@@ -26,6 +26,10 @@ import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
import org.jetbrains.kotlin.script.getScriptDefinition
class KotlinScriptResolveScopeProvider : ResolveScopeProvider() {
companion object {
// Used in LivePlugin
val USE_NULL_RESOLVE_SCOPE = "USE_NULL_RESOLVE_SCOPE"
}
override fun getResolveScope(file: VirtualFile, project: Project): GlobalSearchScope? {
val scriptDefinition = getScriptDefinition(file, project)

View File

@@ -22,12 +22,16 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.fileTypes.LanguageFileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import org.gradle.tooling.ProjectConnection
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
import org.jetbrains.kotlin.lexer.KotlinLexer
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter
import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper
@@ -39,9 +43,14 @@ import org.jetbrains.plugins.gradle.util.GradleConstants
import java.io.File
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.reflect.KClass
import kotlin.script.dependencies.Environment
import kotlin.script.dependencies.ScriptContents
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult
import kotlin.script.experimental.dependencies.ScriptDependencies
import kotlin.script.experimental.dependencies.ScriptReport
import kotlin.script.templates.standard.ScriptTemplateWithArgs
class GradleScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionContributor {
@@ -79,8 +88,6 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD
return loadDefinitions()
}
override fun isError() = failedToLoad.get()
// NOTE: control flow here depends on suppressing exceptions from loadGradleTemplates calls
// TODO: possibly combine exceptions from every loadGradleTemplates call, be mindful of KT-19276
private fun loadDefinitions(): List<KotlinScriptDefinition> {
@@ -109,7 +116,12 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD
return kotlinDslTemplates
}
return tryToLoadOldBuildScriptDefinition()
val default = tryToLoadOldBuildScriptDefinition()
if (default.isNotEmpty()) {
return default
}
return listOf(ErrorGradleScriptDefinition())
}
private fun tryToLoadOldBuildScriptDefinition(): List<KotlinScriptDefinition> {
@@ -137,7 +149,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD
} catch (t: Throwable) {
// TODO: review exception handling
failedToLoad.set(true)
emptyList()
listOf(ErrorGradleScriptDefinition(t.message))
}
@@ -168,10 +180,10 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD
}
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
if (gradleSettings.getLinkedProjectsSettings().isEmpty()) return emptyList()
if (gradleSettings.getLinkedProjectsSettings().isEmpty()) error("Project '${project.name}' isn't linked with Gradle")
val projectSettings =
gradleSettings.getLinkedProjectsSettings().filterIsInstance<GradleProjectSettings>().firstOrNull() ?: return emptyList()
val projectSettings = gradleSettings.getLinkedProjectsSettings().filterIsInstance<GradleProjectSettings>().firstOrNull()
?: error("Project '${project.name}' isn't linked with Gradle")
val gradleExeSettings = ExternalSystemApiUtil.getExecutionSettings<GradleExecutionSettings>(
project,
@@ -207,12 +219,52 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD
ScriptDefinitionsManager.getInstance(project).reloadDefinitionsBy(this)
}
private class ErrorGradleScriptDefinition(message: String? = null) : KotlinScriptDefinition(ScriptTemplateWithArgs::class) {
override val name: String = "Default Kotlin Gradle Script"
override val fileType: LanguageFileType = KotlinFileType.INSTANCE
override val annotationsForSamWithReceivers: List<String> = emptyList()
override val acceptedAnnotations: List<KClass<out Annotation>> = emptyList()
override val dependencyResolver: DependenciesResolver = ErrorScriptDependenciesResolver(message)
override fun getScriptName(script: KtScript) =
Name.identifier(script.containingKtFile.name.removeSuffix(".gradle.kts"))
override fun isScript(fileName: String): Boolean =
fileName.endsWith(".gradle.kts")
}
private class ErrorScriptDependenciesResolver(private val message: String? = null) : DependenciesResolver {
override fun resolve(scriptContents: ScriptContents, environment: Environment): ResolveResult {
val failureMessage = if (ReloadGradleTemplatesOnSync.gradleState.isSyncInProgress) {
"Highlighting is impossible during Gradle Import"
} else {
message ?: "Failed to load script definitions by ${GradleScriptDefinitionsContributor::class.java.name}"
}
return ResolveResult.Failure(ScriptReport(failureMessage, ScriptReport.Severity.FATAL))
}
}
}
internal class GradleSyncState {
var isSyncInProgress: Boolean = false
}
class ReloadGradleTemplatesOnSync : ExternalSystemTaskNotificationListenerAdapter() {
companion object {
internal val gradleState = GradleSyncState()
}
override fun onStart(id: ExternalSystemTaskId) {
if (id.type == ExternalSystemTaskType.RESOLVE_PROJECT && id.projectSystemId == GRADLE_SYSTEM_ID) {
gradleState.isSyncInProgress = true
}
}
override fun onEnd(id: ExternalSystemTaskId) {
if (id.type == ExternalSystemTaskType.RESOLVE_PROJECT && id.projectSystemId == GRADLE_SYSTEM_ID) {
gradleState.isSyncInProgress = false
val project = id.findProject() ?: return
val gradleDefinitionsContributor = ScriptDefinitionContributor.find<GradleScriptDefinitionsContributor>(project)
gradleDefinitionsContributor?.reloadIfNeccessary()

View File

@@ -35,7 +35,7 @@
interface="org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.scriptTemplatesProvider"
interface="org.jetbrains.kotlin.idea.core.script.ScriptTemplatesProvider"
interface="org.jetbrains.kotlin.script.ScriptTemplatesProvider"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.facetConfigurationExtension"
interface="org.jetbrains.kotlin.idea.facet.KotlinFacetConfigurationExtension"/>

View File

@@ -47,8 +47,7 @@ import kotlin.reflect.KProperty1
private fun getDefaultTargetPlatform(module: Module, rootModel: ModuleRootModel?): TargetPlatformKind<*> {
for (platform in TargetPlatformKind.ALL_PLATFORMS) {
if (platform.version == TargetPlatformVersion.NoVersion &&
getRuntimeLibraryVersions(module, rootModel, platform).isNotEmpty()) {
if (getRuntimeLibraryVersions(module, rootModel, platform).isNotEmpty()) {
return platform
}
}

View File

@@ -36,7 +36,7 @@ class KotlinReportSubmitter : ITNReporter() {
override fun showErrorInRelease(event: IdeaLoggingEvent): Boolean {
val notificationEnabled = "disabled" != System.getProperty("kotlin.fatal.error.notification", "enabled")
return !notificationEnabled && (!hasUpdate || KotlinInternalMode.enabled)
return notificationEnabled && (!hasUpdate || KotlinInternalMode.enabled)
}
override fun submit(events: Array<IdeaLoggingEvent>, additionalInfo: String?, parentComponent: Component, consumer: Consumer<SubmittedReportInfo>): Boolean {

View File

@@ -0,0 +1,5 @@
<info descr="Info"></info><warning descr="Warning"></warning><error descr="Fatal"></error><error descr="Error"></error>
1 + 1
// CHECK_WARNINGS
// CHECK_INFOS

View File

@@ -0,0 +1,24 @@
package custom.scriptDefinition
import java.io.File
import kotlin.script.dependencies.*
import kotlin.script.experimental.dependencies.*
import kotlin.script.templates.ScriptTemplateDefinition
class TestDependenciesResolver : DependenciesResolver {
override fun resolve(
scriptContents: ScriptContents,
environment: Environment
): DependenciesResolver.ResolveResult {
return DependenciesResolver.ResolveResult.Failure(
ScriptReport("Error"),
ScriptReport("Fatal", ScriptReport.Severity.FATAL),
ScriptReport("Info", ScriptReport.Severity.INFO),
ScriptReport("Warning", ScriptReport.Severity.WARNING),
ScriptReport("Debug", ScriptReport.Severity.DEBUG)
)
}
}
@ScriptTemplateDefinition(TestDependenciesResolver::class, scriptFilePattern = "script.kts")
open class Template

View File

@@ -1,5 +1,4 @@
<error descr="TestDependenciesResolver threw exception IllegalStateException:
Exception from resolver">
</error>
Exception from resolver"></error>
val s = 3
val g = 4

View File

@@ -26,9 +26,9 @@ import org.jetbrains.kotlin.name.ClassId
import org.junit.Assert
abstract class AbstractInternalCompiledClassesTest : KotlinLightCodeInsightFixtureTestCase() {
private fun isFileWithHeader(predicate: (KotlinClassHeader, ClassId) -> Boolean) : VirtualFile.() -> Boolean = {
private fun isFileWithHeader(predicate: (IDEKotlinBinaryClassCache.KotlinBinaryClassHeaderData, ClassId) -> Boolean) : VirtualFile.() -> Boolean = {
val info = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(this)
info != null && predicate(info.classHeader, info.classId)
info != null && predicate(info, info.classId)
}
protected fun isSyntheticClass(): VirtualFile.() -> Boolean =

View File

@@ -44,7 +44,10 @@ import kotlin.script.dependencies.Environment
abstract class AbstractScriptConfigurationHighlightingTest : AbstractScriptConfigurationTest() {
fun doTest(path: String) {
configureScriptFile(path)
checkHighlighting(editor, false, false)
checkHighlighting(
editor,
InTextDirectivesUtils.isDirectiveDefined(file.text, "// CHECK_WARNINGS"),
InTextDirectivesUtils.isDirectiveDefined(file.text, "// CHECK_INFOS"))
}
}

View File

@@ -79,6 +79,12 @@ public class ScriptConfigurationHighlightingTestGenerated extends AbstractScript
doTest(fileName);
}
@TestMetadata("errorResolver")
public void testErrorResolver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/script/definition/highlighting/errorResolver/");
doTest(fileName);
}
@TestMetadata("javaNestedClass")
public void testJavaNestedClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/script/definition/highlighting/javaNestedClass/");

View File

@@ -94,16 +94,6 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
private val PATH_TO_KOTLIN_JS_LIBRARY = AbstractKotlinJpsBuildTestCase.TEST_DATA_PATH + "general/KotlinJavaScriptProjectWithDirectoryAsLibrary/" + KOTLIN_JS_LIBRARY
private val KOTLIN_JS_LIBRARY_JAR = "$KOTLIN_JS_LIBRARY.jar"
private fun k2jsOutput(vararg moduleNames: String): Array<String> {
val list = arrayListOf<String>()
for (moduleName in moduleNames) {
val outputDir = File("out/production/$moduleName")
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputFile(outputDir, moduleName, false).path))
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputMetaFile(outputDir, moduleName, false).path))
}
return list.toTypedArray()
}
private fun getMethodsOfClass(classFile: File): Set<String> {
val result = TreeSet<String>()
ClassReader(FileUtil.loadFileBytes(classFile)).accept(object : ClassVisitor(Opcodes.ASM5) {
@@ -257,6 +247,21 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
checkWhen(touch("src/test1.kt"), null, k2jsOutput(PROJECT_NAME))
}
private fun k2jsOutput(vararg moduleNames: String): Array<String> {
val list = arrayListOf<String>()
for (moduleName in moduleNames) {
val outputDir = File("out/production/$moduleName")
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputFile(outputDir, moduleName, false).path))
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputMetaFile(outputDir, moduleName, false).path))
val kjsmFiles = File(workDir, outputDir.path).walk()
.filter { it.isFile && it.extension.equals("kjsm", ignoreCase = true) }
list.addAll(kjsmFiles.map { toSystemIndependentName(it.relativeTo(workDir).path) })
}
return list.toTypedArray()
}
fun testKotlinJavaScriptProjectWithSourceMap() {
initProject(JS_STDLIB)
buildAllModules().assertSuccessful()

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.config;
import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VirtualFile;
@@ -23,9 +24,7 @@ import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.util.SmartList;
import com.intellij.util.io.URLUtil;
import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.config.*;
@@ -157,13 +156,12 @@ public class JsConfig {
}
public boolean checkLibFilesAndReportErrors(@NotNull JsConfig.Reporter report) {
return checkLibFilesAndReportErrors(getLibraries(), report, null);
return checkLibFilesAndReportErrors(getLibraries(), report);
}
private boolean checkLibFilesAndReportErrors(
@NotNull Collection<String> libraries,
@NotNull JsConfig.Reporter report,
@Nullable Function1<List<KotlinJavascriptMetadata>, Unit> action
@NotNull JsConfig.Reporter report
) {
if (libraries.isEmpty()) {
return false;
@@ -217,11 +215,14 @@ public class JsConfig {
}
}
if (action != null) {
action.invoke(metadataList);
Set<String> friendLibsSet = new HashSet<>(getFriends());
metadata.addAll(metadataList);
if (friendLibsSet.contains(path)){
friends.addAll(metadataList);
}
}
initialized = true;
return false;
}
@@ -287,9 +288,7 @@ public class JsConfig {
}
private void init() {
if (initialized) return;
if (!getLibraries().isEmpty()) {
if (!initialized) {
JsConfig.Reporter reporter = new Reporter() {
@Override
public void error(@NotNull String message) {
@@ -297,24 +296,8 @@ public class JsConfig {
}
};
boolean hasErrors = checkLibFilesAndReportErrors(getFriends(), reporter, metaList -> {
metadata.addAll(metaList);
friends.addAll(metaList);
return Unit.INSTANCE;
});
hasErrors |= checkLibFilesAndReportErrors(CollectionsKt.subtract(getLibraries(), getFriends()), reporter, metaList -> {
metadata.addAll(metaList);
return Unit.INSTANCE;
});
assert !hasErrors : "hasErrors should be false";
checkLibFilesAndReportErrors(reporter);
}
initialized = true;
}
private final IdentityHashMap<KotlinJavascriptMetadata, JsModuleDescriptor<ModuleDescriptorImpl>> factoryMap = new IdentityHashMap<>();

View File

@@ -43,6 +43,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.jetbrains.kotlin.js.inline.util.CollectUtilsKt.getImportTag;
import static org.jetbrains.kotlin.js.inline.util.CollectionUtilsKt.IdentitySet;
import static org.jetbrains.kotlin.js.translate.declaration.InlineCoroutineUtilKt.transformSpecialFunctionsToCoroutineMetadata;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.flattenStatement;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
@@ -51,6 +52,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
private final JsConfig config;
private final Map<JsName, FunctionWithWrapper> functions;
private final Set<JsFunction> namedFunctionsSet;
private final Map<String, FunctionWithWrapper> accessors;
private final Stack<JsInliningContext> inliningContexts = new Stack<>();
private final Set<JsFunction> processedFunctions = CollectionUtilsKt.IdentitySet();
@@ -129,6 +131,10 @@ public class JsInliner extends JsVisitorWithContextImpl {
) {
this.config = config;
this.functions = functions;
this.namedFunctionsSet = IdentitySet();
for (FunctionWithWrapper functionWithWrapper : functions.values()) {
namedFunctionsSet.add(functionWithWrapper.getFunction());
}
this.accessors = accessors;
this.functionReader = functionReader;
this.trace = trace;
@@ -182,7 +188,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
assert !inProcessFunctions.contains(function): "Inliner has revisited function";
inProcessFunctions.add(function);
if (functions.values().stream().anyMatch(namedFunction -> namedFunction.getFunction().equals(function))) {
if (namedFunctionsSet.contains(function)) {
namedFunctionsStack.push(function);
}
}

View File

@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.AnnotationSerializer
@@ -91,43 +92,90 @@ object KotlinJavascriptSerializationUtil {
}
fun serializeMetadata(
bindingContext: BindingContext,
module: ModuleDescriptor,
moduleKind: ModuleKind,
importedModules: List<String>
): JsProtoBuf.Library {
val builder = JsProtoBuf.Library.newBuilder()
bindingContext: BindingContext,
jsDescriptor: JsModuleDescriptor<ModuleDescriptor>,
languageVersionSettings: LanguageVersionSettings
): SerializedMetadata {
val serializedFragments = HashMap<FqName, ProtoBuf.PackageFragment>()
val module = jsDescriptor.data
val moduleProtoKind = when (moduleKind) {
ModuleKind.PLAIN -> JsProtoBuf.Library.Kind.PLAIN
ModuleKind.AMD -> JsProtoBuf.Library.Kind.AMD
ModuleKind.COMMON_JS -> JsProtoBuf.Library.Kind.COMMON_JS
ModuleKind.UMD -> JsProtoBuf.Library.Kind.UMD
}
if (builder.kind != moduleProtoKind) {
builder.kind = moduleProtoKind
}
importedModules.forEach { builder.addImportedModule(it) }
for (fqName in getPackagesFqNames(module)) {
for (fqName in getPackagesFqNames(module).sortedBy { it.asString() }) {
val fragment = serializePackageFragment(bindingContext, module, fqName)
if (!fragment.isEmpty()) {
builder.addPackageFragment(fragment)
serializedFragments[fqName] = fragment
}
}
return builder.build()
return SerializedMetadata(serializedFragments, jsDescriptor, languageVersionSettings)
}
fun metadataAsString(
bindingContext: BindingContext,
jsDescriptor: JsModuleDescriptor<ModuleDescriptor>,
languageVersionSettings: LanguageVersionSettings
): String = KotlinJavascriptMetadataUtils.formatMetadataAsString(
jsDescriptor.name,
jsDescriptor.serializeToBinaryMetadata(bindingContext, languageVersionSettings)
)
class SerializedMetadata(
private val serializedFragments: Map<FqName, ProtoBuf.PackageFragment>,
private val jsDescriptor: JsModuleDescriptor<ModuleDescriptor>,
private val languageVersionSettings: LanguageVersionSettings
) {
class SerializedPackage(val fqName: FqName, val bytes: ByteArray)
fun serializedPackages(): List<SerializedPackage> {
val packages = arrayListOf<SerializedPackage>()
for ((fqName, part) in serializedFragments) {
val stream = ByteArrayOutputStream()
with(DataOutputStream(stream)) {
val version = JsMetadataVersion.INSTANCE.toArray()
writeInt(version.size)
version.forEach(this::writeInt)
}
serializeHeader(jsDescriptor.data, fqName, languageVersionSettings).writeDelimitedTo(stream)
part.writeTo(stream)
packages.add(SerializedPackage(fqName, stream.toByteArray()))
}
return packages
}
fun asString(): String =
KotlinJavascriptMetadataUtils.formatMetadataAsString(jsDescriptor.name, asByteArray())
private fun asByteArray(): ByteArray =
ByteArrayOutputStream().apply {
GZIPOutputStream(this).use { stream ->
serializeHeader(
jsDescriptor.data,
packageFqName = null,
languageVersionSettings = languageVersionSettings
).writeDelimitedTo(stream)
asLibrary().writeTo(stream)
}
}.toByteArray()
private fun asLibrary(): JsProtoBuf.Library {
val moduleKind = jsDescriptor.kind
jsDescriptor.imported
val builder = JsProtoBuf.Library.newBuilder()
val moduleProtoKind = when (moduleKind) {
ModuleKind.PLAIN -> JsProtoBuf.Library.Kind.PLAIN
ModuleKind.AMD -> JsProtoBuf.Library.Kind.AMD
ModuleKind.COMMON_JS -> JsProtoBuf.Library.Kind.COMMON_JS
ModuleKind.UMD -> JsProtoBuf.Library.Kind.UMD
}
if (builder.kind != moduleProtoKind) {
builder.kind = moduleProtoKind
}
jsDescriptor.imported.forEach { builder.addImportedModule(it) }
for ((_, fragment) in serializedFragments.entries.sortedBy { (fqName, _) -> fqName.asString() }) {
builder.addPackageFragment(fragment)
}
return builder.build()
}
}
private fun serializePackageFragment(bindingContext: BindingContext, module: ModuleDescriptor, fqName: FqName): ProtoBuf.PackageFragment {
val packageView = module.getPackage(fqName)
@@ -151,7 +199,7 @@ object KotlinJavascriptSerializationUtil {
val serializerExtension = KotlinJavascriptSerializerExtension(fileRegistry)
val serializer = DescriptorSerializer.createTopLevel(serializerExtension)
val classDescriptors = DescriptorSerializer.sort(scope).filterIsInstance<ClassDescriptor>()
val classDescriptors = scope.filterIsInstance<ClassDescriptor>().sortedBy { it.fqNameSafe.asString() }
fun serializeClasses(descriptors: Collection<DeclarationDescriptor>) {
fun serializeClass(classDescriptor: ClassDescriptor) {
@@ -210,33 +258,6 @@ object KotlinJavascriptSerializationUtil {
return filesProto.build()
}
fun toContentMap(
bindingContext: BindingContext,
module: ModuleDescriptor,
languageVersionSettings: LanguageVersionSettings
): Map<String, ByteArray> {
val contentMap = mutableMapOf<String, ByteArray>()
for (fqName in getPackagesFqNames(module)) {
val part = serializePackageFragment(bindingContext, module, fqName)
if (part.isEmpty()) continue
val stream = ByteArrayOutputStream()
with(DataOutputStream(stream)) {
val version = JsMetadataVersion.INSTANCE.toArray()
writeInt(version.size)
version.forEach(this::writeInt)
}
serializeHeader(module, fqName, languageVersionSettings).writeDelimitedTo(stream)
part.writeTo(stream)
contentMap[JsSerializerProtocol.getKjsmFilePath(fqName)] = stream.toByteArray()
}
return contentMap
}
private fun ProtoBuf.PackageFragment.isEmpty(): Boolean =
class_Count == 0 && `package`.let { it.functionCount == 0 && it.propertyCount == 0 && it.typeAliasCount == 0 }
@@ -292,18 +313,6 @@ object KotlinJavascriptSerializationUtil {
}
}
private fun JsModuleDescriptor<ModuleDescriptor>.serializeToBinaryMetadata(
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings
): ByteArray {
return ByteArrayOutputStream().apply {
GZIPOutputStream(this).use { stream ->
serializeHeader(data, null, languageVersionSettings).writeDelimitedTo(stream)
serializeMetadata(bindingContext, data, kind, imported).writeTo(stream)
}
}.toByteArray()
}
private fun ByteArray.deserializeToLibraryParts(name: String): JsModuleDescriptor<KotlinJavaScriptLibraryParts> {
val (header, content) = GZIPInputStream(ByteArrayInputStream(this)).use { stream ->
JsProtoBuf.Header.parseDelimitedFrom(stream, JsSerializerProtocol.extensionRegistry) to

View File

@@ -32,10 +32,12 @@ import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
import org.jetbrains.kotlin.js.util.TextOutput
import org.jetbrains.kotlin.js.util.TextOutputImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor
import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import java.io.File
@@ -108,14 +110,15 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
imported = importedModules
)
val settings = config.configuration.languageVersionSettings
val metaFileContent = KotlinJavascriptSerializationUtil.metadataAsString(bindingContext, moduleDescription, settings)
val serializedMetadata = KotlinJavascriptSerializationUtil.serializeMetadata(bindingContext, moduleDescription, settings)
val metaFileContent = serializedMetadata.asString()
val sourceFilesForMetaFile = ArrayList(sourceFiles)
val jsMetaFile = SimpleOutputFile(sourceFilesForMetaFile, metaFileName, metaFileContent)
outputFiles.add(jsMetaFile)
KotlinJavascriptSerializationUtil.toContentMap(bindingContext, moduleDescriptor, settings).forEach {
// TODO Add correct source files
outputFiles.add(SimpleOutputBinaryFile(emptyList(), config.moduleId + VfsUtilCore.VFS_SEPARATOR_CHAR + it.key, it.value))
for (serializedPackage in serializedMetadata.serializedPackages()) {
val outputBinaryFile = kjsmFileForPackage(serializedPackage.fqName, serializedPackage.bytes)
outputFiles.add(outputBinaryFile)
}
}
@@ -129,6 +132,15 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
return SimpleOutputFileCollection(outputFiles)
}
private fun kjsmFileForPackage(packageFqName: FqName, bytes: ByteArray): SimpleOutputBinaryFile {
val ktFiles = (bindingContext.get(BindingContext.PACKAGE_TO_FILES, packageFqName) ?: emptyList())
val sourceFiles = ktFiles.map { VfsUtilCore.virtualToIoFile(it.virtualFile) }
val relativePath = config.moduleId +
VfsUtilCore.VFS_SEPARATOR_CHAR +
JsSerializerProtocol.getKjsmFilePath(packageFqName)
return SimpleOutputBinaryFile(sourceFiles, relativePath, bytes)
}
private fun getCode(output: TextOutput, sourceLocationConsumer: SourceLocationConsumer?) {
program.accept(JsToStringGenerationVisitor(output, sourceLocationConsumer ?: NoOpSourceLocationConsumer))
}

View File

@@ -193,6 +193,54 @@ open class Kapt3IT : Kapt3BaseIT() {
}
}
@Test
fun testRemoveJavaClassICRebuild() {
testICRebuild { project ->
project.projectFile("Foo.java").delete()
}
}
@Test
fun testChangeClasspathICRebuild() {
testICRebuild { project ->
project.projectFile("build.gradle").modify {
"$it\ndependencies { compile 'org.jetbrains.kotlin:kotlin-reflect:' + kotlin_version }"
}
}
}
// tests all output directories are cleared when IC rebuilds
private fun testICRebuild(performChange: (Project) -> Unit) {
val project = Project("incrementalRebuild", directoryPrefix = "kapt2")
val options = defaultBuildOptions().copy(incremental = true)
val generatedSrc = "build/generated/source/kapt/main"
project.build("build", options = options) {
assertSuccessful()
// generated sources
assertFileExists("$generatedSrc/bar/UseBar_MembersInjector.java")
}
performChange(project)
project.projectFile("UseBar.kt").modify { it.replace("package bar", "package foo.bar") }
project.build("build", options = options) {
assertSuccessful()
assertTasksExecuted(listOf(":kaptGenerateStubsKotlin", ":kaptKotlin", ":compileKotlin", ":compileJava"))
// generated sources
assertFileExists("$generatedSrc/foo/bar/UseBar_MembersInjector.java")
assertNoSuchFile("$generatedSrc/bar/UseBar_MembersInjector.java")
// classes
assertFileExists(kotlinClassesDir() + "foo/bar/UseBar.class")
assertNoSuchFile(kotlinClassesDir() + "bar/UseBar.class")
assertFileExists(javaClassesDir() + "foo/bar/UseBar_MembersInjector.class")
assertNoSuchFile(javaClassesDir() + "bar/UseBar_MembersInjector.class")
}
}
@Test
fun testRemoveAnnotationIC() {
val project = Project("simple", directoryPrefix = "kapt2")

View File

@@ -0,0 +1,24 @@
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: "java"
apply plugin: "kotlin"
apply plugin: "kotlin-kapt"
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'com.google.dagger:dagger:2.14.1'
kapt 'com.google.dagger:dagger-compiler:2.14.1'
}

View File

@@ -0,0 +1,14 @@
/*
* 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 bar
import javax.inject.Inject
import foo.*
class UseBar {
@Inject
lateinit var bar: Bar
}

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 foo;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class Bar {
@Inject
public Bar(){
}
}

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 foo;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class Foo {
@Inject
public Foo(){
}
}

View File

@@ -30,6 +30,7 @@ dependencies {
compile project(':kotlin-gradle-plugin-api')
compileOnly project(':compiler')
compileOnly project(':compiler:incremental-compilation-impl')
compileOnly project(':compiler:daemon-common')
compile project(':kotlin-stdlib')
compileOnly project(':kotlin-reflect-api')

View File

@@ -39,5 +39,6 @@ internal class GradleIncrementalCompilerEnvironment(
val artifactFile: File? = null,
val buildHistoryFile: File? = null,
val friendBuildHistoryFile: File? = null,
val usePreciseJavaTracking: Boolean = false
val usePreciseJavaTracking: Boolean = false,
val localStateDirs: List<File> = emptyList()
) : GradleCompilerEnvironment(compilerClasspath, messageCollector, outputItemsCollector, compilerArgs)

View File

@@ -269,7 +269,8 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil
targetPlatform = targetPlatform,
resultDifferenceFile = environment.buildHistoryFile,
friendDifferenceFile = environment.friendBuildHistoryFile,
usePreciseJavaTracking = environment.usePreciseJavaTracking
usePreciseJavaTracking = environment.usePreciseJavaTracking,
localStateDirs = environment.localStateDirs
)
log.info("Options for KOTLIN DAEMON: $compilationOptions")

View File

@@ -84,16 +84,6 @@ open class KaptGenerateStubsTask : KotlinCompile() {
args.destinationAsFile = this.destinationDir
}
override fun clearOutputsBeforeNonIncrementalBuild() {
super.clearOutputsBeforeNonIncrementalBuild()
if (!stubsDir.deleteRecursively()) {
logger.kotlinWarn("Could not delete $stubsDir")
}
stubsDir.mkdirs()
}
override fun execute(inputs: IncrementalTaskInputs) {
val sourceRoots = kotlinCompileTask.getSourceRoots()
val allKotlinSources = sourceRoots.kotlinSourceFiles

View File

@@ -97,9 +97,7 @@ open class KaptTask : ConventionTask(), CompilerArgumentAwareWithInput<K2JVMComp
fun compile() {
/** Delete everything inside generated sources and classes output directory
* (annotation processing is not incremental) */
destinationDir.clearDirectory()
classesDir.clearDirectory()
kotlinSourcesDestinationDir.clearDirectory()
clearOutputDirectories()
val sourceRootsFromKotlin = kotlinCompileTask.sourceRootsContainer.sourceRoots
val rawSourceRoots = FilteringSourceRootsContainer(sourceRootsFromKotlin, { !isInsideDestinationDirs(it) })
@@ -124,11 +122,6 @@ open class KaptTask : ConventionTask(), CompilerArgumentAwareWithInput<K2JVMComp
throwGradleExceptionIfError(exitCode)
}
private fun File.clearDirectory() {
deleteRecursively()
mkdirs()
}
private val isAtLeastJava9: Boolean
get() = compareVersionNumbers(getJavaRuntimeVersion(), "9") >= 0

View File

@@ -341,13 +341,6 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
@Internal
override fun getSourceRoots() = SourceRoots.ForJvm.create(getSource(), sourceRootsContainer)
protected open fun clearOutputsBeforeNonIncrementalBuild() {
logger.kotlinDebug { "Removing all kotlin classes in $destinationDir" }
destinationDir.deleteRecursively()
destinationDir.mkdirs()
}
override fun callCompiler(args: K2JVMCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
sourceRoots as SourceRoots.ForJvm
@@ -371,13 +364,14 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
artifactFile = artifactFile,
buildHistoryFile = buildHistoryFile,
friendBuildHistoryFile = friendTask?.buildHistoryFile,
usePreciseJavaTracking = usePreciseJavaTracking
usePreciseJavaTracking = usePreciseJavaTracking,
localStateDirs = outputDirectories
)
}
}
if (!incremental) {
clearOutputsBeforeNonIncrementalBuild()
clearOutputDirectories(reason = "IC is disabled for the task")
}
try {

View File

@@ -1,7 +1,15 @@
package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.GradleException
import org.gradle.api.Task
import org.gradle.api.tasks.OutputDirectory
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
import org.jetbrains.kotlin.gradle.utils.outputsCompatible
import java.io.File
import kotlin.reflect.KProperty1
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
fun throwGradleExceptionIfError(exitCode: ExitCode) {
when (exitCode) {
@@ -11,4 +19,25 @@ fun throwGradleExceptionIfError(exitCode: ExitCode) {
ExitCode.OK -> {}
else -> throw IllegalStateException("Unexpected exit code: $exitCode")
}
}
internal val <T : Task> T.outputDirectories: List<File>
get() = outputsCompatible.files.files.filter { it.isDirectory }
internal fun <T : Task> T.clearOutputDirectories(reason: String? = null) {
logger.kotlinDebug {
val suffix = reason?.let { " ($it)" }.orEmpty()
"Clearing output directories for task '$path'$suffix:"
}
val outputDirectories = outputDirectories
for (dir in outputDirectories) {
when {
dir.isDirectory -> {
dir.deleteRecursively()
dir.mkdirs()
logger.kotlinDebug { " deleted $dir" }
}
else -> logger.kotlinDebug { " skipping $dir (not a directory)" }
}
}
}