Compare commits

..

326 Commits

Author SHA1 Message Date
Mikhail Glukhikh
ede11fbdd0 Fix compilation in 161 branch (KtLightClassForLocalDeclaration) 2017-03-16 13:38:10 +03:00
Mikhail Glukhikh
823a371fa9 Fix compilation (AbstractAndroidFoldingTest) 2017-03-16 13:29:29 +03:00
Mikhail Glukhikh
ec68471f82 Revert startInWriteAction in quick-fix for EqualsOrHashCodeInspection (no such thing in 161) 2017-03-16 13:29:22 +03:00
mglukhikh
9f5e6f5f9c Quick doc provider test fix (2016.1 platform specific) 2017-03-16 13:29:16 +03:00
mglukhikh
6b9c4c1526 Debugger test fix (161 branch specific) 2017-03-16 13:29:09 +03:00
Mikhail Glukhikh
198fa9733a Revert commit d13c342 to fix KotlinConsoleKeeper in 161 / AS22 2017-03-16 13:29:03 +03:00
Mikhail Glukhikh
34de3283f7 Fix 161 branch IDE tests by removing "compatible build" 2017-03-16 13:28:56 +03:00
mglukhikh
28a2abea4e Fix compilation (KotlinLineMarkerProvider) 2017-03-16 13:28:50 +03:00
mglukhikh
61cb263af6 Fix compilation (KotlinSuspendCallLineMarkerProvider) 2017-03-16 13:28:43 +03:00
Ilya Chernikov
745665dfe7 Fix compilation 2017-03-16 13:28:37 +03:00
Yan Zhulanow
119f81cda3 Revert "Rename: Fix exceptions on moving file with facade class to another package"
This reverts commit f8513abfa1.

(cherry picked from commit e53914d)
2017-03-16 13:28:30 +03:00
Ilya Chernikov
622e8ceb8f Fix test code after KotlinTestUtils api changes 2017-03-16 13:28:23 +03:00
Ilya Chernikov
b862999394 Fix missing api problem by copying functions from newer IOUtil 2017-03-16 13:28:17 +03:00
Dmitry Jemerov
df76ad533e revert Snappy version 2017-03-16 13:28:10 +03:00
Dmitry Jemerov
97fd653235 Revert: Get rid of deprecated (as of IDEA 2016.2) method calls 2017-03-16 13:28:04 +03:00
Dmitry Jemerov
4a32239a88 Fix compilation of AS 2.2 linters against IJ 2016.1 2017-03-16 13:27:58 +03:00
Dmitry Jemerov
b7c35d4545 fix compilation under 161 2017-03-16 13:27:51 +03:00
Dmitry Jemerov
e24a20360a delete postfix template test from 161 branch 2017-03-16 13:27:44 +03:00
Dmitry Jemerov
8291f07464 compilation fix 2017-03-16 13:27:38 +03:00
Dmitry Jemerov
6bee3f8aff set plugins compatible build to a version which is compatible with the Kotlin plugin 2017-03-16 13:27:31 +03:00
Dmitry Jemerov
127e2cba50 Revert: Problem: fix thread leaking check fail on teamcity for ultimate rename tests 2017-03-16 13:27:25 +03:00
Dmitry Jemerov
e6130042a7 fix compilation against 161 (KotlinSteppingCommandProvider) 2017-03-16 13:27:18 +03:00
Dmitry Jemerov
bd49deef41 Revert "Add TransactionGuard application service to KotlinCoreEnvironment"
This reverts commit 3e0b79e40a.
2017-03-16 13:27:11 +03:00
Dmitry Jemerov
581ae0fd86 Revert "Push Down: Support moving members from Java to Kotlin class"
This reverts commit f9e877ce96.
2017-03-16 13:27:05 +03:00
Dmitry Jemerov
2bb965607c until build for 2016.1 version of the plugin 2017-03-16 13:26:58 +03:00
Dmitry Jemerov
a23fe719c8 do not register Kotlin postfix template provider 2017-03-16 13:26:51 +03:00
Dmitry Jemerov
6b74b8cf0b Revert: Fix goto implementation tests - deffered task should be executed 2017-03-16 13:26:45 +03:00
Dmitry Jemerov
a3fd53b843 Revert: Fix goto implementation tests - deffered task should be executed 2017-03-16 13:26:39 +03:00
Dmitry Jemerov
e1afe868e8 Revert: Test only: method signature changed 2017-03-16 13:26:32 +03:00
Dmitry Jemerov
97bb1a92e3 Revert: Problem: workaround thread leaking problem 2017-03-16 13:26:25 +03:00
Dmitry Jemerov
12d7461cdd Revert: Register TypeAnnotationModifier EP in environment for web demo converter 2017-03-16 13:26:19 +03:00
Dmitry Jemerov
233cbf1069 Revert: Tests only: codeCleanup() method signature was changed 2017-03-16 13:26:12 +03:00
Dmitry Jemerov
5988728417 Revert: Tests only: Constructor for XWatchesViewImpl was changed 2017-03-16 13:26:06 +03:00
Dmitry Jemerov
89c2b98629 Revert: Tests only: add new method in MockPsiManager.java 2017-03-16 13:25:59 +03:00
Dmitry Jemerov
d0dff3638c Revert: Tests only: reparseRange parameters changed 2017-03-16 13:25:52 +03:00
Dmitry Jemerov
cb3804c7e4 Revert: Tests only: implement new method 2017-03-16 13:25:46 +03:00
Dmitry Jemerov
97187fa5d2 Revert: Register TypeAnnotationModifier as extension point 2017-03-16 13:25:39 +03:00
Dmitry Jemerov
b336ad43c5 Revert: More write action requirement remove 2017-03-16 13:25:32 +03:00
Dmitry Jemerov
8c75426545 Revert: API Change: Implement new method isSuppressAll() 2017-03-16 13:25:26 +03:00
Dmitry Jemerov
06dbc029d8 Revert startInWriteAction() methods 2017-03-16 13:25:19 +03:00
Dmitry Jemerov
cf9369264e Revert: registerUnresolvedError is in base class in idea from br146 2017-03-16 13:25:13 +03:00
Dmitry Jemerov
7def1618a8 Revert: Patch ThreadTracker during Kotlin plugin init 2017-03-16 13:25:05 +03:00
Dmitry Jemerov
c0d6987a3a revert IDEA version to 2016.1.2 2017-03-16 13:24:59 +03:00
Alexey Sedunov
0e4c3ec202 Kotlin Facet: Do not present imported -d/-cp in "Additional arguments" 2017-03-16 03:14:41 +03:00
Alexey Sedunov
88a394e892 Kotlin Facet: Validate "additional arguments"
Validate consistency of "additional arguments" with respect to settings specified in other UI controls
2017-03-16 03:14:40 +03:00
Alexey Sedunov
fa06965ed6 Kotlin Facet: Add import test for Maven project with submodule 2017-03-16 03:14:39 +03:00
Alexey Sedunov
cf9d7a0470 Kotlin Facet: Detect platform by stdlib dependency in android-gradle projects
#KT-16827 Fixed
2017-03-16 03:14:38 +03:00
Alexey Sedunov
040f5f88f2 Configuration: Show warning in project settings if they'are overridden in some modules(s) 2017-03-16 03:14:37 +03:00
Alexey Sedunov
5dc5ca551f Configuration: Make UI improvements
Use JTextField for output file prefix/postfix.
Use TextFieldWithBrowseButton for output directory
Improve layout
2017-03-16 03:14:36 +03:00
Alexey Sedunov
ee36abd73a Kotlin Facet: Drop obsolete facet detection infrastructure 2017-03-16 03:14:35 +03:00
Alexey Sedunov
5c55b9fbbe Configuration: Check that project-level common arguments are not changed through platform-specific holders 2017-03-16 03:14:34 +03:00
Alexey Sedunov
ce434585e3 J2K: Convert BaseKotlinCompilerSettings and its inheritors 2017-03-16 03:14:32 +03:00
Alexey Sedunov
f8e5065845 J2K: Convert BaseKotlinCompilerSettings and its inheritors (rename to .kt) 2017-03-16 03:14:31 +03:00
Pavel V. Talanov
f1c0d5316f Refactor delegate members to light members conversion 2017-03-15 20:55:42 +03:00
Pavel V. Talanov
eedcc19209 J2K KtLightClassBase: rename file 2017-03-15 20:55:41 +03:00
Pavel V. Talanov
04591bb938 LightClassDataHolder: refactor, extract subinterfaces 2017-03-15 20:55:40 +03:00
Pavel V. Talanov
6d595e30c2 ClassFileFactory, minor: make done() public and use in LightClassDataProvider 2017-03-15 20:55:40 +03:00
Pavel V. Talanov
d62db8dc6b LightClassGenerationSupport: refactor, minor
Use typealias where appropriate
Less verbose method names
2017-03-15 20:55:39 +03:00
Pavel V. Talanov
a645dc109a KotlinLightClassBuilderFactory, LightClassBuilder: refactor, clarify 2017-03-15 20:55:38 +03:00
Pavel V. Talanov
c73e58516b Refactor LightClassDataProvider: drop LightClassDataProvider class
Move code to inheritors
Improve api to avoid getting empty file lists in random places
2017-03-15 20:55:37 +03:00
Pavel V. Talanov
ab0d939626 searchHelpers: remove hack relying on light classes triggering resolve 2017-03-15 20:55:08 +03:00
Pavel V. Talanov
feae5079ed Light classes: refactor, introduce lazyPub util to reduce verbosity 2017-03-15 20:55:07 +03:00
Pavel V. Talanov
ba185d7616 LightClassDataProvider: refactor, extract class filters to separate classes 2017-03-15 20:55:05 +03:00
Pavel V. Talanov
48cae0e480 KtLightField/Method: Use equality in equivalence checks
Avoid computing delegate to determine equivalence
2017-03-15 20:55:03 +03:00
Pavel V. Talanov
8054020f61 IDELightClassContexts: @PublishedApi affects codegen 2017-03-15 20:55:02 +03:00
Pavel V. Talanov
d846d05527 PsiElementChecker: minor
Check own members before inners' since it triggers the computation of outer stub
2017-03-15 20:55:01 +03:00
Pavel V. Talanov
d34b73befb Light class codegen: all objects are considered static
Simplify code handling access flag computation
Fix a problem where kotlin nested object wasn't producing a nested light class
2017-03-15 20:55:01 +03:00
Pavel V. Talanov
d94da5af40 Frontend: create component functions for properties with error types
Fixes an inconsistency in light classes where we could have different
  class structure depending on whether the type was resolved
2017-03-15 20:55:00 +03:00
Pavel V. Talanov
fa58f1b4d7 KtLightMethod(Field): use dummyDelegate to determine modifier properties 2017-03-15 20:54:59 +03:00
Pavel V. Talanov
abf206a134 KtLightMethod(Field): do not use clsDelegate in hashCode && equality checks 2017-03-15 20:54:58 +03:00
Pavel V. Talanov
fee29c47c8 KtLightMethod: use dummy delegate to compute parameter count and isContructor 2017-03-15 20:54:56 +03:00
Pavel V. Talanov
3e7357a5d7 IDELightClassTest: provide tools to check laziness of light class construction
StubComputationTracker knows which context was used to construct light class
2017-03-15 20:54:55 +03:00
Pavel V. Talanov
daef8a0eed Light classes in IDE: Make light class delegate construction a two step process
Step 0: Light class object is created, no delegates are computed
Step 1: constructs dummy delegate which can not be relied upon to know signature of any member
		It can be used to construct light field and light method objects
		(which can correctly respond to some queries) before constructing real delegate
Step 2:
		Construct real delegate if dummy delegate is not enough to respond to a query

This speeds up multiple scenarios where getMethods() and getFields() are called on numerous classes

Dummy delegate's faster consruction is achieved by using specially setup dumb analysis instead of ide analysis

Introduce LazyLightClassDataHolder: which manages creation of Step 1 and Step 2 delegates
Introduce MemberIndex: keeping track of member creation order, helps matching light class delegates created in different contexts
KtLightMethod and Field: make use of dummy delegate
KtLightMethod no longer extends LightMethod since it requires eager delegate construction
KtLightMethod now implements PsiAnnotationMethod for convenience (ClsMethodImpl implements PsiAnnotationMethod)
2017-03-15 20:54:55 +03:00
Pavel V. Talanov
ed9e94c632 KtLightModifierListWithExplicitModifiers: fix equals 2017-03-15 20:53:59 +03:00
Pavel V. Talanov
d01aaeb65c Refactor light classes: Delegate LightClassDataHolder construction to LightClassGenerationSupport 2017-03-15 20:53:58 +03:00
Pavel V. Talanov
00e84fb483 Light classes: Refactor construction
Introduce LightClassDataHolder: which now is reponsible for constructing clsDelegate
Move out light big chunk of delegate building logic out of LightClassDataProvider into LightClassBuilder
LightClassData only holds information about single class
2017-03-15 20:53:37 +03:00
Pavel V. Talanov
22fb9ec5e1 Refactor light classes: move light members creation to their respective classes 2017-03-15 20:52:51 +03:00
Pavel V. Talanov
15b063d236 J2K LightClassGenerationSupport: rename file 2017-03-15 20:52:50 +03:00
Pavel V. Talanov
dd2d9c1dc2 J2K LightClassGenerationSupport: convert code 2017-03-15 20:52:49 +03:00
Pavel V. Talanov
71161e218b Refactor LightClassData: remove redundant entities 2017-03-15 20:52:48 +03:00
Pavel V. Talanov
0a0e628068 Refactor: move code to new package 2017-03-15 20:52:26 +03:00
Pavel V. Talanov
ac368ac182 Light classes test: test methods & fields with same name 2017-03-15 20:52:25 +03:00
Pavel V. Talanov
955fe9e1e6 Light class tests: add tests
- test Jvm* annotations with wrong arguments
  - test JvmStatic annotation
  - test JvmName annotation
2017-03-15 20:52:24 +03:00
Pavel V. Talanov
dbcd141a46 Extract superclass from AnnotationResolver 2017-03-15 20:52:24 +03:00
Pavel V. Talanov
8794005234 JvmPlatform#getDefaultImports: avoid recomputing JvmBuiltins
We need to use LockBasedStorageManager() (instead of NO_LOCKS) since getDefaultImports()
    can be called concurrently in certain scenarios
2017-03-15 20:52:23 +03:00
Pavel V. Talanov
bbe3b3cabe WrappedType: introduce WrappedTypeFactory to encapsulate wrapped types creation 2017-03-15 20:52:22 +03:00
Pavel V. Talanov
85420d1ffd MemberCodegen: Do not try to write inner class metadata for inner class 2017-03-15 20:51:22 +03:00
Pavel V. Talanov
1441aea2ea Light classes: allow light classes for inner/nested classes to be build separately
Avoid analyzing/generating bytecode for outers
2017-03-15 20:51:22 +03:00
Pavel V. Talanov
6924ddeace Clarify logic in KotlinTypeMapper.mapType() dealing with enum entries
This allows to write correct class signatures for enum entries
    regardless of whether ASM_TYPE slice was written to
2017-03-15 20:51:20 +03:00
Pavel V. Talanov
6f6a595fef Refactor FileScopeFactory 2017-03-15 20:51:19 +03:00
Pavel V. Talanov
d7c1993194 FileScopeFactory: postpone default import resolver construction 2017-03-15 20:51:18 +03:00
Pavel V. Talanov
babb3b557d J2K ImportPath: kotlinify 2017-03-15 20:51:17 +03:00
Pavel V. Talanov
50d0f5bde6 J2K ImportPath: autoconvert 2017-03-15 20:50:12 +03:00
Pavel V. Talanov
91e8d9e211 J2K ImportPath: rename file 2017-03-15 20:49:22 +03:00
Simon Ogorodnik
e7753c31db Minor: Add Dokka format param to build-docs script
To have an ability to change it in TeamCity between custom builds
2017-03-15 19:43:14 +03:00
Simon Ogorodnik
38047240d3 Fix documentation for stdlib
Add forgotten files to file list used by
Dokka when generating documentation
2017-03-15 18:26:52 +03:00
Simon Ogorodnik
5c4ba53f42 Optimization of Basic Code Completion
Now we first search for simple reference variants, then for extensions
 Because extension search is slow
 #KT-16856
2017-03-15 17:50:29 +03:00
Simon Ogorodnik
4906ddfc29 Optimization of Basic Code Completion
Now we don't perform code formatting on temporary psi used
  in ShadowedDeclarationFilter
  #KT-16856
2017-03-15 17:50:20 +03:00
Mikhail Glukhikh
bbab0f11ca Cleanup: fix some "leaking this" warnings 2017-03-15 17:36:08 +03:00
Mikhail Glukhikh
045a23ae10 Cleanup: apply "Convert lambda to reference" 2017-03-15 17:36:02 +03:00
Mikhail Glukhikh
b121bf8802 Cleanup: fix some compiler warnings (mostly deprecations, javaClass) 2017-03-15 17:35:31 +03:00
Mikhail Glukhikh
d0cc1635db Cleanup: apply "Use synthetic property access syntax" 2017-03-15 16:13:40 +03:00
Mikhail Glukhikh
1375267996 Cleanup: apply redundant curly braces in string template inspection 2017-03-15 16:13:22 +03:00
Mikhail Glukhikh
e37800d056 Cleanup: apply redundant string template inspection 2017-03-15 16:12:59 +03:00
Igor Chevdar
10ea2883f7 Supported KProperty2 and KMutableProperty2 for delegated properties
Consider this code:
object Delegate {
    operator fun getValue(t: Any?, p: KProperty<*>): String {
        return ""
    }
}

class A {
    val String.ext by Delegate
}

then the type of <p> is KProperty2 (it has 2 receivers).

Test fix + review fixes
2017-03-15 12:20:57 +03:00
Alexander Udalov
d58d75c6ef Refactor "do not check impl" flag for multi-platform projects
Instead of LanguageFeature, make it an AnalysisFlag, which is more clear
2017-03-15 11:03:05 +03:00
Alexander Udalov
56201a6dc4 Refactor skipMetadataVersionCheck flag
To make addition of other flags easier in the future, provide a more
abstract 'isFlagEnabled' in LanguageVersionSettings
2017-03-15 11:03:04 +03:00
Alexander Udalov
7a240b63c7 Use LanguageFeature.State enum instead of CoroutineSupport 2017-03-15 11:03:03 +03:00
Alexander Udalov
34e131c928 Refactor LanguageVersionSettings.isApiVersionExplicit
Pass it in the CompilerConfiguration instead of LanguageVersionSettings.
This is better because LanguageVersionSettings is accessible everywhere
in front-end and back-end, and this flag should not be used there
2017-03-15 11:03:01 +03:00
Alexander Udalov
32826c1686 Introduce LanguageFeature.State, drop coroutines-related pseudofeatures
Previously there were three LanguageFeature instances -- Coroutines,
DoNotWarnOnCoroutines and ErrorOnCoroutines -- which were handled very
awkwardly in the compiler and in the IDE to basically support a language
feature with a more complex state: not just enabled/disabled, but also
enabled with warning and enabled with error. Introduce a new enum
LanguageFeature.State for this and allow LanguageVersionSettings to get
the state of any language feature with 'getFeatureSupport'.

One noticeable drawback of this approach is that looking at the API, one
may assume that any language feature can be in one of the four states
(enabled, warning, error, disabled). This is not true however; there's
only one language feature at the moment (coroutines) for which these
intermediate states (warning, error) are handled in any way. This may be
refactored further by abstracting the logic that checks the language
feature availability so that it would work exactly the same for any
feature.

Another issue is that the difference among ENABLED_WITH_ERROR and
DISABLED is not clear. They are left as separate states because at the
moment, different diagnostics are reported in these two cases and
quick-fixes in IDE rely on that
2017-03-15 11:03:00 +03:00
Alexander Udalov
cf7048dd0f Do not inject CompilerConfiguration into compiler front-end
Inject LanguageVersionSettings instead; all information relevant to the
analysis should be now passed via an instance of LanguageVersionSettings
(which should be renamed to a more general name in the future).

This is partially a revert of d499998 and related commits
2017-03-15 11:02:59 +03:00
Alexander Udalov
a879cb0cfd Minor, take LanguageVersionSettings in CompilerDeserializationConfiguration 2017-03-15 11:02:58 +03:00
Alexander Udalov
ac530ac49c Move skipMetadataVersionCheck flag to LanguageVersionSettings
This makes it possible to avoid the CompilerConfiguration instance in
injectors, because CompilerDeserializationConfiguration was the only
left component that required it.

LanguageVersionSettings is not a good name for this entity anymore, it
should be renamed in the future
2017-03-15 11:02:58 +03:00
Alexander Udalov
f5d4dd33da Inject JvmTarget into some JVM-specific call checkers
This makes it possible to drop CompilerConfiguration from
CallCheckerContext, which in turn helps to avoid passing the entire
CompilerConfiguration instance through front-end
2017-03-15 11:02:57 +03:00
Alexander Udalov
573c6ab5d4 Move JvmTarget to frontend.java, introduce TargetPlatformVersion
Previously JvmTarget was declared in module 'util' which is accessible
for example from 'frontend', which is not very good.

Also add a superinterface named TargetPlatformVersion which is going to
be used in platform-independent injectors in 'frontend' in the following
commits. Use it in one place (LanguageVersionSettingsProviderImpl.kt)
instead of DescriptionAware because TargetPlatformVersion sounds like a
better abstraction than DescriptionAware here
2017-03-15 11:02:56 +03:00
Denis Zharkov
d2cd5d46fa Minor. Use static method from super class
It was a code with warning
2017-03-15 10:47:12 +03:00
Denis Zharkov
dcc98e3839 Improve check for statements-only postfix templates
Before this change the check was quite complicated
because of cases like:
for (i in 1..9)
    foo(i)<caret>

It's not located in a block, but in the same time it's a stament.
So we had a tricky heuristics that if is parent is not a block, then
we should check if element isn't used as expression.

Of course this heuristics is wrong, e.g. for import/package nodes.

The solution is to reuse similar logic from BasicExpressionTypingVisitor.
it has been checked once that statement container is one of:
- KtBlockExpression
- KtContainerNodeForControlStructureBody
- KtWhenEntry

So there's no need to check anything else

 #KT-14986 Fixed
 #KT-14483 Fixed
2017-03-15 10:47:12 +03:00
Denis Zharkov
78ffe47bf8 Fix samples for 'iter' postfix template
#KT-14727 Fixed
2017-03-15 10:47:12 +03:00
Denis Zharkov
bd88919411 Refine predicate for 'iter' postfix template
Use IterableTypesDetection to determine if the given expression may be iterated

 #KT-14134 Fixed
 #KT-14129 Fixed
2017-03-15 10:47:12 +03:00
Denis Zharkov
465a424af4 Refactor postfix template selector
Allow to specify predicate by KtExpression instead of type predicate
It will be used for `for` template which need a context to determine
whether the expression is iterable
2017-03-15 10:47:12 +03:00
Vyacheslav Gerasimov
b8ebc087e2 Add inspection for calls of function with lambda expression body
Added "Unused return value of a function with lambda expression body" inspection with quickfix "Remove '=' token from function declaration"

#KT-10393 Fixed
2017-03-15 00:22:31 +03:00
Vyacheslav Gerasimov
087551ad61 Implement quick fix for "Invalid type of annotation member"
Quickfix changes array of boxed type to array of primitive type

#KT-8568 Fixed
2017-03-15 00:21:24 +03:00
Vyacheslav Gerasimov
b8563f7fcf Fix KotlinUastTypesTest.testCycleInTypeParameters 2017-03-15 00:20:40 +03:00
Mikhail Glukhikh
cab80812ef KT-13111: lambda --> reference supports also object members 2017-03-14 18:45:08 +03:00
Mikhail Glukhikh
631f58f27f Lambda --> reference: correct handling of companion references
Reference receivers are named more accurately now #KT-13341 Fixed
2017-03-14 18:45:06 +03:00
Mikhail Glukhikh
2c692de98f KT-13111: lambda --> reference support methods called via this now 2017-03-14 18:45:05 +03:00
Mikhail Glukhikh
19db4869e6 Lambda --> reference: correct handling of parameter-less function
Issue #KT-15556 Fixed
2017-03-14 18:45:04 +03:00
Mikhail Glukhikh
b6974a88c5 Refactoring: convert lambda --> reference intention 2017-03-14 18:45:02 +03:00
Mikhail Glukhikh
3a14a5c461 Lambda --> reference supports bound references now #KT-13111 Fixed 2017-03-14 18:45:01 +03:00
Mikhail Glukhikh
831467891c Reference --> lambda supports bound references now #KT-16292 Fixed 2017-03-14 18:45:00 +03:00
Yan Zhulanow
f6734e74e1 Minor, SamWithReceiver: Fix services for kotlinc CLI execution
Move service files to META-INF to support execution from CLI (using PluginCliParser).
2017-03-14 18:36:40 +03:00
Mikhael Bogdanov
23698f93e0 Fix reification for crossinline lambdas inlined into object literal
Inline lambda could capture reified parameter of containing inline function ('a' function)
when it is inlined in another one.
If it's inlined in any anonymous object we should track it and
add reification marker to such anonymous object instance creation
to rewrite it on inlining bytecode of 'a' function.

  #KT-15997 Fixed
2017-03-14 15:54:13 +01:00
Alexey Sedunov
6b6d7a5030 Configuration: Don't create kotlinc.xml if the settings don't differ from the defaults
#KT-16647 Fixed
2017-03-14 15:33:11 +03:00
Alexey Sedunov
e8749e639c Kotlin Facet: Add link to project-level compiler settings UI
#KT-16022 Fixed
2017-03-14 15:33:10 +03:00
Alexey Sedunov
8c91dc579a Kotlin Facet: Show project-level settings when "Use project settings" is selected
#KT-16023 Fixed
2017-03-14 15:33:09 +03:00
Alexey Sedunov
9bbea47f93 Kotlin Facet: Parse and merge compiler arguments specified in <arg> elements instead of appending them (to avoid duplication)
#KT-16776 Fixed
2017-03-14 15:33:08 +03:00
Alexey Sedunov
e5a128ab2e JPS: Parse and merge additional arguments with primary ones instead of
appending them (to avoid duplication)
 #KT-16788 Fixed
2017-03-14 15:33:07 +03:00
Alexey Sedunov
73b879ea89 Misc: Include cli-parser 1.1.2 sources into the project under different package and drop original library dependency
This would allow building the project with Kotlin JPS plugin on TeamCity where older library takes precendence due to appearing earlier in JPS classpath
2017-03-14 15:33:06 +03:00
Dmitry Jemerov
e037e9de39 Do not cache contents in VFS when reading contents of .jar files
This follows the standard IDEA policy of caching file contents.
2017-03-14 13:06:47 +01:00
Dmitry Jemerov
8d1d76cdae Try to recover from corrupt VFS data for a .kotlin_module file
#KT-13135 Fixed
2017-03-14 13:06:29 +01:00
Mikhail Zarechenskiy
da53317357 Fix exception when type parameters appear in object declaration
#KT-14536 Fixed
2017-03-14 01:10:00 +03:00
Mikhail Zarechenskiy
0568bc3ef1 Add note about JS to the changelog 2017-03-13 21:09:17 +03:00
Mikhail Zarechenskiy
fd80c0d1d1 Remove KT-15200 from the changelog
It was postponed until 1.1.2
2017-03-13 20:38:43 +03:00
Mikhail Zarechenskiy
05ef705609 Add IGNORE_BACKEND directive for native automatically
Also parse correctly case IGNORE_BACKEND: JS, NATIVE
2017-03-13 19:56:13 +03:00
Dmitry Jemerov
006062499c Optimize imports (to fix compilation under 171 branch) 2017-03-13 16:34:48 +01:00
Mikhail Zarechenskiy
774aa720b4 Update Changelog for version 1.1.1 2017-03-13 16:45:25 +03:00
Dmitry Petrov
a0a8beee82 Handle TypeAliasDescriptor in AdaptiveClassifierNamePolicy
(as ClassDescriptor)
2017-03-13 14:15:27 +03:00
Mikhael Bogdanov
ce3b455f57 Fix for KT-16801: Accessors of @PublishedApi property gets mangled
#KT-16801 Fixed
2017-03-13 10:51:10 +01:00
Dmitry Petrov
c46164481a KT-15871 Unnecessary boxing for equality operator on inlined primitive values
Allow kotlin.jvm.internal.Intrinsics#areEqual for boxed values.
Rewrite to primitive equality.

NB we can't do that for Float and Double, because java.lang.Float#equals
and java.lang.Double#equals behave differently from primitive equality comparisons.
2017-03-13 09:04:31 +03:00
Dmitry Petrov
a087ea559f Eliminate redundant CHECKCAST instructions
CHECKCAST is redundant if the corresponding static type exactly matches the target type.
CHECKCAST instructions to-be-reified should not be eliminated.

KT-14811 Unnecessary checkcast generated in parameterized functions
KT-14963 unnecessary checkcast java/lang/Object
2017-03-13 09:04:31 +03:00
Dmitry Petrov
ec403bfdbc KT-16245 Redundant null-check generated for a cast of already non-nullable value
KT-16194 Code with unnecessary safe call contains redundant boxing/unboxing for primitive values
KT-12839 Two null checks are generated when manually null checking platform type

Recognize some additional cases of trivial null checks and trivial instance-of checks.

A variable is "checked for null", if it is:
- a function parameter checked with 'INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull'
- checked for nullability with 'IFNULL/IFNONNULL'
- checked for nullability with 'INSTANCEOF'
  (if objectref is instance-of T, then objectref is non-null)

Before analyzing nullability, introduce synthetic assumptions for execution branches
where a variable is guaranteed to be null or not null. For example, the following bytecode:

     ALOAD 1 // Ljava/lang/String;
     IFNULL L
     <non-null branch>
  L:
     <null branch>

is transformed to

     ALOAD 1
     IFNULL L1
     NEW java/lang/String
     ASTORE 1            // tells analyzer that variable 1 is non-null
     <non-null branch>
  L:
     <null branch>
  L1:
     ACONST_NULL
     ASTORE 1            // tells analyzer that variable 1 is null
     GOTO L

After the analysis is performed on a preprocessed method,
remember the results for "interesting" instructions
and revert the preprocessing transformations.

After that, perform bytecode transformations as usual.

Do not transform INSTANCEOF to-be-reified, because reification at call site
can introduce null checks. E.g.,

    inline fun <reified T> isNullable() = null is T
    ...
    assert(isNullable<String?>())
2017-03-13 09:04:31 +03:00
Dmitry Petrov
3c09a26e16 KT-5248 Don't wrap variable if it is captured only in inlined closures
Remove non-escaping Ref's on bytecode postprocessing pass.
2017-03-13 09:04:31 +03:00
Dmitry Petrov
3fc106572e Make redundant null check optimization independent of boxing optimization algorithm.
Run DCE after each single redundant null check optimization pass.
2017-03-13 09:04:31 +03:00
Ilya Matveev
eda43c8b45 Mute tests with standard collection extensions in native 2017-03-10 19:59:37 +03:00
Ilya Matveev
29e5ad5abe Mute tests with '::class' in native backend 2017-03-10 19:59:37 +03:00
Ilya Matveev
8a3fa2e4e5 Fix expected SMAPs after test muting for native 2017-03-10 19:59:37 +03:00
Ilya Matveev
a5e4e0284e Mute some box tests for native backend
This patch mutes the following test categories:
   * Tests with java dependencies (System class,
     java stdlib, jvm-oriented annotations etc).
   * Coroutines tests.
   * Reflection tests.
   * Tests with an inheritance from the standard
     collections.
2017-03-10 19:59:37 +03:00
Alexander Udalov
d21d362f0f Allow enum entries in double colon LHS with LV = 1.0
#KT-16782 Fixed
2017-03-10 19:44:00 +03:00
Denis Zharkov
39055229a1 Add diagnostic info to assertion on type argument consistency 2017-03-10 18:17:50 +03:00
Vyacheslav Gerasimov
830bf62d94 Fix SOE from UAST in containsLocalType
containsLocalType now properly handles start projections
#KT-16680 Fixed
2017-03-10 17:30:21 +03:00
Simon Ogorodnik
4e98394c38 Fix Sample reference to resolve cross-module packages correctly
Now @sample links to FqName in IDE will be resolved correctly
 Cause now we resolve packages over all modules in project
 #KT-14710 fixed
2017-03-10 15:33:47 +03:00
Nikolay Krasko
688802de51 Check breakpoints work in delegate initializer
Additional test after review
2017-03-10 14:59:37 +03:00
Nikolay Krasko
e6ee933b27 Fix "smart step into" for classes with complex hierarchy (KT-16667)
#KT-16667 Fixed
2017-03-10 14:58:21 +03:00
Nikolay Krasko
6d9b519bb2 Use new utility method for getting lexical scope
It's expected that for call expressing some nearest parent will have
lexical scope written in binding context. Under this circumstances it's
refactoring.
2017-03-10 14:58:17 +03:00
Nikolay Krasko
0a7a73d4be Refactoring: extract method for getting lexical scope without facade 2017-03-10 14:58:16 +03:00
Nikolay Krasko
9120ccc054 Fix breakpoints in inline calls in fields initialization (KT-16525)
Backend generates properties initializer in constructor context

 #KT-16525 Fixed
2017-03-10 14:58:15 +03:00
Nikolay Krasko
d886cd7d06 Fix breakpoints when inline call is in qualified expression (KT-16062)
Scope is stored for DOT_QUALIFIED_EXPRESSION not directly for
CALL_EXPRESSION.

 #KT-16062 Fixed
2017-03-10 14:58:14 +03:00
Nikolay Krasko
2719016539 Fix search of correspondent call expression by element (KT-11234)
getStrictParentOfType() looks for nearest parent of given type

In complex expressions like:

SamConversion.doAction({
  inlineCall {
    {
      // here <--
    }()
  }
})

doAction was found twice, while inlineCall was skipped.

See code:
// call(param, { <it> })
lambdaExpression?.typedParent<KtValueArgument>()?.typedParent<KtValueArgumentList>()?.typedParent<KtCallExpression>() ?:

// call { <it> }
lambdaExpression?.typedParent<KtLambdaArgument>()?.typedParent<KtCallExpression>()

 #KT-11234 Fixed
2017-03-10 14:58:13 +03:00
Nikolay Krasko
b240ae791c Minor: extract variable 2017-03-10 14:58:12 +03:00
Denis Zharkov
52d11eb22b Minor. Revert workarounds for problem on KClass from annotation
See KT-9453 for clarification
2017-03-10 13:49:07 +03:00
Denis Zharkov
82d7a269ed Minor. Make sure that implicit contract of mapSignature is satisfied
For ordinary functions mapSignature doesn't use original descriptor
and maps the given descriptor itself, but for constructor it obtained
the original value parameters.

Necessary `getOriginal` calls were added to the call-sites
2017-03-10 13:49:06 +03:00
Denis Zharkov
394c68c326 Minor. Move unwrapping of FunctionImportedFromObject
It should not affect the semantics, because mapSignatureWithCustomParameters
can only be called with FunctionImportedFromObject from mapSignature.

At the same time it's very nice to have all of these kinds
of custom unwrapping in the same place
2017-03-10 13:49:06 +03:00
Denis Zharkov
530214fcee Minor. Simplify mapping to callable method
There's no need in unwrapping for TypeAliasConstructorDescriptor
because mapSignatureSkipGeneric/mapDefaultMethod already do it
in some moment, and ConstructorDescriptor has getConstructedClass method
for mapping its owner
2017-03-10 13:49:05 +03:00
Denis Zharkov
be90f7d331 Make type aliases constructors return correct original descriptors
The problem was that when resolving super-calls we used known substitutor
when creating a type alias constructor, thus its original return itself,
while it's expected that it should return the descriptor before substitution

The main idea of the fix that `createIfAvailable` should always return
unsubstituted constructor.

Note that known substitutor for type alias constructor should be based
on abbreviation.

The test change seems to be correct as PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE
is already reported.
Beside this, resolution behavior isn't expected to be changed dramatically
2017-03-10 13:49:05 +03:00
Denis Zharkov
2b21280ba9 Unwrap underlying typealias constructor earlier
The problem is very subtle (see the test): when generating a signature
for an object literal we also were mapping its super-class
(a type alias here).

Although we did unwrap its underlying constructor to map it properly
we did too late (after obtaining value parameters from the type alias constructor descriptor).

Another problem is that TypeAliasConstructorDescriptor.getOriginal
in the case does return itself, while it's expected to return
unsubstituted version

Note: everything works for common calls for such constructors
because they mapped through mapCallableMethod which contains
another custom unwrapping of type alias constructors

 #KT-16555 Fixed
2017-03-10 13:45:37 +03:00
Denis Zharkov
8761ef6694 Minor. Rename mapSignature overload to mapSignatureWithCustomParameters 2017-03-10 13:45:37 +03:00
Denis Zharkov
7173e56393 Make computation of arguments for raw types lazy
See how we translate raw types to Kotlin model:
RawType(A) = A<ErasedUpperBound(T1), ...>
ErasedUpperBound(T : G<t>) = G<*> // UpperBound(T) is a type G<t> with arguments
ErasedUpperBound(T : A) = A // UpperBound(T) is a type A without arguments
ErasedUpperBound(T : F) = UpperBound(F) // UB(T) is another type parameter F

Stack overflow happens with the following classes:
class A<X extends B> // NB: raw type B in upper bound
class B<Y extends A> // NB: raw type A in upper bound

when calculating raw type for A, we start calculate ErasedUpperBound(Y),
thus starting calculating raw type for B => ErasedUpperBound(X) => RawType(A),
so we have SOE here.
The problem is that we calculating the arguments for these raw types eagerly,
while from the definition of ErasedUpperBound(Y) we only need a type constructor
of raw type B (and the number of parameters), we don't use its arguments.

The solution is to make arguments calculating for raw types lazy

 #KT-16528 Fixed
2017-03-10 13:30:33 +03:00
Mikhael Bogdanov
f2fea9a04a Generate unboxing operation on boxed class not Number.class when possible 2017-03-10 10:04:30 +01:00
Mikhael Bogdanov
5e80d80797 Fix for KT-16732: Type 'java/lang/Number' (current frame, stack[0]) is not assignable to 'java/lang/Character
#KT-16732 Fixed
2017-03-10 10:04:29 +01:00
Mikhail Glukhikh
32bdb6becb KT-16714 related refactoring of tryRunWriteAction (now runWriteAction is not used if intention is called from J2K) 2017-03-10 10:46:49 +03:00
Alexey Sedunov
faa0dff649 Kotlin Facet: Do no present compiler plugin classpaths and options in additional arguments string
#KT-16313 Fixed
2017-03-09 23:06:52 +03:00
Alexey Sedunov
cc20c66bfc Kotlin Facet: Fix platform detection by Maven execution goals
#KT-15947 Fixed
 #KT-16342 Fixed
2017-03-09 23:06:47 +03:00
Alexey Sedunov
e8640b441d JPS: Fix earlier configurations with incorrect combination of language and API version 2017-03-09 23:06:42 +03:00
Alexey Sedunov
811b8978c2 Kotlin Facet: Escape additional compiler arguments when converting them to string and unescape before parsing
#KT-16700 Fixed
2017-03-09 23:06:38 +03:00
Alexey Sedunov
c5ee28da05 Kotlin Facet: Detect module platform by gradle plugin
#KT-16703 Fixed
 #KT-16342 Fixed
2017-03-09 23:06:33 +03:00
Alexey Sedunov
26537cd8fc Kotlin Facet: Distinguish compiler arguments specified for different source sets
#KT-16698 Fixed
2017-03-09 23:06:28 +03:00
Alexey Sedunov
0e583aa929 Kotlin Facet: Update Gradle import test data to use 1.1.0 plugin 2017-03-09 23:06:23 +03:00
Alexey Sedunov
278cc71c4a Kotlin Facet: Reuse configuration serialization in JPS (previous implementation is not usable after configuration refactoring) 2017-03-09 23:06:18 +03:00
Alexey Sedunov
641a9a7153 Kotlin Facet: Get rid of duplicating data in facet configuration 2017-03-09 23:06:12 +03:00
Alexey Sedunov
19ea18a340 Kotlin Facet: Correctly enable/disable "output directory" field when changing "Use project settings" option
#KT-16317 Fixed
2017-03-09 22:48:44 +03:00
Dmitry Jemerov
01a9d9a284 Support lazy conversion of parent chain; correctly check expected class 2017-03-09 17:07:43 +01:00
Dmitry Jemerov
8c3936a0ee Update to UAST 0.12 2017-03-09 17:07:43 +01:00
Simon Ogorodnik
3bf7223448 Internal Kotlin packages now should be completable in parent packages
Internal packages which are hard-excluded from completion and
 imports now should be visible there if file package are parent of
 excluded one
 e.g kotlin.jvm.internal.* now visible from kotlin and kotlin.jvm
 #KT-16214 fixed
2017-03-09 19:05:10 +03:00
Dmitry Petrov
27bf51c73f All multifile class tests should have 'TARGET_BACKEND: JVM' directive. 2017-03-09 17:22:28 +03:00
Dmitry Petrov
6a68eb218f KT-16077 Redundant private getter for private var in a class within a JvmMultifileClass annotated file 2017-03-09 17:22:28 +03:00
Dmitry Jemerov
c9df227fef Add more tests for coroutines; use higher-level API to check that changes have been applied 2017-03-09 13:57:45 +01:00
Dmitry Jemerov
73a2c8c436 Test quickfixes for updating language/API version and coroutine support in Gradle projects 2017-03-09 13:41:57 +01:00
Dmitry Jemerov
5d461ec6df Support updating language/API level specified with compact options 2017-03-09 13:41:57 +01:00
Dmitry Jemerov
4261880340 Add test for enabling coroutines/bumping language level, fix several breakages 2017-03-09 13:41:57 +01:00
Sergey Igushkin
999ef51653 Added gradle-plugins properties with fqnames
Added .property files to make the plugins available by fqnames in
order to publish them to Gradle Plugin Portal.

#KT-5756

(cherry picked from commit 991de64)
2017-03-09 14:13:40 +03:00
Dmitry Jemerov
cbccb68948 Fix logic for searching inner classes in LazyResolveBasedCache.findInPackageFragments()
#KT-14058 Fixed
2017-03-09 11:47:21 +01:00
Alexander Udalov
9f2ce3c521 Refactor synthesized invokes creation in resolution
Instead of verifying that the container of an 'invoke' is a
FunctionClassDescriptor instance, make sure that it's a function class
checking its FQ name instead (classId + isBuiltinFunctionClass calls).
This makes sure that we will create synthesized invokes in a setting
where function classes are not FunctionClassDescriptor instances
synthesized by the compiler, but ordinary classes from sources or
binaries as well, as is going to be the case in kotlin-native
2017-03-09 11:29:39 +03:00
Dmitry Petrov
d188de3086 KT-6014 Wrong ABSTRACT_MEMBER_NOT_IMPLEMENTED for toString implemented by delegation
Members declared in interface or overriding members declared in super-interfaces
can be implemented by delegation even if they override members declared in super-class
(NB for interface this can be only 'kotlin.Any').
2017-03-09 09:38:48 +03:00
Mikhail Glukhikh
5e8afd26e1 Do not run write actions from J2K #KT-16714 Fixed
Also #EA-97363 Fixed
2017-03-09 09:37:35 +03:00
Dmitry Petrov
f950ff4b8f 'ConstructorDescriptor#getConstructedClass()' should be used to obtain a descriptor for constructed class
(it can be different from 'getContainingDeclaration()' in case of type alias constructor).

KT-15109 Subclass from a type alias with named parameter in constructor will produce compiler exception
KT-15192 Compiler crashes on certain companion objects: "Error generating constructors of class Companion with kind IMPLEMENTATION"
2017-03-09 09:23:38 +03:00
Dmitry Petrov
9a2c9ed30e KT-13342 Unqualified super call should not resolve to a method of supertype overridden in another supertype 2017-03-09 09:16:21 +03:00
Dmitry Jemerov
954c1d853d Correctly locate build.gradle for modules created from source sets
(cherry picked from commit ecce92d)
2017-03-08 15:08:41 +01:00
Dmitry Jemerov
a2f7808ab1 Don't check Java version in LauncherScriptTest 2017-03-08 14:07:47 +01:00
Dmitry Jemerov
263cf85c5c Fix project leak in IdeReplExecutionTest 2017-03-08 13:47:09 +01:00
Dmitry Petrov
11caa03427 KT-16713 Insufficient maximum stack size
1. Analyze method node with fake jumps for loops to make sure that
all instructions reachable only through break/continue jumps are processed.
2. Fix stack for break/continue jumps.
3. Drop fake jumps for loops, analyze method node again.
4. Fix stack for try/catch and beforeInline.
2017-03-08 09:56:08 +01:00
Mikhail Glukhikh
80063b6f91 Quick-fix for DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE added #KT-15966 Fixed 2017-03-07 19:06:16 +03:00
Ilya Gorbunov
b83b534374 Add missing SinceKotlin to IntStream.toList. 2017-03-07 18:22:11 +03:00
Ilya Gorbunov
c038d3e9a3 Mark all api in kotlin.reflect.full package with SinceKotlin(1.1), since it actually appeared in that package only in 1.1. #KT-16557 Fixed.
It doesn't matter that some functions were since 1.0 in the old package.
2017-03-07 18:22:11 +03:00
Kirill Rakhman
646f50dd66 Extract method refactoring should order parameters by first usage
Fixes #KT-16198
2017-03-07 18:10:02 +03:00
Ilya Gorbunov
1296c5444b Fix warning that failed maven plugin smoke test. 2017-03-07 13:56:11 +03:00
Ilya Gorbunov
61e8848aa2 Add samples for sequence building API. 2017-03-07 13:32:39 +03:00
Ilya Gorbunov
a04e6de047 Add groupingBy and eachCount sample. 2017-03-07 13:31:44 +03:00
Ilya Gorbunov
75ae42121b Improve sample comments.
Improve sample for lastIndex property.
2017-03-07 13:31:44 +03:00
Mikhail Zarechenskiy
578dd1dc42 Update Changelog for Kotlin 1.1.1-RC 2017-03-07 12:12:04 +03:00
Dmitry Petrov
d096f1d381 'while' and 'do-while' loop generator fixes.
Generate 'do-while' loop body as IrComposite, because variables declared
in loop body should be visible in loop condition.
Wrap 'do-while' loop in IrBlock so that variables declared in loop body
are not visible outside of the loop.

Generate 'while' and 'do-while' loops as expressions of type Unit.
2017-03-07 11:56:52 +03:00
Dmitry Petrov
cb61c358ea Always generate primitive boolean constants as expressions of type 'kotlin.Boolean'. 2017-03-07 11:56:52 +03:00
Dmitry Petrov
1bbbc1ca1c KT-16684 hashCode doesn't check data class property value of generic type for null 2017-03-07 11:56:52 +03:00
Dmitry Petrov
68fab55251 Minor: cleanup unused imports 2017-03-07 11:56:52 +03:00
Dmitry Petrov
6bc6c1b6cc KT-16671 Calls to members imported from objects should be desugared in PSI2IR 2017-03-07 11:56:52 +03:00
Dmitry Petrov
4ba8268a29 KT-16669 Exception in PSI2IR on type alias constructor in supertypes list 2017-03-07 11:56:52 +03:00
Dmitry Petrov
e4683a1e9f KT-16666 IMPLICIT_INTEGER_COERCION expression should have non-nullable type 2017-03-07 11:56:52 +03:00
Dmitry Petrov
8c32719f3d Render 'type' for IrTypeOperatorCall expressions, update testData. 2017-03-07 11:56:52 +03:00
Dmitry Petrov
b3aeddac85 Refactor: generalize postfix order transformation in InsertImplicitCasts 2017-03-07 11:56:52 +03:00
Dmitry Petrov
8e8f83656f KT-16618 IMPLICIT_INTEGER_COERCION isn't generated for global properties and default parameters 2017-03-07 11:56:52 +03:00
Sergey Igushkin
ee6aae7219 Enabled incremental compilation by default in Gradle plugin.
#KT-16546 Fixed

(cherry picked from commit 06715c5)
2017-03-07 11:32:26 +03:00
Alexey Andreev
ef38761dc2 JS: unmute now passing tests and mute test that passed by accident. 2017-03-07 10:46:09 +03:00
Alexey Andreev
a6ca2906d8 JS: add tests for reflection against external classes 2017-03-07 10:46:08 +03:00
Alexey Andreev
723c9be5a0 JS: fix class literal expression with primitive classes. See KT-16545 2017-03-07 10:46:08 +03:00
Alexey Andreev
8567db10b5 JS: fix coroutine transformation of callable references to local functions. See KT-16164 2017-03-07 10:46:07 +03:00
Dmitry Petrov
18fb70b32f Potential fix for KT-16673
See also:
http://stackoverflow.com/questions/42571812/unsupportedoperationexception-while-building-a-kotlin-project-in-idea

'original' for SamAdapterFunctionScope.MyFunctionDescriptor#doSubstitute should exactly match 'this.original',
so we can just provide it by default in SamAdapterFunctionScope.MyFunctionDescriptor#newCopyBuilder.
2017-03-06 22:00:09 +03:00
Dmitry Jemerov
268f7b715c "Configure Kotlin plugin updates" shows 1.2 and doesn't show 1.0.x 2017-03-06 19:50:58 +01:00
Ilya Chernikov
50e7973fc0 Implement verification workaround for annotation-like class InvalidScriptResolverAnnotation
fixes #KT-16621
2017-03-06 16:31:52 +01:00
Sergey Mashkov
243f718193 EA-88059 - assert: CompositeElement.addChild
ensure parent element for anchor elements so we never try to insert at wrong place
2017-03-06 17:34:36 +03:00
Sergey Mashkov
4637dcde33 EA-86479 - ISE: PomFile.<init>
don't apply any inspections for inappropriate pom files
2017-03-06 17:34:35 +03:00
Mikhael Bogdanov
ff9fe85507 Fix for KT-16614: Report inability to inline 1.8 bytecode into 1.6 bytecode as an error, no as an exception 2017-03-06 15:15:22 +01:00
Vyacheslav Gerasimov
5e4459f41d Fix broken MultiFileHighlightingTest
Android resource folding builder should not run in non-Android projects
2017-03-06 14:31:01 +03:00
Alexander Udalov
0111c4d581 Allow references to nested class constructors in objects in LV = 1.0
#KT-16598 Fixed
2017-03-06 11:03:24 +03:00
Alexander Udalov
7c22113c34 Refactor serialization of package FQ name extension
Instead of requiring to pass it in SerializerExtensionBase's
constructor, pass it always in serializePackage. This is more
straightforward and helps in a situation where one SerializerExtension
instance is used for the whole module, not one per-package
2017-03-06 11:03:24 +03:00
Kirill Rakhman
c952e26cbb Fix NPE caused by Rename Refactoring of backing field when caret is after the last character
#KT-16605 Fixed
2017-03-06 11:01:38 +03:00
Kirill Rakhman
1bad04db50 Fix Can't rename implicit lambda parameter 'it' when caret is placed right after the last character
#KT-14401 Fixed
2017-03-06 11:01:38 +03:00
Ilya Chernikov
e3391175d9 Rewrite parallel daemon start test to make it tougher but more robust 2017-03-05 11:29:54 +01:00
Anton Bannykh
4c6b9b695c JS: mute some tests with extension functions in external declarations 2017-03-03 21:39:40 +03:00
Anton Bannykh
fcffd190d0 JS: prohibited extension function arguments in external functions; removed extension receiver in jQuery declarations. 2017-03-03 20:37:59 +03:00
Sergey Igushkin
73e94ffde0 Added a test for the fix of KT-16434.
(cherry picked from commit 5a6d06f)
2017-03-03 18:04:23 +03:00
Sergey Igushkin
6605ba80e7 Fix for androidTest variants of Android Gradle build.
Added a workaround reflection call to TaskManager to create a
javac task since it is missing for androidTest variants with jack.
Added source configuration with the tested variant to make
the tested sources visible to the compiler.

#KT-16434 Fixed

(cherry picked from commit 84efd05)
2017-03-03 18:04:12 +03:00
Mikhail Glukhikh
0432e2e947 Quick-fix to add noinline to parameter with suspend function type + AddInlineModifierFix refactoring #KT-16074 Fixed 2017-03-03 17:28:37 +03:00
Mikhail Glukhikh
d9710ea4ff #EA-97027 Fixed 2017-03-03 17:28:35 +03:00
Mikhail Glukhikh
8965bb8977 Navigation: new icons for header <---> impl #KT-15842 Fixed 2017-03-03 17:28:34 +03:00
Vyacheslav Gerasimov
1376c8f8cf Implement quickfixes for Android Lint api issues
#KT-16624 Fixed
#KT-16625 Fixed
#KT-14947 Fixed
2017-03-03 16:22:36 +03:00
Vyacheslav Gerasimov
a907ec92b5 Implement Android resource reference folding
#KT-15451 Fixed
2017-03-03 16:18:20 +03:00
Vyacheslav Gerasimov
39010ab847 Fix broken isReferenceTo checking code for Android extensions
#KT-16132 Fixed
2017-03-03 16:17:52 +03:00
Alexander Udalov
25c1828288 JS: write and load pre-release flag on binaries 2017-03-03 13:33:51 +03:00
Alexander Udalov
de8dd37e44 Change DeserializedContainerSource.presentableFqName to String
To allow outputting something other than "Class 'XXX'" in the diagnostic
message for declarations deserialized from JS
2017-03-03 13:33:51 +03:00
Alexander Udalov
f120865350 Combine cls stub builders for built-ins and JS 2017-03-03 13:33:51 +03:00
Alexander Udalov
297eb952bc Extract common parts of built-ins and JS decompilers 2017-03-03 13:33:51 +03:00
Alexander Udalov
b52b90c182 Extract serialization of packageFqName extension to SerializerExtensionBase 2017-03-03 13:33:51 +03:00
Alexander Udalov
4e91dadfab Combine decompiler deserializers for built-ins and JS 2017-03-03 13:33:50 +03:00
Alexander Udalov
bafa0ec1ee Minor, don't throw exception on empty proto message 2017-03-03 13:33:50 +03:00
Alexander Udalov
5a00a97cf1 Extract common parts from deserialization of built-ins and JS 2017-03-03 13:33:50 +03:00
Alexander Udalov
3cb8f1ab20 Drop BuiltIns protobuf message, use ProtoBuf.PackageFragment instead 2017-03-03 13:33:50 +03:00
Alexander Udalov
a36e457c12 Introduce PackageFragment protobuf message for kjsm/builtins/common metadata 2017-03-03 13:33:50 +03:00
Alexander Udalov
2b1b1fb0d4 Merge VirtualFileKotlinClassFinder into VirtualFileFinder
VirtualFileKotlinClassFinder was the only direct subclass of VirtualFileFinder
2017-03-03 13:33:50 +03:00
Alexander Udalov
abb5bc6aba Simplify VirtualFileFinder and their factories' hierarchy
Since there's no JsVirtualFileFinder anymore, inline JvmVirtualFileFinder into
VirtualFileFinder and drop "Jvm" prefix everywhere
2017-03-03 13:33:50 +03:00
Alexander Udalov
ee0874a26d Drop JsVirtualFileFinder and its factory, refactor nearby
The only remaining usage was in KotlinRuntimeLibraryUtil.kt where we only
needed to check whether there's at least one file in a given package indexed by
KotlinJavaScriptMetaFileIndex. Move that logic to a public extension, drop
everything else
2017-03-03 13:33:50 +03:00
Alexander Udalov
67699bf17e Rename metadata version index and its subclasses 2017-03-03 13:33:50 +03:00
Alexander Udalov
57877bb007 Add default value to js_code_binary_version in js.proto
By default, assume the version is 1.0.0
2017-03-03 13:33:49 +03:00
Mikhael Bogdanov
a03ed6f742 Fix for KT-16581: VerifyError when calling default value parameter with jvm-target 1.8
#KT-16581 Fixed
2017-03-03 11:21:42 +01:00
Ilya Chernikov
ffe3453937 Do not pollute IDEA log with fake script dependencies 2017-03-03 10:59:28 +01:00
Mikhail Glukhikh
3060ecc066 Minor build fix: "Convert to apply" is now applicable only with 2+ calls with the same receiver 2017-03-03 11:10:01 +03:00
Dmitry Petrov
634d9834de Wrong receiver is generated for variable-as-function call on object.
Move 'generateExpressionForReferencedDescriptor' to CallGenerator,
use it in 'generateCall',
add PSI-free versions of some utility methods so that call elements can
be generated when we're already deep in ResolvedCall generation
and have forgotten about PSI.
2017-03-03 10:15:59 +03:00
Mikhail Zarechenskiy
d573962259 Add test for class delegation with private constructor
#KT-16583 Obsolete
2017-03-02 18:34:59 +03:00
Mikhail Zarechenskiy
e2dcec62d3 Fix access to top-level declarations inside anonymous initializer
#KT-16583 Fixed
2017-03-02 18:34:51 +03:00
shiraji
0e5603f644 Implement an intention converting several calls with same receiver to with/apply/run #KT-12183 Fixed 2017-03-02 16:56:56 +03:00
shiraji
c2e5fc5215 Move KtDotQualifiedExpression.deleteFirstReceiver to Utils.kt 2017-03-02 16:56:53 +03:00
Alexander Udalov
39d0cd7237 Test that all Kotlin versions in the project are consistent
There are two different tests: the one that checks that all versions are
consistent (but not equal, because some versions are major.minor.patch,
but some only major.minor), and the one that checks that versions of all
subprojects of the Maven projects are exactly equal (1.1-SNAPSHOT
currently)

 #KT-16455 Fixed
2017-03-02 16:36:51 +03:00
Denis Zharkov
6fb83c2ba3 Force wrapping java classes from annotation methods into KClasses
Before this change such wrapping happened only during coercion,
i.e. when a call-site expected a KClass instance.

But when call-site expects Any, for example, no wrapping happened,
and raw j.l.Class instance was left on stack.

The solution is to put wrapping code closer to generation of annotation's
method call itself to guarantee that necessary wrapping will happen.

 #KT-9453 Fixed
2017-03-02 15:19:09 +03:00
Denis Zharkov
415c3d57af Fix substitutor for synthetic SAM adapters
When synthetic member comes not from the receiver type itself,
but from one of its supertypes it doesn't make sense to subsitute
the member with receiver type, we should obtain relevant supertype
and use it instead.

 #KT-16578 Fixed
2017-03-02 15:06:59 +03:00
Anton Bannykh
9e5ecc11b7 JS: fixed Double.NaN behaviour (KT-13610). 2017-03-02 14:29:50 +03:00
Dmitry Petrov
f636ab21f8 Use proper descriptor for (generic) property assignment.
Insert IMPLICIT_INTEGER_COERCION only if Int is coerced to an integer type.
2017-03-02 14:25:58 +03:00
Dmitry Petrov
97fbbc74e6 KT-16440 ClassConstructorDescriptorImpl has null returnType
Set constructor return type in FunctionDescriptorResolver#createConstructorDescriptor
(it seems to be the only place where ClassConstructorDescriptorImpl#initialize(...)
is called, but returnType is not set).
2017-03-02 14:25:58 +03:00
Dmitry Petrov
dc1d92855d KT-16438 Strange dispatch receiver for descriptors of delegated members
Provide proper dispatch receiver parameter for delegated members.
Use dispatch receiver parameter for delegated members in IR generation
for delegated member body (and check that the receiver has corresponding type).
2017-03-02 14:25:58 +03:00
Dmitry Petrov
c92f118e5e Refactoring: introduce CopyBuilder for CallableMemberDescriptor and PropertyDescriptor.
Allow providing new dispatchReceiverParameter via CopyBuilder
(required for proper dispatch receiver for delegates).
2017-03-02 14:25:58 +03:00
Dmitry Petrov
9baaf607a3 KT-16566 Support destructuring declarations for lambda parameter in psi2ir 2017-03-02 14:25:58 +03:00
Dmitry Petrov
c226707a80 KT-16554 Local function with default arguments have no IR elements for them 2017-03-02 14:25:58 +03:00
Igor Chevdar
ab3681e164 Package level delegated properties have no dispatch receiver. 2017-03-02 12:33:01 +03:00
Igor Chevdar
3ef612f05a Added dispatch receiver to delegation implementing property 2017-03-02 12:33:01 +03:00
Simon Ogorodnik
6dd75f697a Fix Show implementation to show inheritance through type-aliases
Show implementation(Ctrl-Hover) now should show classes which inherit such class through type-alias
 #KT-15200 fixed
2017-03-01 23:05:19 +03:00
Yan Zhulanow
593fbadc98 Force using the 'kotlin-stdlib-jre7' artifact when configuring Android modules with JDK >= 1.8 as Dex can't process our 'kotlin-stdlib-jre8' artifact.
This fixes KT-16530: Configure Kotlin in Project inserts dependency to kotlin-stdlib-jre8 in Android projects.
2017-03-01 18:50:22 +03:00
Yan Zhulanow
060095d39f Remove kotlin-annotation-processing artifact from the serialized compiler options. It is unused in kapt3 (or if no annotation processor dependencies are provided) but is still imported into the IDEA module files. This leads to compilation error due to the plugin incompatibility.
Incompatibility reason: kotlin-annotation-processing has references to the shaded intellij-core, so, being provided to the unshaded kotlinc from the Kotlin plugin, it throws the AbstractMethodError.

This fixes #KT-16184.
2017-03-01 18:50:22 +03:00
Kirill Rakhman
2506bb6673 Inspection checking that destructuring variable name matches the name of different component #KT-12004 Fixed 2017-03-01 18:24:48 +03:00
Dmitry Jemerov
af7de9a0c5 Warn when running the compiler under Java 6 or 7
(cherry picked from commit 5537800)

(cherry picked from commit 5614874)
2017-03-01 16:21:57 +01:00
Simon Ogorodnik
000da2f6d0 Fix of <ERROR CLASS>-es pointing to public TypeAliases 2017-03-01 16:09:24 +01:00
Dmitry Jemerov
78b4cbdb69 Don't generate documentation for option that doesn't work in Gradle 2017-03-01 16:09:23 +01:00
Alexey Andreev
0c0e0aab09 JS: add some docs to declarations related to interop 2017-03-01 16:09:21 +01:00
Dmitry Jemerov
322379e6ae Assorted stdlib KDocs 2017-03-01 16:09:01 +01:00
Dmitry Jemerov
1d86bd5610 Build multiplatform stdlib docs 2017-03-01 16:08:38 +01:00
Dmitry Jemerov
adc937c57d Extract separate target for preprocessing JS stdlib sources 2017-03-01 16:08:28 +01:00
Kirill Rakhman
8d425a6f94 Add intention to add missing components to destructuring assignment #KT-16258 Fixed 2017-03-01 18:00:55 +03:00
Mikhael Bogdanov
4d47c0fd63 Partial fix for KT-16193: Incremental compilation generates invalid bytecode for crossinlined functions; avoid IllegalAccessError 2017-03-01 14:45:11 +01:00
Alexander Udalov
3ad4f18e1a Update grammar to Kotlin 1.1
Also drop obsolete comments and inline some trivial rules
2017-03-01 14:50:36 +03:00
Mikhail Zarechenskiy
875fdef917 Add tests for obsolete issues
#KT-15913 Obsolete
 #KT-12248 Obsolete
2017-03-01 14:07:09 +03:00
Anton Bannykh
318014e4ab Test vararg with Java behaviour only for JVM backends 2017-03-01 13:58:57 +03:00
Mikhail Glukhikh
91cd590395 Change log: note about javaClass added 2017-03-01 10:14:57 +03:00
Denis Zharkov
a7fc32c8da Add diagnostic on calling inner classes constructors without receiver
Otherwise there will be just an unresolved reference that doesn't give
any useful information

 #KT-8959 Fixed
2017-03-01 09:59:01 +03:00
Denis Zharkov
1e0ae04aba Minor. Convert if to when 2017-03-01 09:59:00 +03:00
Denis Zharkov
b5a8ffaddc Fix resolution of callable references
When there is unsuccessful (e.g invisible) result of one kind (static/non-static)
and there is a successful candidate for another kind, choose the latter one.

Note, that we have to postpone commiting trace until we choose one of the results,
otherwise errors of unsuccessful results are reported

TODO: Maybe it makes sense to report all results when all of them are
unsuccessful (NONE_APPLICABLE or something like this)

 #KT-16278 Fixed
2017-03-01 09:59:00 +03:00
Dmitry Petrov
dd61a5b2c6 KT-16553 Underscore variable values shall not be evaluated
Do not generate 'componentN' calls for '_' in destructuring assignment.
2017-03-01 09:25:38 +03:00
Dmitry Petrov
63b16e14d8 KT-16536 Wrong IR generated for '++x'
Make psi2ir confirm to JVM BE behavior for prefix increment/decrement.
TODO reconsider after design decision (in 1.2?).
2017-03-01 09:25:38 +03:00
Dmitry Petrov
885f397cdd KT-16535 'provideDelegate' convention is not supported in IR
Implement provideDelegate convention support.
NB delegate type now depends on 'provideDelegate' convention resolution.
2017-03-01 09:25:38 +03:00
Dmitry Petrov
6046b25f56 Minor: silence that irritating KT-14030 2017-03-01 09:25:38 +03:00
Dmitry Petrov
045a12ddc6 Minor: constructor IrExpressionBodyImpl(IrExpression) 2017-03-01 09:25:38 +03:00
Dmitry Petrov
e66c2621af KT-16436 Incorrect primitive constants handling
Expression '1.unaryMinus()' is resolved as Int::unaryMinus call with Int receiver.
However, this expression is implicitly coerced to a different integral type (Byte, Short, Long)
based on results of constant evaluation.

Introduce IMPLICIT_INTEGER_COERCION type operator to handle such cases.

TODO: should we use it for simple constant expressions like '1' and '-1'?
2017-03-01 09:25:38 +03:00
Dmitry Petrov
d0134f2c64 KT-16437 Incorrect type inference for some when coerced to Unit
If the result of 'when' is not used in an expression,
this 'when' expression has type 'Unit' despite of whatever FE has inferred.
2017-03-01 09:25:38 +03:00
Dmitry Petrov
e2e57e5b6d KT-16439 Generated methods of data classes have no expression for default arguments
Provide default argument expressions for generated 'copy' declaration.
2017-03-01 09:25:38 +03:00
Dmitry Petrov
0f1f354ba6 KT-16486 Strange IR for delegated members
Delegated implementations should refer to delegate field:
  $this: GET_FIELD <delegate_field> ...
    receiver: <this_for_containing_class>
2017-03-01 09:25:38 +03:00
Alexander Udalov
abbbdb5771 Update KotlinVersion.CURRENT to 1.1.2 2017-02-28 20:24:33 +03:00
Alexander Udalov
559da842c0 Clear reflection caches in black box codegen tests
To prevent tests from altering outcomes of the subsequent tests.

Also expose the clearCaches method (in the internal class
ReflectionFactoryImpl) so that it can be used in other places in similar
circumstances
2017-02-28 20:19:58 +03:00
Alexander Udalov
e19c1b5364 Drop MockTypeAliasDescriptor, use MockClassDescriptor instead
It's irrelevant whether the non-found classifier is a class or a
typealias
2017-02-28 20:19:58 +03:00
Alexander Udalov
12b48f86e7 Do not load error classes in ReflectionTypes
Previously ReflectionTypes.find returned an error class in case a class
is not found in the module dependencies. The problem with this approach
is that each call site should call ErrorUtils.isError on the result and
report an error if needed, in order to stop this type from reaching the
codegen, which can't handle error types.

Now we create a MockClassDescriptor instance instead. It's not an error
class, so it'll be handled correctly in the codegen. Also its scope is
empty and errors are reported on any non-trivial usage (see
MissingDependencyClassChecker), so this approach is not worse than error
classes

 #KT-16484 Fixed
2017-02-28 20:19:58 +03:00
Alexander Udalov
794cc1e3be Refactor API of NotFoundClasses
Move deserialization-related stuff to TypeDeserializer, because it's
going to be used in other places besides deserialization
2017-02-28 20:19:58 +03:00
Alexander Udalov
86994f81c3 Refactor ClassId.getOuterClassId, make it nullable 2017-02-28 20:19:57 +03:00
2976 changed files with 29856 additions and 16000 deletions

View File

@@ -11,7 +11,6 @@
<element id="directory" name="META-INF">
<element id="dir-copy" path="$PROJECT_DIR$/jps-plugin/src/META-INF" />
</element>
<element id="extracted-dir" path="$PROJECT_DIR$/dependencies/cli-parser-1.1.2.jar" path-in-jar="/" />
<element id="module-output" name="cli-common" />
<element id="module-output" name="idea-jps-common" />
<element id="module-output" name="jps-plugin" />

7
.idea/dictionaries/4u7.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="4u7">
<words>
<w>foldable</w>
</words>
</dictionary>
</component>

View File

@@ -1,11 +0,0 @@
<component name="libraryTable">
<library name="cli-parser">
<CLASSES>
<root url="jar://$PROJECT_DIR$/dependencies/cli-parser-1.1.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$PROJECT_DIR$/dependencies/cli-parser-1.1.2-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -3,6 +3,42 @@
<!-- Find: ([^\`/\[])(KT-\d+) -->
<!-- Replace: $1[`$2`](https://youtrack.jetbrains.com/issue/$2) -->
## 1.1.1
### IDE
- [`KT-16714`](https://youtrack.jetbrains.com/issue/KT-16714) J2K: Write access is allowed from event dispatch thread only
### Compiler
- [`KT-16801`](https://youtrack.jetbrains.com/issue/KT-16801) Accessors of `@PublishedApi` property gets mangled
- [`KT-16673`](https://youtrack.jetbrains.com/issue/KT-16673) Potentially problematic code causes exception when work with SAM adapters
### Libraries
- [`KT-16557`](https://youtrack.jetbrains.com/issue/KT-16557) Correct `SinceKotlin(1.1)` for all declarations in `kotlin.reflect.full`
## 1.1.1-RC
### IDE
- [`KT-16481`](https://youtrack.jetbrains.com/issue/KT-16481) Kotlin debugger & bytecode fail on select statement blocks (IllegalStateException: More than one package fragment)
### Gradle support
- [`KT-15783`](https://youtrack.jetbrains.com/issue/KT-15783) Gradle builds don't use incremental compilation due to an error: "Could not connect to kotlin daemon"
- [`KT-16434`](https://youtrack.jetbrains.com/issue/KT-16434) Gradle plugin does not compile androidTest sources when Jack is enabled
- [`KT-16546`](https://youtrack.jetbrains.com/issue/KT-16546) Enable incremental compilation in gradle by default
### Compiler
- [`KT-16184`](https://youtrack.jetbrains.com/issue/KT-16184) AbstractMethodError in Kapt3ComponentRegistrar while compiling from IntelliJ using Kotlin 1.1.0
- [`KT-16578`](https://youtrack.jetbrains.com/issue/KT-16578) Fix substitutor for synthetic SAM adapters
- [`KT-16581`](https://youtrack.jetbrains.com/issue/KT-16581) VerifyError when calling default value parameter with jvm-target 1.8
- [`KT-16583`](https://youtrack.jetbrains.com/issue/KT-16583) Cannot access private file-level variables inside a class init within the same file if a secondary constructor is present
- [`KT-16587`](https://youtrack.jetbrains.com/issue/KT-16587) AbstractMethodError: Delegates not generated correctly for private interfaces
- [`KT-16598`](https://youtrack.jetbrains.com/issue/KT-16598) Incorrect error: The feature "bound callable references" is only available since language version 1.1
- [`KT-16621`](https://youtrack.jetbrains.com/issue/KT-16621) Kotlin compiler doesn't report an error if a class implements Annotation interface but doesn't implement annotationType method
- [`KT-16441`](https://youtrack.jetbrains.com/issue/KT-16441) `NoSuchFieldError: $$delegatedProperties` when delegating through `provideDelegate` in companion object
### JavaScript support
- Prohibit function types with receiver as parameter types of external declarations
- Remove extension receiver for function parameters in `jQuery` declarations
## 1.1
### Compiler exceptions
@@ -12,6 +48,7 @@
### Standard library
- [`KT-6561`](https://youtrack.jetbrains.com/issue/KT-6561) Drop java.util.Collections package from js stdlib
- `javaClass` extension property is no more deprecated due to migration problems
### IDE
- [`KT-16329`](https://youtrack.jetbrains.com/issue/KT-16329) Inspection "Calls to staic methods in Java interfaces..." always reports warning undependent of jvm-target

View File

@@ -29,8 +29,8 @@ internal object KotlinAntTaskUtil {
private val libPath: File by lazy {
// Find path of kotlin-ant.jar in the filesystem and find kotlin-compiler.jar in the same directory
val resourcePath = "/" + javaClass.name.replace('.', '/') + ".class"
val jarConnection = javaClass.getResource(resourcePath).openConnection() as? JarURLConnection
val resourcePath = "/" + this::class.java.name.replace('.', '/') + ".class"
val jarConnection = this::class.java.getResource(resourcePath).openConnection() as? JarURLConnection
?: throw UnsupportedOperationException("Kotlin compiler Ant task should be loaded from the JAR file")
val antTaskJarPath = File(jarConnection.jarFileURL.toURI())
@@ -54,7 +54,7 @@ internal object KotlinAntTaskUtil {
val cached = classLoaderRef.get()
if (cached != null) return cached
val myLoader = javaClass.classLoader
val myLoader = this::class.java.classLoader
if (myLoader !is AntClassLoader) return myLoader
val classLoader = ClassPreloadingUtils.preloadClasses(listOf(compilerJar), Preloader.DEFAULT_CLASS_NUMBER_ESTIMATE, myLoader, null)

View File

@@ -19,9 +19,9 @@ package org.jetbrains.kotlin.compilerRunner;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ComparatorUtil;
import com.sampullara.cli.Argument;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments;
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
import java.lang.reflect.Field;
import java.util.ArrayList;

View File

@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import org.jetbrains.kotlin.serialization.deserialization.supertypes
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
import org.jetbrains.kotlin.utils.singletonOrEmptyList
import org.jetbrains.org.objectweb.asm.*
import java.io.File
import java.security.MessageDigest
@@ -272,7 +271,7 @@ open class IncrementalCacheImpl<Target>(
ProtoBuf.Class::getPropertyList
) + classData.classProto.enumEntryList.map { classData.nameResolver.getString(it.name) }
val companionObjectChanged = createChangeInfo(classFqName.parent(), classFqName.shortName().asString().singletonOrEmptyList())
val companionObjectChanged = createChangeInfo(classFqName.parent(), listOfNotNull(classFqName.shortName().asString()))
val companionObjectMembersChanged = createChangeInfo(classFqName, memberNames)
listOf(companionObjectMembersChanged, companionObjectChanged)
@@ -780,7 +779,7 @@ sealed class ChangeInfo(val fqName: FqName) {
protected open fun toStringProperties(): String = "fqName = $fqName"
override fun toString(): String {
return this.javaClass.simpleName + "(${toStringProperties()})"
return this::class.java.simpleName + "(${toStringProperties()})"
}
}

View File

@@ -50,5 +50,5 @@ class LocalFileKotlinClass private constructor(
override fun hashCode(): Int = file.hashCode()
override fun equals(other: Any?): Boolean = other is LocalFileKotlinClass && file == other.file
override fun toString(): String = "$javaClass: $file"
override fun toString(): String = "${this::class.java}: $file"
}

View File

@@ -42,7 +42,7 @@ import java.util.*
fun Iterable<File>.javaSourceRoots(roots: Iterable<File>): Iterable<File> =
filter { it.isJavaFile() }
filter(File::isJavaFile)
.map { findSrcDirRoot(it, roots) }
.filterNotNull()
@@ -145,7 +145,7 @@ fun LookupStorage.update(
filesToCompile: Iterable<File>,
removedFiles: Iterable<File>
) {
if (lookupTracker !is LookupTrackerImpl) throw AssertionError("Lookup tracker is expected to be LookupTrackerImpl, got ${lookupTracker.javaClass}")
if (lookupTracker !is LookupTrackerImpl) throw AssertionError("Lookup tracker is expected to be LookupTrackerImpl, got ${lookupTracker::class.java}")
removeLookupsFrom(filesToCompile.asSequence() + removedFiles.asSequence())

View File

@@ -46,7 +46,7 @@ abstract class BasicMap<K : Comparable<K>, V>(
fun dump(): String {
return with(StringBuilder()) {
with(Printer(this)) {
println(this@BasicMap.javaClass.simpleName)
println(this@BasicMap::class.java.simpleName)
pushIndent()
for (key in storage.keys.sorted()) {

View File

@@ -131,7 +131,7 @@ object ConstantsMapExternalizer : DataExternalizer<Map<String, Any>> {
output.writeByte(Kind.STRING.ordinal)
IOUtil.writeString(value, output)
}
else -> throw IllegalStateException("Unexpected constant class: ${value.javaClass}")
else -> throw IllegalStateException("Unexpected constant class: ${value::class.java}")
}
}
}

View File

@@ -144,7 +144,7 @@ private fun classFileToString(classFile: File): String {
out.write("\n------ string table types proto -----\n${DebugJvmProtoBuf.StringTableTypes.parseDelimitedFrom(input)}")
if (!classHeader!!.metadataVersion.isCompatible()) {
if (!classHeader.metadataVersion.isCompatible()) {
error("Incompatible class ($classHeader): $classFile")
}

View File

@@ -81,8 +81,8 @@ fun getModificationsToPerform(
val rules = mapOf<String, (String, File) -> Modification>(
newSuffix to { path, file -> ModifyContent(path, file) },
touchSuffix to { path, file -> TouchFile(path, touchPolicy) },
deleteSuffix to { path, file -> DeleteFile(path) }
touchSuffix to { path, _ -> TouchFile(path, touchPolicy) },
deleteSuffix to { path, _ -> DeleteFile(path) }
)
val modifications = ArrayList<Modification>()
@@ -130,7 +130,7 @@ fun getModificationsToPerform(
abstract class Modification(val path: String) {
abstract fun perform(workDir: File, mapping: MutableMap<File, File>)
override fun toString(): String = "${javaClass.simpleName} $path"
override fun toString(): String = "${this::class.java.simpleName} $path"
}
class ModifyContent(path: String, val dataFile: File) : Modification(path) {

View File

@@ -1,4 +1,4 @@
<project name="Kotlin" default="dist" xmlns:if="ant:if" xmlns:unless="ant:unless">
<project xmlns:if="ant:if" xmlns:unless="ant:unless" name="Kotlin" default="dist">
<import file="common.xml" optional="false"/>
<property file="resources/kotlinManifest.properties"/>
@@ -72,7 +72,6 @@
<fileset dir="${basedir}/lib" includes="**/*.jar"/>
<fileset dir="${dependencies}" includes="jansi.jar"/>
<fileset dir="${dependencies}" includes="jline.jar"/>
<fileset dir="${dependencies}" includes="cli-parser-1.1.2.jar"/>
<fileset dir="${basedir}/ideaSDK/jps" includes="jps-model.jar"/>
</path>
@@ -406,9 +405,12 @@
byline="true" encoding="UTF-8" />
</target>
<target name="js-stdlib">
<property environment="env"/>
<target name="js-stdlib-preprocess">
<kotlin-pp src="libraries/stdlib/src" output="${intermediate-sources}/stdlib/js" profile="JS" />
</target>
<target name="js-stdlib" depends="js-stdlib-preprocess">
<property environment="env"/>
<cleandir dir="${js.stdlib.output.dir}"/>
<!-- We don't want descriptors for built-ins to be serialized, so we compile these files separately. -->
@@ -474,7 +476,7 @@
<copy file="${kotlin-home}/lib/kotlin-stdlib-js.jar" tofile="${kotlin-home}/lib/kotlin-jslib.jar" />
</target>
<target name="pack-js-stdlib-sources">
<target name="pack-js-stdlib-sources" depends="js-stdlib-preprocess">
<jar destfile="${kotlin-home}/lib/kotlin-stdlib-js-sources.jar" duplicate="fail">
<resources refid="js.lib.files" />
<fileset refid="kotlin.builtin.files" />
@@ -586,7 +588,6 @@
<zipfileset src="${idea.sdk}/lib/oromatcher.jar"/>
<zipfileset src="${idea.sdk}/jps/jps-model.jar"/>
<zipfileset src="${dependencies}/jline.jar"/>
<zipfileset src="${dependencies}/cli-parser-1.1.2.jar"/>
<zipfileset src="${protobuf.jar}"/>
<manifest>
@@ -1032,13 +1033,13 @@
<sequential>
<java classname="org.jetbrains.kotlin.preloading.Preloader" failonerror="true" fork="true" maxmemory="${max.heap.size.for.forked.jvm}">
<classpath>
<pathelement location="${kotlin-home}/lib/kotlin-preloader.jar"/>
<pathelement location="${bootstrap.compiler.home}/lib/kotlin-preloader.jar"/>
</classpath>
<assertions>
<enable/>
</assertions>
<arg value="-cp"/>
<arg value="${kotlin-home}/lib/kotlin-compiler.jar"/>
<arg value="${bootstrap.compiler.home}/lib/kotlin-compiler.jar"/>
<arg value="org.jetbrains.kotlin.preprocessor.PreprocessorCLI"/>
<arg value="@{src}"/>
<arg value="@{output}"/>

View File

@@ -91,7 +91,7 @@ object CodegenUtil {
else if (traitMember is PropertyDescriptor) {
for (traitAccessor in traitMember.accessors) {
for (inheritedAccessor in (copy as PropertyDescriptor).accessors) {
if (inheritedAccessor.javaClass == traitAccessor.javaClass) { // same accessor kind
if (inheritedAccessor::class.java == traitAccessor::class.java) { // same accessor kind
result.put(traitAccessor, inheritedAccessor)
}
}

View File

@@ -103,5 +103,5 @@ abstract class DataClassMethodGenerator(private val declaration: KtClassOrObject
.map { bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it)!! }
private val primaryConstructorParameters: List<KtParameter>
get() = (declaration as? KtClass)?.getPrimaryConstructorParameters().orEmpty()
get() = (declaration as? KtClass)?.primaryConstructorParameters.orEmpty()
}

View File

@@ -77,9 +77,13 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
}
}
generatePrimaryConstructorProperties();
generateConstructors();
generateDefaultImplsIfNeeded();
boolean generateNonClassMembers = shouldGenerateNonClassMembers();
if (generateNonClassMembers) {
generatePrimaryConstructorProperties();
generateConstructors();
generateDefaultImplsIfNeeded();
}
// Generate _declared_ companions
for (KtObjectDeclaration companion : companions) {
@@ -92,23 +96,30 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
genSyntheticClassOrObject((SyntheticClassOrObjectDescriptor) companionObjectDescriptor);
}
if (!DescriptorUtils.isInterface(descriptor)) {
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
if (memberDescriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor member = (CallableMemberDescriptor) memberDescriptor;
if (!member.getKind().isReal() && ImplKt.findInterfaceImplementation(member) == null) {
if (member instanceof FunctionDescriptor) {
functionCodegen.generateBridges((FunctionDescriptor) member);
if (generateNonClassMembers) {
generateBridges();
}
}
private void generateBridges() {
if (DescriptorUtils.isInterface(descriptor)) {
return;
}
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
if (memberDescriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor member = (CallableMemberDescriptor) memberDescriptor;
if (!member.getKind().isReal() && ImplKt.findInterfaceImplementation(member) == null) {
if (member instanceof FunctionDescriptor) {
functionCodegen.generateBridges((FunctionDescriptor) member);
}
else if (member instanceof PropertyDescriptor) {
PropertyGetterDescriptor getter = ((PropertyDescriptor) member).getGetter();
if (getter != null) {
functionCodegen.generateBridges(getter);
}
else if (member instanceof PropertyDescriptor) {
PropertyGetterDescriptor getter = ((PropertyDescriptor) member).getGetter();
if (getter != null) {
functionCodegen.generateBridges(getter);
}
PropertySetterDescriptor setter = ((PropertyDescriptor) member).getSetter();
if (setter != null) {
functionCodegen.generateBridges(setter);
}
PropertySetterDescriptor setter = ((PropertyDescriptor) member).getSetter();
if (setter != null) {
functionCodegen.generateBridges(setter);
}
}
}
@@ -116,6 +127,11 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
}
}
private boolean shouldGenerateNonClassMembers() {
return !(myClass instanceof KtClassOrObject) ||
state.getGenerateDeclaredClassFilter().shouldGenerateClassMembers((KtClassOrObject) myClass);
}
protected void generateConstructors() {
}
@@ -130,7 +146,9 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
protected void generateDeclaration(KtDeclaration declaration) {
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) {
genSimpleMember(declaration);
if (shouldGenerateNonClassMembers()) {
genSimpleMember(declaration);
}
}
else if (declaration instanceof KtClassOrObject) {
if (declaration instanceof KtEnumEntry && !enumEntryNeedSubclass(bindingContext, (KtEnumEntry) declaration)) {

View File

@@ -82,7 +82,7 @@ public class ClassFileFactory implements OutputFileCollection {
return answer;
}
void done() {
public void done() {
if (!isDone) {
isDone = true;
writeModuleMappings();

View File

@@ -54,7 +54,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
contextKind: OwnerKind,
classOrObject: KtPureClassOrObject
) {
val methodElement = classOrObject.getPrimaryConstructor() ?: classOrObject
val methodElement = classOrObject.primaryConstructor ?: classOrObject
if (generateOverloadsIfNeeded(methodElement, constructorDescriptor, constructorDescriptor, contextKind, classBuilder, memberCodegen)) {
return
@@ -135,7 +135,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
(if (isStatic) Opcodes.ACC_STATIC else 0) or
(if (functionDescriptor.modality == Modality.FINAL && functionDescriptor !is ConstructorDescriptor) Opcodes.ACC_FINAL else 0) or
(if (remainingParameters.lastOrNull()?.varargElementType != null) Opcodes.ACC_VARARGS else 0)
val signature = typeMapper.mapSignature(functionDescriptor, contextKind, remainingParameters, false)
val signature = typeMapper.mapSignatureWithCustomParameters(functionDescriptor, contextKind, remainingParameters, false)
val mv = classBuilder.newMethod(OtherOrigin(methodElement, functionDescriptor), flags,
signature.asmMethod.name,
signature.asmMethod.descriptor,
@@ -251,7 +251,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
val classDescriptor = constructorDescriptor.constructedClass
if (classDescriptor.kind != ClassKind.CLASS) return false
if (classOrObject.isLocal()) return false
if (classOrObject.isLocal) return false
if (CodegenBinding.canHaveOuter(state.bindingContext, classDescriptor)) return false
@@ -265,6 +265,6 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
}
private fun hasSecondaryConstructorsWithNoParameters(klass: KtClass) =
klass.getSecondaryConstructors().any { it.valueParameters.isEmpty() }
klass.secondaryConstructors.any { it.valueParameters.isEmpty() }
}

View File

@@ -33,10 +33,10 @@ abstract class DelegatingClassBuilderFactory(
abstract override fun newClassBuilder(origin: JvmDeclarationOrigin): DelegatingClassBuilder
override fun asBytes(builder: ClassBuilder?): ByteArray? {
return delegate.asBytes((builder as DelegatingClassBuilder).getDelegate())
return delegate.asBytes((builder as DelegatingClassBuilder).delegate)
}
override fun asText(builder: ClassBuilder?): String? {
return delegate.asText((builder as DelegatingClassBuilder).getDelegate())
return delegate.asText((builder as DelegatingClassBuilder).delegate)
}
}

View File

@@ -1919,11 +1919,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return asmType(varType);
}
private static boolean isSharedVarType(@NotNull Type type) {
return type.getSort() == Type.OBJECT && type.getInternalName().startsWith(REF_TYPE_PREFIX);
}
private void putDescriptorIntoFrameMap(@NotNull KtElement statement) {
if (statement instanceof KtDestructuringDeclaration) {
KtDestructuringDeclaration multiDeclaration = (KtDestructuringDeclaration) statement;
@@ -4320,6 +4315,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
private static ReceiverValue getConstructorReceiver(@NotNull ResolvedCall<?> resolvedCall) {
CallableDescriptor constructor = resolvedCall.getResultingDescriptor();
if (constructor.getExtensionReceiverParameter() != null) {
// see comment on `withDispatchReceiver` parameter in
// org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptorImpl.Companion.createIfAvailable
assert constructor instanceof TypeAliasConstructorDescriptor :
"Only type alias constructor can have an extension receiver: " + constructor;
return resolvedCall.getExtensionReceiver();

View File

@@ -88,6 +88,7 @@ import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.
import static org.jetbrains.kotlin.types.Variance.INVARIANT;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isLocalFunction;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
import static org.jetbrains.org.objectweb.asm.Type.getObjectType;
public class ImplementationBodyCodegen extends ClassBodyCodegen {
private static final String ENUM_VALUES_FIELD_NAME = "$VALUES";
@@ -113,7 +114,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
boolean isLocal
) {
super(aClass, context, v, state, parentCodegen);
this.classAsmType = typeMapper.mapClass(descriptor);
this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor));
this.isLocal = isLocal;
delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries());
}
@@ -127,43 +128,35 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
boolean isAbstract = false;
boolean isInterface = false;
boolean isFinal = false;
boolean isStatic;
boolean isAnnotation = false;
boolean isEnum = false;
ClassKind kind = descriptor.getKind();
if (kind == ClassKind.OBJECT) {
isStatic = isCompanionObject(descriptor);
isFinal = true;
Modality modality = descriptor.getModality();
if (modality == Modality.ABSTRACT || modality == Modality.SEALED) {
isAbstract = true;
}
else {
Modality modality = descriptor.getModality();
if (modality == Modality.ABSTRACT || modality == Modality.SEALED) {
isAbstract = true;
}
if (kind == ClassKind.INTERFACE) {
isAbstract = true;
isInterface = true;
}
else if (kind == ClassKind.ANNOTATION_CLASS) {
isAbstract = true;
isInterface = true;
isAnnotation = true;
}
else if (kind == ClassKind.ENUM_CLASS) {
isAbstract = hasAbstractMembers(descriptor);
isEnum = true;
}
if (kind == ClassKind.INTERFACE) {
isAbstract = true;
isInterface = true;
}
else if (kind == ClassKind.ANNOTATION_CLASS) {
isAbstract = true;
isInterface = true;
isAnnotation = true;
}
else if (kind == ClassKind.ENUM_CLASS) {
isAbstract = hasAbstractMembers(descriptor);
isEnum = true;
}
if (modality != Modality.OPEN && !isAbstract) {
// Light-class mode: Do not make enum classes final since PsiClass corresponding to enum is expected to be inheritable from
isFinal = !(kind == ClassKind.ENUM_CLASS && !state.getClassBuilderMode().generateBodies);
}
isStatic = !descriptor.isInner();
if (modality != Modality.OPEN && !isAbstract) {
isFinal = kind == ClassKind.OBJECT ||
// Light-class mode: Do not make enum classes final since PsiClass corresponding to enum is expected to be inheritable from
!(kind == ClassKind.ENUM_CLASS && !state.getClassBuilderMode().generateBodies);
}
int access = 0;
@@ -175,7 +168,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
// Thus we must write full accessibility flags on inner classes in this mode
access |= getVisibilityAccessFlag(descriptor);
// Same for STATIC
if (isStatic) {
if (!descriptor.isInner()) {
access |= ACC_STATIC;
}
}
@@ -332,7 +325,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
for (String kotlinMarkerInterface : kotlinMarkerInterfaces) {
sw.writeInterface();
sw.writeAsmType(Type.getObjectType(kotlinMarkerInterface));
sw.writeAsmType(getObjectType(kotlinMarkerInterface));
sw.writeInterfaceEnd();
}
@@ -1207,9 +1200,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
else if (descriptor instanceof VariableDescriptor) {
if (descriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
ClassDescriptor classDescriptor =
(ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration();
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof ConstructorDescriptor) {
ClassDescriptor classDescriptor = ((ConstructorDescriptor) containingDeclaration).getConstructedClass();
if (classDescriptor == ImplementationBodyCodegen.this.descriptor) return;
}
lookupInContext(descriptor);

View File

@@ -127,7 +127,10 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
generateBody();
generateSyntheticParts();
if (!(element instanceof KtClassOrObject) ||
state.getGenerateDeclaredClassFilter().shouldGenerateClassMembers((KtClassOrObject) element)) {
generateSyntheticParts();
}
if (state.getClassBuilderMode().generateMetadata) {
generateKotlinMetadataAnnotation();
@@ -342,17 +345,19 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
}
private void writeInnerClass(@NotNull ClassDescriptor innerClass) {
writeInnerClass(innerClass, typeMapper, v);
if (!ErrorUtils.isError(innerClass)) {
writeInnerClass(innerClass, typeMapper, v);
}
}
public static void writeInnerClass(@NotNull ClassDescriptor innerClass, @NotNull KotlinTypeMapper typeMapper, @NotNull ClassBuilder v) {
DeclarationDescriptor containing = innerClass.getContainingDeclaration();
String outerClassInternalName = null;
if (containing instanceof ClassDescriptor) {
outerClassInternalName = typeMapper.mapClass((ClassDescriptor) containing).getInternalName();
outerClassInternalName = typeMapper.classInternalName((ClassDescriptor) containing);
}
String innerName = innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName();
String innerClassInternalName = typeMapper.classInternalName(innerClass);
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
}

View File

@@ -176,7 +176,7 @@ class MultifileClassPartCodegen(
}
val serializer = DescriptorSerializer.createTopLevel(JvmSerializerExtension(v.serializationBindings, state))
val packageProto = serializer.packagePartProto(members).build()
val packageProto = serializer.packagePartProto(packageFragment.fqName, members).build()
val extraFlags = if (shouldGeneratePartHierarchy) JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG else 0

View File

@@ -129,7 +129,7 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
final DescriptorSerializer serializer =
DescriptorSerializer.createTopLevel(new JvmSerializerExtension(v.getSerializationBindings(), state));
final ProtoBuf.Package packageProto = serializer.packagePartProto(members).build();
final ProtoBuf.Package packageProto = serializer.packagePartProto(element.getPackageFqName(), members).build();
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.FILE_FACADE, 0, new Function1<AnnotationVisitor, Unit>() {
@Override

View File

@@ -57,7 +57,6 @@ import java.util.List;
import static org.jetbrains.kotlin.codegen.AsmUtil.getDeprecatedAccessFlag;
import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityForBackingField;
import static org.jetbrains.kotlin.codegen.AsmUtil.isPropertyWithBackingFieldCopyInOuterClass;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY;
@@ -189,7 +188,7 @@ public class PropertyCodegen {
if (isCompanionObject(descriptor.getContainingDeclaration())) return true;
// Non-const properties from multifile classes have accessors regardless of visibility
if (!descriptor.isConst() && JvmFileClassUtilKt.isInsideJvmMultifileClassFile(declaration)) return true;
if (isNonConstTopLevelPropertyInMultifileClass(declaration, descriptor)) return true;
// Private class properties have accessors only in cases when those accessors are non-trivial
if (Visibilities.isPrivate(descriptor.getVisibility())) {
@@ -199,6 +198,15 @@ public class PropertyCodegen {
return true;
}
private static boolean isNonConstTopLevelPropertyInMultifileClass(
@NotNull KtProperty declaration,
@NotNull PropertyDescriptor descriptor
) {
return !descriptor.isConst() &&
descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor &&
JvmFileClassUtilKt.isInsideJvmMultifileClassFile(declaration);
}
private static boolean areAccessorsNeededForPrimaryConstructorProperty(
@NotNull PropertyDescriptor descriptor
) {

View File

@@ -34,7 +34,7 @@ data class SourceInfo(val source: String, val pathOrCleanFQN: String, val linesI
val isTopLevel = element is KtFile || (element is KtNamedFunction && element.getParent() is KtFile)
val cleanedClassFqName = if (!isTopLevel) internalClassName else internalClassName.substringBefore('$')
return SourceInfo(element.getContainingKtFile().name, cleanedClassFqName, lineNumbers!!)
return SourceInfo(element.containingKtFile.name, cleanedClassFqName, lineNumbers!!)
}
}

View File

@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
@@ -281,60 +282,29 @@ public abstract class StackValue {
}
private static void box(Type type, Type toType, InstructionAdapter v) {
if (type == Type.BYTE_TYPE || toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME) && type == Type.INT_TYPE) {
v.cast(type, Type.BYTE_TYPE);
v.invokestatic(NULLABLE_BYTE_TYPE_NAME, "valueOf", "(B)L" + NULLABLE_BYTE_TYPE_NAME + ";", false);
}
else if (type == Type.SHORT_TYPE || toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME) && type == Type.INT_TYPE) {
v.cast(type, Type.SHORT_TYPE);
v.invokestatic(NULLABLE_SHORT_TYPE_NAME, "valueOf", "(S)L" + NULLABLE_SHORT_TYPE_NAME + ";", false);
}
else if (type == Type.LONG_TYPE || toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME) && type == Type.INT_TYPE) {
v.cast(type, Type.LONG_TYPE);
v.invokestatic(NULLABLE_LONG_TYPE_NAME, "valueOf", "(J)L" + NULLABLE_LONG_TYPE_NAME + ";", false);
}
else if (type == Type.INT_TYPE) {
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
}
else if (type == Type.BOOLEAN_TYPE) {
v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
}
else if (type == Type.CHAR_TYPE) {
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
}
else if (type == Type.FLOAT_TYPE) {
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
}
else if (type == Type.DOUBLE_TYPE) {
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
if (type == Type.INT_TYPE) {
if (toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME)) {
type = Type.BYTE_TYPE;
}
else if (toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME)) {
type = Type.SHORT_TYPE;
}
else if (toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME)) {
type = Type.LONG_TYPE;
}
v.cast(Type.INT_TYPE, type);
}
Type boxedType = AsmUtil.boxType(type);
if (boxedType == type) return;
v.invokestatic(boxedType.getInternalName(), "valueOf", Type.getMethodDescriptor(boxedType, type), false);
coerce(boxedType, toType, v);
}
private static void unbox(Type type, InstructionAdapter v) {
if (type == Type.INT_TYPE) {
v.invokevirtual("java/lang/Number", "intValue", "()I", false);
}
else if (type == Type.BOOLEAN_TYPE) {
v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z", false);
}
else if (type == Type.CHAR_TYPE) {
v.invokevirtual("java/lang/Character", "charValue", "()C", false);
}
else if (type == Type.SHORT_TYPE) {
v.invokevirtual("java/lang/Number", "shortValue", "()S", false);
}
else if (type == Type.LONG_TYPE) {
v.invokevirtual("java/lang/Number", "longValue", "()J", false);
}
else if (type == Type.BYTE_TYPE) {
v.invokevirtual("java/lang/Number", "byteValue", "()B", false);
}
else if (type == Type.FLOAT_TYPE) {
v.invokevirtual("java/lang/Number", "floatValue", "()F", false);
}
else if (type == Type.DOUBLE_TYPE) {
v.invokevirtual("java/lang/Number", "doubleValue", "()D", false);
}
private static void unbox(Type methodOwner, Type type, InstructionAdapter v) {
assert isPrimitive(type) : "Unboxing should be performed to primitive type, but " + type.getClassName();
v.invokevirtual(methodOwner.getInternalName(), type.getClassName() + "Value", "()" + type.getDescriptor(), false);
}
protected void coerceTo(@NotNull Type toType, @NotNull InstructionAdapter v) {
@@ -372,23 +342,12 @@ public abstract class StackValue {
}
}
else if (toType.getSort() == Type.ARRAY) {
if (fromType.getSort() == Type.ARRAY &&
fromType.getElementType().equals(AsmTypes.JAVA_CLASS_TYPE) && toType.equals(K_CLASS_ARRAY_TYPE)) {
wrapJavaClassesIntoKClasses(v);
}
else {
v.checkcast(toType);
}
v.checkcast(toType);
}
else if (toType.getSort() == Type.OBJECT) {
if (fromType.getSort() == Type.OBJECT || fromType.getSort() == Type.ARRAY) {
if (!toType.equals(OBJECT_TYPE)) {
if (fromType.equals(AsmTypes.JAVA_CLASS_TYPE) && toType.equals(AsmTypes.K_CLASS_TYPE)) {
wrapJavaClassIntoKClass(v);
}
else {
v.checkcast(toType);
}
v.checkcast(toType);
}
}
else {
@@ -396,20 +355,29 @@ public abstract class StackValue {
}
}
else if (fromType.getSort() == Type.OBJECT) {
//toType is primitive here
Type unboxedType = unboxPrimitiveTypeOrNull(fromType);
if (unboxedType != null) {
unbox(unboxedType, v);
unbox(fromType, unboxedType, v);
coerce(unboxedType, toType, v);
}
else {
Type numberType = getType(Number.class);
if (toType.getSort() == Type.BOOLEAN || (toType.getSort() == Type.CHAR && !numberType.equals(fromType))) {
coerce(fromType, boxType(toType), v);
else if (toType.getSort() == Type.BOOLEAN) {
coerce(fromType, BOOLEAN_WRAPPER_TYPE, v);
unbox(BOOLEAN_WRAPPER_TYPE, Type.BOOLEAN_TYPE, v);
}
else if (toType.getSort() == Type.CHAR) {
if (fromType.equals(NUMBER_TYPE)) {
unbox(NUMBER_TYPE, Type.INT_TYPE, v);
v.visitInsn(Opcodes.I2C);
}
else {
coerce(fromType, numberType, v);
coerce(fromType, CHARACTER_WRAPPER_TYPE, v);
unbox(CHARACTER_WRAPPER_TYPE, Type.CHAR_TYPE, v);
}
unbox(toType, v);
}
else {
coerce(fromType, NUMBER_TYPE, v);
unbox(NUMBER_TYPE, toType, v);
}
}
else {
@@ -1211,7 +1179,20 @@ public abstract class StackValue {
else {
getter.genInvokeInstruction(v);
}
coerce(getter.getReturnType(), type, v);
Type typeOfValueOnStack = getter.getReturnType();
if (DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration())) {
if (this.type.equals(K_CLASS_TYPE)) {
wrapJavaClassIntoKClass(v);
typeOfValueOnStack = K_CLASS_TYPE;
}
else if (this.type.equals(K_CLASS_ARRAY_TYPE)) {
wrapJavaClassesIntoKClasses(v);
typeOfValueOnStack = K_CLASS_ARRAY_TYPE;
}
}
coerce(typeOfValueOnStack, type, v);
KotlinType returnType = descriptor.getReturnType();
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
@@ -1378,9 +1359,7 @@ public abstract class StackValue {
default:
PrimitiveType primitiveType = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(type);
if (primitiveType == null) throw new UnsupportedOperationException();
String typeName = primitiveType.getTypeName().getIdentifier();
return Type.getObjectType(REF_TYPE_PREFIX + typeName + "Ref");
return sharedTypeForPrimitive(primitiveType);
}
}

View File

@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getParentCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeAsSequence
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.singletonOrEmptyList
import java.util.*
class BridgeForBuiltinSpecial<out Signature : Any>(
@@ -76,7 +75,7 @@ object BuiltinSpecialBridgesUtil {
else null
val commonBridges = reachableDeclarations.mapTo(LinkedHashSet<Signature>(), signatureByDescriptor)
commonBridges.removeAll(specialBridgesSignaturesInSuperClass + specialBridge?.from.singletonOrEmptyList())
commonBridges.removeAll(specialBridgesSignaturesInSuperClass + listOfNotNull(specialBridge?.from))
if (fake) {
for (overridden in function.overriddenDescriptors.map { it.original }) {

View File

@@ -42,7 +42,6 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.singletonOrEmptyList
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -289,8 +288,8 @@ class CoroutineCodegen private constructor(
}
private fun allFunctionParameters() =
originalSuspendFunctionDescriptor.extensionReceiverParameter.singletonOrEmptyList() +
originalSuspendFunctionDescriptor.valueParameters.orEmpty()
listOfNotNull(originalSuspendFunctionDescriptor.extensionReceiverParameter) +
originalSuspendFunctionDescriptor.valueParameters.orEmpty()
private fun ParameterDescriptor.getFieldInfoForCoroutineLambdaParameter() =
createHiddenFieldInfo(type, COROUTINE_LAMBDA_PARAMETER_PREFIX + (this.safeAs<ValueParameterDescriptor>()?.index ?: ""))

View File

@@ -294,7 +294,7 @@ class CoroutineTransformerMethodVisitor(
get() {
assert(suspensionCallEnd.next is LabelNode) {
"Next instruction after ${this} should be a label, but " +
"${suspensionCallEnd.next.javaClass}/${suspensionCallEnd.next.opcode} was found"
"${suspensionCallEnd.next::class.java}/${suspensionCallEnd.next.opcode} was found"
}
return suspensionCallEnd.next as LabelNode
@@ -421,7 +421,7 @@ private fun InstructionAdapter.generateResumeWithExceptionCheck() {
private fun Type.fieldNameForVar(index: Int) = descriptor.first() + "$" + index
private fun withInstructionAdapter(block: InstructionAdapter.() -> Unit): InsnList {
inline fun withInstructionAdapter(block: InstructionAdapter.() -> Unit): InsnList {
val tmpMethodNode = MethodNode()
InstructionAdapter(tmpMethodNode).apply(block)

View File

@@ -217,7 +217,7 @@ private class VarExpectedTypeFrame(maxLocals: Int) : VarFrame<VarExpectedTypeFra
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
if (other == null || other::class.java != this::class.java) return false
other as VarExpectedTypeFrame

View File

@@ -66,7 +66,6 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
createClassReader().accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
@Override
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
InlineCodegenUtil.assertVersionNotGreaterThanGeneratedOne(version, name, inliningContext.state);
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces);
if(CoroutineCodegenUtilKt.COROUTINE_IMPL_ASM_TYPE.getInternalName().equals(superName)) {
inliningContext.setContinuation(true);
@@ -271,7 +270,7 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
//TODO for inline method make public class
transformationInfo.setNewConstructorDescriptor(constructorDescriptor);
MethodVisitor constructorVisitor = classBuilder.newMethod(
NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY
NO_ORIGIN, constructor.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY
);
final Label newBodyStartLabel = new Label();
@@ -312,7 +311,7 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
}
MethodNode intermediateMethodNode =
new MethodNode(AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
new MethodNode(constructor.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor, constructorInlineBuilder, true);
InlineCodegenUtil.removeFinallyMarkers(intermediateMethodNode);

View File

@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
@@ -202,7 +203,7 @@ public class InlineCodegen extends CallGenerator {
MethodNode node = nodeAndSmap != null ? nodeAndSmap.getNode() : null;
throw new CompilationException(
"Couldn't inline method call '" + functionDescriptor.getName() + "' into\n" +
contextDescriptor + "\n" +
DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" +
(element != null ? element.getText() : "<no source>") +
(generateNodeText ? ("\nCause: " + InlineCodegenUtil.getNodeText(node)) : ""),
e, callElement
@@ -321,7 +322,7 @@ public class InlineCodegen extends CallGenerator {
}
});
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId, state);
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId);
}
assert callableDescriptor instanceof DeserializedCallableMemberDescriptor : "Not a deserialized function or proper: " + callableDescriptor;
@@ -348,7 +349,7 @@ public class InlineCodegen extends CallGenerator {
});
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId, state);
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId);
}
@NotNull

View File

@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.fileClasses.FileClasses;
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder;
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.tree.*;
import org.jetbrains.org.objectweb.asm.util.Printer;
import org.jetbrains.org.objectweb.asm.util.Textifier;
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
@@ -92,8 +93,7 @@ public class InlineCodegenUtil {
byte[] classData,
final String methodName,
final String methodDescriptor,
ClassId classId,
final @NotNull GenerationState state
ClassId classId
) {
ClassReader cr = new ClassReader(classData);
final MethodNode[] node = new MethodNode[1];
@@ -103,10 +103,6 @@ public class InlineCodegenUtil {
lines[1] = Integer.MIN_VALUE;
//noinspection PointlessBitwiseExpression
cr.accept(new ClassVisitor(API) {
@Override
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
assertVersionNotGreaterThanGeneratedOne(version, name, state);
}
@Override
public void visitSource(String source, String debug) {
@@ -151,16 +147,6 @@ public class InlineCodegenUtil {
return new SMAPAndMethodNode(node[0], smap);
}
public static void assertVersionNotGreaterThanGeneratedOne(int version, String internalName, @NotNull GenerationState state) {
// TODO: report a proper diagnostic
if (version > state.getClassFileVersion() && !"true".equals(System.getProperty("kotlin.skip.bytecode.version.check"))) {
throw new UnsupportedOperationException(
"Cannot inline bytecode of class " + internalName + " which has version " + version + ". " +
"This compiler can only inline Java 1.6 bytecode (version " + Opcodes.V1_6 + ")"
);
}
}
public static void initDefaultSourceMappingIfNeeded(
@NotNull CodegenContext context, @NotNull MemberCodegen codegen, @NotNull GenerationState state
) {
@@ -179,7 +165,7 @@ public class InlineCodegenUtil {
@Nullable
public static VirtualFile findVirtualFile(@NotNull GenerationState state, @NotNull ClassId classId) {
return JvmVirtualFileFinder.SERVICE.getInstance(state.getProject()).findVirtualFileWithHeader(classId);
return VirtualFileFinder.SERVICE.getInstance(state.getProject()).findVirtualFileWithHeader(classId);
}
@Nullable
@@ -405,6 +391,11 @@ public class InlineCodegenUtil {
return sw.toString().trim();
}
@NotNull
public static String getInsnOpcodeText(@Nullable AbstractInsnNode node) {
return node == null ? "null" : Printer.OPCODES[node.getOpcode()];
}
@NotNull
/* package */ static ClassReader buildClassReaderByInternalName(@NotNull GenerationState state, @NotNull String internalName) {
//try to find just compiled classes then in dependencies

View File

@@ -252,6 +252,7 @@ public class MethodInliner {
//TODO add skipped this and receiver
InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info, invokeCall.finallyDepthShift);
result.mergeWithNotChangeInfo(lambdaResult);
result.getReifiedTypeParametersUsages().mergeAll(lambdaResult.getReifiedTypeParametersUsages());
//return value boxing/unboxing
Method bridge = typeMapper.mapAsmMethod(ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor()));
@@ -486,6 +487,11 @@ public class MethodInliner {
);
awaitClassReification = false;
}
else if (inliningContext.isInliningLambda && ReifiedTypeInliner.Companion.isOperationReifiedMarker(cur)) {
ReificationArgument reificationArgument = ReifiedTypeInlinerKt.getReificationArgument((MethodInsnNode) cur);
String parameterName = reificationArgument.getParameterName();
result.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterName);
}
}
else if (cur.getOpcode() == Opcodes.GETSTATIC) {
FieldInsnNode fieldInsnNode = (FieldInsnNode) cur;

View File

@@ -66,7 +66,6 @@ class WhenMappingTransformer(
val fieldNode = transformationInfo.fieldNode
classReader.accept(object : ClassVisitor(InlineCodegenUtil.API, classBuilder.visitor) {
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
InlineCodegenUtil.assertVersionNotGreaterThanGeneratedOne(version, name, state)
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces)
}

View File

@@ -70,7 +70,5 @@ internal class Parameters(val parameters: List<ParameterInfo>) : Iterable<Parame
}
val capturedTypes: List<Type>
get() = captured.map {
it.getType()
}
get() = captured.map(CapturedParamInfo::getType)
}

View File

@@ -70,7 +70,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
const val REIFIED_OPERATION_MARKER_METHOD_NAME = "reifiedOperationMarker"
const val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME = "needClassReification"
private fun isOperationReifiedMarker(insn: AbstractInsnNode) =
fun isOperationReifiedMarker(insn: AbstractInsnNode) =
isReifiedMarker(insn) { it == REIFIED_OPERATION_MARKER_METHOD_NAME }
private fun isReifiedMarker(insn: AbstractInsnNode, namePredicate: (String) -> Boolean): Boolean {
@@ -247,7 +247,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
}
}
private val MethodInsnNode.reificationArgument: ReificationArgument?
val MethodInsnNode.reificationArgument: ReificationArgument?
get() {
val prev = previous!!

View File

@@ -57,7 +57,7 @@ class SMAPBuilder(
private fun generateDebugStrata(realMappings: List<FileMapping>): String {
val combinedMapping = FileMapping(source, path)
realMappings.forEach { fileMapping ->
fileMapping.lineMappings.filter { it.callSiteMarker != null }.forEach { (source, dest, range, callSiteMarker) ->
fileMapping.lineMappings.filter { it.callSiteMarker != null }.forEach { (_, dest, range, callSiteMarker) ->
combinedMapping.addRangeMapping(RangeMapping(
callSiteMarker!!.lineNumber, dest, range
))

View File

@@ -28,7 +28,7 @@ internal val classId: ClassId =
ClassId.topLevel(FqName("org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt"))
internal val bytecode: ByteArray by lazy {
val stream = object {}.javaClass.classLoader.getResourceAsStream("${classId.asString()}.class")
val stream = object {}::class.java.classLoader.getResourceAsStream("${classId.asString()}.class")
stream.readBytes().apply {
stream.close()
}

View File

@@ -58,7 +58,7 @@ object JavaClassProperty : IntrinsicPropertyGetter() {
}
override fun toCallable(fd: FunctionDescriptor, isSuper: Boolean, resolvedCall: ResolvedCall<*>, codegen: ExpressionCodegen): Callable {
val classType = codegen.getState().typeMapper.mapType(resolvedCall.call.dispatchReceiver!!.type)
val classType = codegen.state.typeMapper.mapType(resolvedCall.call.dispatchReceiver!!.type)
return object : IntrinsicCallable(getType(Class::class.java), listOf(), classType, null) {
override fun invokeIntrinsic(v: InstructionAdapter) {
if (isPrimitive(classType)) {

View File

@@ -26,7 +26,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class NewArray : IntrinsicMethod() {
override fun toCallable(fd: FunctionDescriptor, isSuper: Boolean, resolvedCall: ResolvedCall<*>, codegen: ExpressionCodegen): Callable {
val jetType = resolvedCall.resultingDescriptor.returnType!!
val type = codegen.getState().typeMapper.mapType(jetType)
val type = codegen.state.typeMapper.mapType(jetType)
return object : IntrinsicCallable(type, listOf(Type.INT_TYPE), null, null) {
override fun invokeIntrinsic(v: InstructionAdapter) {
codegen.newArrayInstruction(jetType)

View File

@@ -29,9 +29,13 @@ class DeadCodeEliminationMethodTransformer : MethodTransformer() {
}
fun transformWithResult(internalClassName: String, methodNode: MethodNode): Result {
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
return removeDeadCodeByFrames(methodNode, frames)
}
fun removeDeadCodeByFrames(methodNode: MethodNode, frames: Array<out Any?>): Result {
val removedNodes = HashSet<AbstractInsnNode>()
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
val insnList = methodNode.instructions
val insnsArray = insnList.toArray()
@@ -51,6 +55,7 @@ class DeadCodeEliminationMethodTransformer : MethodTransformer() {
}
class Result(val removedNodes: Set<AbstractInsnNode>) {
fun hasRemovedAnything() = removedNodes.isNotEmpty()
fun isRemoved(node: AbstractInsnNode) = removedNodes.contains(node)
fun isAlive(node: AbstractInsnNode) = !isRemoved(node)
}

View File

@@ -21,8 +21,9 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor;
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer;
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantCoercionToUnitTransformer;
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantNullCheckMethodTransformer;
import org.jetbrains.kotlin.codegen.optimization.captured.CapturedVarsOptimizationMethodTransformer;
import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
import org.jetbrains.kotlin.codegen.optimization.nullCheck.RedundantNullCheckV2MethodTransformer;
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
@@ -33,7 +34,9 @@ public class OptimizationMethodVisitor extends TransformationMethodVisitor {
private static final MethodTransformer MANDATORY_METHOD_TRANSFORMER = new FixStackWithLabelNormalizationMethodTransformer();
private static final MethodTransformer[] OPTIMIZATION_TRANSFORMERS = new MethodTransformer[] {
new RedundantNullCheckMethodTransformer(),
new CapturedVarsOptimizationMethodTransformer(),
new RedundantNullCheckV2MethodTransformer(),
new RedundantCheckCastEliminationMethodTransformer(),
new RedundantBoxingMethodTransformer(),
new RedundantCoercionToUnitTransformer(),
new DeadCodeEliminationMethodTransformer(),

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.nullCheck.popReferenceValueBefore
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) {
val insns = methodNode.instructions.toArray()
if (!insns.any { it.opcode == Opcodes.CHECKCAST }) return
val redundantCheckCasts = ArrayList<TypeInsnNode>()
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
for (i in insns.indices) {
val valueType = frames[i]?.top()?.type ?: continue
val insn = insns[i]
if (ReifiedTypeInliner.isOperationReifiedMarker(insn.previous)) continue
if (insn is TypeInsnNode) {
val insnType = Type.getObjectType(insn.desc)
if (!isTrivialSubtype(insnType, valueType)) continue
if (insn.opcode == Opcodes.CHECKCAST) {
redundantCheckCasts.add(insn)
}
}
}
redundantCheckCasts.forEach {
methodNode.instructions.remove(it)
}
}
private fun isTrivialSubtype(superType: Type, subType: Type) =
superType == subType
}

View File

@@ -20,7 +20,6 @@ import com.intellij.openapi.util.Pair
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.utils.toReadOnlyList
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import java.util.*
@@ -66,7 +65,7 @@ class BoxedValueDescriptor(
var isSafeToRemove = true; private set
val unboxedType: Type = getUnboxedType(boxedType)
fun getAssociatedInsns() = associatedInsns.toReadOnlyList()
fun getAssociatedInsns() = associatedInsns.toList()
fun addInsn(insnNode: AbstractInsnNode) {
associatedInsns.add(insnNode)

View File

@@ -35,14 +35,12 @@ import java.util.*
open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasicInterpreter() {
private val boxingPlaces = HashMap<Int, BoxedBasicValue>()
protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue {
val index = insnList.indexOf(insn)
return boxingPlaces.getOrPut(index) {
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
onNewBoxedValue(boxedBasicValue)
boxedBasicValue
}
}
protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue =
boxingPlaces.getOrPut(insnList.indexOf(insn)) {
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
onNewBoxedValue(boxedBasicValue)
boxedBasicValue
}
protected fun checkUsedValue(value: BasicValue) {
if (value is TaintedBoxedValue) {
@@ -66,14 +64,17 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
onUnboxing(insn, firstArg, value.type)
value
}
insn.isIteratorMethodCallOfProgression(values) -> {
ProgressionIteratorBasicValue(getValuesTypeOfProgressionClass(firstArg.type.internalName))
}
insn.isIteratorMethodCallOfProgression(values) ->
ProgressionIteratorBasicValue.byProgressionClassType(firstArg.type)
insn.isNextMethodCallOfProgressionIterator(values) -> {
val progressionIterator = firstArg as? ProgressionIteratorBasicValue
?: throw AssertionError("firstArg should be progression iterator")
createNewBoxing(insn, AsmUtil.boxType(progressionIterator.valuesPrimitiveType), progressionIterator)
}
insn.isAreEqualIntrinsicForSameTypedBoxedValues(values) && canValuesBeUnboxedForAreEqual(values) -> {
onAreEqual(insn, values[0] as BoxedBasicValue, values[1] as BoxedBasicValue)
value
}
else -> {
// N-ary operation should be a method call or multinewarray.
// Arguments for multinewarray could be only numeric,
@@ -100,7 +101,7 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
protected open fun isExactValue(value: BasicValue) =
value is ProgressionIteratorBasicValue ||
value is CleanBoxedValue ||
value.type != null && isProgressionClass(value.type.internalName)
value.type != null && isProgressionClass(value.type)
override fun merge(v: BasicValue, w: BasicValue) =
when {
@@ -125,6 +126,7 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
protected open fun onNewBoxedValue(value: BoxedBasicValue) {}
protected open fun onUnboxing(insn: AbstractInsnNode, value: BoxedBasicValue, resultType: Type) {}
protected open fun onAreEqual(insn: AbstractInsnNode, value1: BoxedBasicValue, value2: BoxedBasicValue) {}
protected open fun onMethodCallWithBoxedValue(value: BoxedBasicValue) {}
protected open fun onMergeFail(value: BoxedBasicValue) {}
protected open fun onMergeSuccess(v: BoxedBasicValue, w: BoxedBasicValue) {}
@@ -190,23 +192,44 @@ private fun AbstractInsnNode.isJavaLangClassBoxing() =
desc == JLCLASS_TO_KCLASS
}
private fun AbstractInsnNode.isNextMethodCallOfProgressionIterator(values: List<BasicValue>) =
values[0] is ProgressionIteratorBasicValue &&
fun AbstractInsnNode.isNextMethodCallOfProgressionIterator(values: List<BasicValue>) =
values.firstOrNull() is ProgressionIteratorBasicValue &&
isMethodInsnWith(Opcodes.INVOKEINTERFACE) {
name == "next"
}
private fun AbstractInsnNode.isIteratorMethodCallOfProgression(values: List<BasicValue>) =
fun AbstractInsnNode.isIteratorMethodCallOfProgression(values: List<BasicValue>) =
isMethodInsnWith(Opcodes.INVOKEINTERFACE) {
val firstArgType = values[0].type
val firstArgType = values.firstOrNull()?.type
firstArgType != null &&
isProgressionClass(firstArgType.internalName) &&
isProgressionClass(firstArgType) &&
name == "iterator"
}
private fun isProgressionClass(internalClassName: String) =
RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(internalClassName))
fun isProgressionClass(type: Type) =
RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(type.internalName))
private fun getValuesTypeOfProgressionClass(progressionClassInternalName: String) =
RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(buildFqNameByInternal(progressionClassInternalName))
?.typeName?.asString() ?: error("type should be not null")
fun AbstractInsnNode.isAreEqualIntrinsicForSameTypedBoxedValues(values: List<BasicValue>) =
isAreEqualIntrinsic() && run {
if (values.size != 2) return false
val (v1, v2) = values
if (v1 !is BoxedBasicValue || v2 !is BoxedBasicValue) return false
val d1 = v1.descriptor
val d2 = v2.descriptor
d1.unboxedType == d2.unboxedType
}
fun AbstractInsnNode.isAreEqualIntrinsic() =
isMethodInsnWith(Opcodes.INVOKESTATIC) {
name == "areEqual" &&
owner == "kotlin/jvm/internal/Intrinsics" &&
desc == "(Ljava/lang/Object;Ljava/lang/Object;)Z"
}
fun canValuesBeUnboxedForAreEqual(values: List<BasicValue>): Boolean =
!values.any {
val unboxedType = getUnboxedType(it.type)
unboxedType == Type.DOUBLE_TYPE || unboxedType == Type.FLOAT_TYPE
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.boxing
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
class NullabilityInterpreter(insns: InsnList) : BoxingInterpreter(insns) {
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue) = makeNotNullIfNeeded(insn, super.unaryOperation(insn, value))
override fun newOperation(insn: AbstractInsnNode) = makeNotNullIfNeeded(insn, super.newOperation(insn))
override fun isExactValue(value: BasicValue) = super.isExactValue(value) || value is NotNullBasicValue
override fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?) =
NotNullBasicValue(type)
}
private fun makeNotNullIfNeeded(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
when (insn.opcode) {
Opcodes.ANEWARRAY, Opcodes.NEWARRAY, Opcodes.LDC, Opcodes.NEW ->
if (value?.type?.sort == Type.OBJECT || value?.type?.sort == Type.ARRAY)
NotNullBasicValue(value.type)
else
value
else -> value
}
class NotNullBasicValue(type: Type?) : StrictBasicValue(type) {
override fun equals(other: Any?): Boolean = other is NotNullBasicValue
// We do not differ not-nullable values, so we should always return the same hashCode
// Actually it doesn't really matter because analyzer is not supposed to store values in hashtables
override fun hashCode() = 0
}

View File

@@ -18,17 +18,18 @@ package org.jetbrains.kotlin.codegen.optimization.boxing;
import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.PrimitiveType;
import org.jetbrains.kotlin.codegen.RangeCodegenUtil;
import org.jetbrains.kotlin.codegen.intrinsics.IteratorNext;
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
import org.jetbrains.org.objectweb.asm.Type;
public class ProgressionIteratorBasicValue extends StrictBasicValue {
private final static ImmutableMap<String, Type> VALUES_TYPENAME_TO_TYPE;
static {
ImmutableMap.Builder<String, Type> builder = ImmutableMap.builder();
for (PrimitiveType primitiveType : RangeCodegenUtil.supportedRangeTypes()) {
@@ -37,6 +38,15 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue {
VALUES_TYPENAME_TO_TYPE = builder.build();
}
private static final ImmutableMap<PrimitiveType, ProgressionIteratorBasicValue> ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE;
static {
ImmutableMap.Builder<PrimitiveType, ProgressionIteratorBasicValue> builder = ImmutableMap.builder();
for (PrimitiveType elementType : RangeCodegenUtil.supportedRangeTypes()) {
builder.put(elementType, new ProgressionIteratorBasicValue(elementType.getTypeName().asString()));
}
ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE = builder.build();
}
@NotNull
private static Type getValuesType(@NotNull String valuesTypeName) {
Type type = VALUES_TYPENAME_TO_TYPE.get(valuesTypeName);
@@ -47,12 +57,20 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue {
private final Type valuesPrimitiveType;
private final String valuesPrimitiveTypeName;
public ProgressionIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
private ProgressionIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
super(IteratorNext.Companion.getPrimitiveIteratorType(Name.identifier(valuesPrimitiveTypeName)));
this.valuesPrimitiveType = getValuesType(valuesPrimitiveTypeName);
this.valuesPrimitiveTypeName = valuesPrimitiveTypeName;
}
@Nullable
public static ProgressionIteratorBasicValue byProgressionClassType(@NotNull Type progressionClassType) {
FqName classFqName = new FqName(progressionClassType.getClassName());
PrimitiveType elementType = RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(classFqName);
return ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE.get(elementType);
}
@NotNull
public Type getValuesPrimitiveType() {
return valuesPrimitiveType;

View File

@@ -84,6 +84,13 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
}
}
override fun onAreEqual(insn: AbstractInsnNode, value1: BoxedBasicValue, value2: BoxedBasicValue) {
val descriptor1 = value1.descriptor
val descriptor2 = value2.descriptor
candidatesBoxedValues.merge(descriptor1, descriptor2)
descriptor1.addInsn(insn)
}
override fun onMethodCallWithBoxedValue(value: BoxedBasicValue) {
markValueAsDirty(value)
}

View File

@@ -21,7 +21,9 @@ import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue;
import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
@@ -48,7 +50,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
adaptLocalVariableTableForBoxedValues(node, frames);
applyVariablesRemapping(node, buildVariablesRemapping(valuesToOptimize, node));
UtilKt.remapLocalVariables(node, buildVariablesRemapping(valuesToOptimize, node));
adaptInstructionsForBoxedValues(node, valuesToOptimize);
}
@@ -221,21 +223,6 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
return remapping;
}
private static void applyVariablesRemapping(@NotNull MethodNode node, @NotNull int[] remapping) {
for (AbstractInsnNode insn : node.instructions.toArray()) {
if (insn instanceof VarInsnNode) {
((VarInsnNode) insn).var = remapping[((VarInsnNode) insn).var];
}
if (insn instanceof IincInsnNode) {
((IincInsnNode) insn).var = remapping[((IincInsnNode) insn).var];
}
}
for (LocalVariableNode localVariableNode : node.localVariables) {
localVariableNode.index = remapping[localVariableNode.index];
}
}
private static void adaptInstructionsForBoxedValues(
@NotNull MethodNode node,
@NotNull RedundantBoxedValuesCollection values
@@ -341,9 +328,68 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
);
node.instructions.set(insn, new InsnNode(Opcodes.ICONST_1));
break;
case Opcodes.INVOKESTATIC:
if (BoxingInterpreterKt.isAreEqualIntrinsic(insn)) {
adaptAreEqualIntrinsic(node, insn, value);
break;
}
else {
// fall-through to default
}
default:
// CHECKCAST or unboxing-method call
node.instructions.remove(insn);
}
}
private static void adaptAreEqualIntrinsic(@NotNull MethodNode node, @NotNull AbstractInsnNode insn, @NotNull BoxedValueDescriptor value) {
Type unboxedType = value.getUnboxedType();
switch (unboxedType.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
case Type.CHAR:
adaptAreEqualIntrinsicForInt(node, insn);
break;
case Type.LONG:
adaptAreEqualIntrinsicForLong(node, insn);
break;
case Type.OBJECT:
break;
default:
throw new AssertionError("Unexpected unboxed type kind: " + unboxedType);
}
}
private static void adaptAreEqualIntrinsicForInt(@NotNull MethodNode node, @NotNull AbstractInsnNode insn) {
LabelNode lNotEqual = new LabelNode(new Label());
LabelNode lDone = new LabelNode(new Label());
node.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.IF_ICMPNE, lNotEqual));
node.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_1));
node.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.GOTO, lDone));
node.instructions.insertBefore(insn, lNotEqual);
node.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_0));
node.instructions.insertBefore(insn, lDone);
node.instructions.remove(insn);
}
private static void adaptAreEqualIntrinsicForLong(@NotNull MethodNode node, @NotNull AbstractInsnNode insn) {
node.instructions.insertBefore(insn, new InsnNode(Opcodes.LCMP));
ifEqual1Else0(node, insn);
node.instructions.remove(insn);
}
private static void ifEqual1Else0(@NotNull MethodNode node, @NotNull AbstractInsnNode insn) {
LabelNode lNotEqual = new LabelNode(new Label());
LabelNode lDone = new LabelNode(new Label());
node.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.IFNE, lNotEqual));
node.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_1));
node.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.GOTO, lDone));
node.instructions.insertBefore(insn, lNotEqual);
node.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_0));
node.instructions.insertBefore(insn, lDone);
}
}

View File

@@ -63,7 +63,7 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
private val frames by lazy { analyzeMethodBody() }
fun transform() {
if (!insns.any { it.isUnitOrNull() }) return
if (!insns.any { it.isUnitInstanceOrNull() }) return
computeTransformations()
for ((insn, transformation) in transformations.entries) {
@@ -158,7 +158,7 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
transformations[insn] = replaceWithPopTransformation(boxedValueSize)
}
insn.isUnitOrNull() -> {
insn.isUnitInstanceOrNull() -> {
transformations[insn] = replaceWithNopTransformation()
}
@@ -232,7 +232,7 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
it.isPrimitiveBoxing() && (it as MethodInsnNode).owner == resultType
private fun isTransformablePopOperand(insn: AbstractInsnNode) =
insn.opcode == Opcodes.CHECKCAST || insn.isPrimitiveBoxing() || insn.isUnitOrNull()
insn.opcode == Opcodes.CHECKCAST || insn.isPrimitiveBoxing() || insn.isUnitInstanceOrNull()
private fun isDontTouch(insn: AbstractInsnNode) =
dontTouchInsnIndices[insnList.indexOf(insn)]
@@ -240,6 +240,9 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
}
fun AbstractInsnNode.isUnitOrNull() =
opcode == Opcodes.ACONST_NULL ||
opcode == Opcodes.GETSTATIC && this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE"
fun AbstractInsnNode.isUnitInstanceOrNull() =
opcode == Opcodes.ACONST_NULL || isUnitInstance()
fun AbstractInsnNode.isUnitInstance() =
opcode == Opcodes.GETSTATIC &&
this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE"

View File

@@ -1,81 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.boxing;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.tree.*;
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame;
import java.util.ArrayList;
import java.util.List;
public class RedundantNullCheckMethodTransformer extends MethodTransformer {
@Override
public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
while (removeRedundantNullCheckPass(internalClassName, methodNode)) {
//do nothing
}
}
private static boolean removeRedundantNullCheckPass(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
InsnList insnList = methodNode.instructions;
Frame<BasicValue>[] frames = analyze(
internalClassName, methodNode,
new NullabilityInterpreter(insnList)
);
List<AbstractInsnNode> insnsToOptimize = new ArrayList<AbstractInsnNode>();
for (int i = 0; i < insnList.size(); i++) {
Frame<BasicValue> frame = frames[i];
AbstractInsnNode insn = insnList.get(i);
if ((insn.getOpcode() == Opcodes.IFNULL || insn.getOpcode() == Opcodes.IFNONNULL) &&
frame != null && frame.getStack(frame.getStackSize() - 1) instanceof NotNullBasicValue) {
insnsToOptimize.add(insn);
}
}
for (AbstractInsnNode insn : insnsToOptimize) {
if (insn.getPrevious() != null && insn.getPrevious().getOpcode() == Opcodes.DUP) {
insnList.remove(insn.getPrevious());
}
else {
insnList.insertBefore(insn, new InsnNode(Opcodes.POP));
}
assert insn.getOpcode() == Opcodes.IFNULL
|| insn.getOpcode() == Opcodes.IFNONNULL : "only IFNULL/IFNONNULL are supported";
if (insn.getOpcode() == Opcodes.IFNULL) {
insnList.remove(insn);
}
else {
insnList.set(
insn,
new JumpInsnNode(Opcodes.GOTO, ((JumpInsnNode) insn).label)
);
}
}
return insnsToOptimize.size() > 0;
}
}

View File

@@ -0,0 +1,264 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.captured
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) {
Transformer(internalClassName, methodNode).run()
}
// Tracks proper usages of objects corresponding to captured variables.
//
// The 'kotlin.jvm.internal.Ref.*' instance can be replaced with a local variable,
// if all of the following conditions are satisfied:
// * It is created inside a current method.
// * The only permitted operations on it are:
// - store to a local variable
// - ALOAD, ASTORE
// - DUP, POP
// - GETFIELD <owner>.element, PUTFIELD <owner>.element
// * There's a corresponding local variable definition,
// and all ALOAD/ASTORE instructions operate on that particular local variable.
// * Its 'element' field is initialized at start of local variable visibility range.
//
// Note that for code that doesn't create Ref objects explicitly these conditions are true,
// unless the Ref object escapes to a local class constructor (including local classes for lambdas).
//
private class CapturedVarDescriptor(val newInsn: TypeInsnNode, val refType: Type, val valueType: Type) : ReferenceValueDescriptor {
var hazard = false
var initCallInsn: MethodInsnNode? = null
var localVar: LocalVariableNode? = null
var localVarIndex = -1
val astoreInsns: MutableCollection<VarInsnNode> = LinkedHashSet()
val aloadInsns: MutableCollection<VarInsnNode> = LinkedHashSet()
val stackInsns: MutableCollection<AbstractInsnNode> = LinkedHashSet()
val getFieldInsns: MutableCollection<FieldInsnNode> = LinkedHashSet()
val putFieldInsns: MutableCollection<FieldInsnNode> = LinkedHashSet()
fun canRewrite(): Boolean =
!hazard &&
initCallInsn != null &&
localVar != null &&
localVarIndex >= 0
override fun onUseAsTainted() {
hazard = true
}
}
private class Transformer(private val internalClassName: String, private val methodNode: MethodNode) {
private val refValues = ArrayList<CapturedVarDescriptor>()
private val refValuesByNewInsn = LinkedHashMap<TypeInsnNode, CapturedVarDescriptor>()
private val insns = methodNode.instructions.toArray()
private lateinit var frames: Array<out Frame<BasicValue>?>
val hasRewritableRefValues: Boolean
get() = refValues.isNotEmpty()
fun run() {
createRefValues()
if (!hasRewritableRefValues) return
analyze()
if (!hasRewritableRefValues) return
rewrite()
}
private fun AbstractInsnNode.getIndex() = methodNode.instructions.indexOf(this)
private fun createRefValues() {
for (insn in insns) {
if (insn.opcode == Opcodes.NEW && insn is TypeInsnNode) {
val type = Type.getObjectType(insn.desc)
if (AsmTypes.isSharedVarType(type)) {
val valueType = REF_TYPE_TO_ELEMENT_TYPE[type.internalName] ?: continue
val refValue = CapturedVarDescriptor(insn, type, valueType)
refValues.add(refValue)
refValuesByNewInsn[insn] = refValue
}
}
}
}
private inner class Interpreter : ReferenceTrackingInterpreter() {
override fun newOperation(insn: AbstractInsnNode): BasicValue =
refValuesByNewInsn[insn]?.let { descriptor ->
ProperTrackedReferenceValue(descriptor.refType, descriptor)
}
?: super.newOperation(insn)
override fun processRefValueUsage(value: TrackedReferenceValue, insn: AbstractInsnNode, position: Int) {
for (descriptor in value.descriptors) {
if (descriptor !is CapturedVarDescriptor) throw AssertionError("Unexpected descriptor: $descriptor")
when {
insn.opcode == Opcodes.ALOAD ->
descriptor.aloadInsns.add(insn as VarInsnNode)
insn.opcode == Opcodes.ASTORE ->
descriptor.astoreInsns.add(insn as VarInsnNode)
insn.opcode == Opcodes.GETFIELD && insn is FieldInsnNode && insn.name == REF_ELEMENT_FIELD && position == 0 ->
descriptor.getFieldInsns.add(insn)
insn.opcode == Opcodes.PUTFIELD && insn is FieldInsnNode && insn.name == REF_ELEMENT_FIELD && position == 0 ->
descriptor.putFieldInsns.add(insn)
insn.opcode == Opcodes.INVOKESPECIAL && insn is MethodInsnNode && insn.name == INIT_METHOD_NAME && position == 0 ->
if (descriptor.initCallInsn != null && descriptor.initCallInsn != insn)
descriptor.hazard = true
else
descriptor.initCallInsn = insn
insn.opcode == Opcodes.DUP ->
descriptor.stackInsns.add(insn)
else ->
descriptor.hazard = true
}
}
}
}
private fun analyze() {
frames = MethodTransformer.analyze(internalClassName, methodNode, Interpreter())
trackPops()
assignLocalVars()
refValues.removeAll { !it.canRewrite() }
}
private fun trackPops() {
for (i in insns.indices) {
val frame = frames[i] ?: continue
val insn = insns[i]
when (insn.opcode) {
Opcodes.POP -> {
frame.top()?.getCapturedVarOrNull()?.run { stackInsns.add(insn) }
}
Opcodes.POP2 -> {
val top = frame.top()
if (top?.size == 1) {
top.getCapturedVarOrNull()?.hazard = true
frame.peek(1)?.getCapturedVarOrNull()?.hazard = true
}
}
}
}
}
private fun BasicValue.getCapturedVarOrNull() =
safeAs<ProperTrackedReferenceValue>()?.descriptor?.safeAs<CapturedVarDescriptor>()
private fun assignLocalVars() {
for (localVar in methodNode.localVariables) {
val type = Type.getType(localVar.desc)
if (!AsmTypes.isSharedVarType(type)) continue
val startFrame = frames[localVar.start.getIndex()] ?: continue
val refValue = startFrame.getLocal(localVar.index) as? ProperTrackedReferenceValue ?: continue
val descriptor = refValue.descriptor as? CapturedVarDescriptor ?: continue
if (descriptor.hazard) continue
if (descriptor.localVar == null) {
descriptor.localVar = localVar
}
else {
descriptor.hazard = true
}
}
for (refValue in refValues) {
if (refValue.hazard) continue
val localVar = refValue.localVar ?: continue
if (refValue.valueType.size != 1) {
refValue.localVarIndex = methodNode.maxLocals
methodNode.maxLocals += 2
localVar.index = refValue.localVarIndex
}
else {
refValue.localVarIndex = localVar.index
}
val startIndex = localVar.start.getIndex()
val initFieldInsns = refValue.putFieldInsns.filter { it.getIndex() < startIndex }
if (initFieldInsns.size != 1) {
refValue.hazard = true
continue
}
}
}
private fun rewrite() {
for (refValue in refValues) {
if (!refValue.canRewrite()) continue
rewriteRefValue(refValue)
}
methodNode.removeEmptyCatchBlocks()
methodNode.removeUnusedLocalVariables()
}
private fun rewriteRefValue(capturedVar: CapturedVarDescriptor) {
methodNode.instructions.run {
capturedVar.localVar!!.let {
it.signature = null
it.desc = capturedVar.valueType.descriptor
}
remove(capturedVar.newInsn)
remove(capturedVar.initCallInsn!!)
capturedVar.stackInsns.forEach { remove(it) }
capturedVar.aloadInsns.forEach { remove(it) }
capturedVar.astoreInsns.forEach { remove(it) }
capturedVar.getFieldInsns.forEach {
set(it, VarInsnNode(capturedVar.valueType.getOpcode(Opcodes.ILOAD), capturedVar.localVarIndex))
}
capturedVar.putFieldInsns.forEach {
set(it, VarInsnNode(capturedVar.valueType.getOpcode(Opcodes.ISTORE), capturedVar.localVarIndex))
}
}
}
}
}
internal const val REF_ELEMENT_FIELD = "element"
internal const val INIT_METHOD_NAME = "<init>"
internal val REF_TYPE_TO_ELEMENT_TYPE = HashMap<String, Type>().apply {
put(AsmTypes.OBJECT_REF_TYPE.internalName, AsmTypes.OBJECT_TYPE)
PrimitiveType.values().forEach {
put(AsmTypes.sharedTypeForPrimitive(it).internalName, AsmTypes.valueTypeForPrimitive(it))
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.captured
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
abstract class ReferenceTrackingInterpreter : OptimizationBasicInterpreter() {
override fun merge(v: BasicValue, w: BasicValue): BasicValue =
when {
v is ProperTrackedReferenceValue && w is ProperTrackedReferenceValue ->
if (v.descriptor == w.descriptor)
v
else
TaintedTrackedReferenceValue(
getTaintedValueType(v.type, w.type),
setOf(v.descriptor, w.descriptor)
)
v is TrackedReferenceValue || w is TrackedReferenceValue ->
TaintedTrackedReferenceValue(
getTaintedValueType(v.type, w.type),
v.referenceValueDescriptors + w.referenceValueDescriptors
)
else ->
super.merge(v, w)
}
private val BasicValue.referenceValueDescriptors: Set<ReferenceValueDescriptor>
get() = if (this is TrackedReferenceValue) this.descriptors else emptySet()
private fun getTaintedValueType(type1: Type?, type2: Type?): Type =
when {
type1 == null || type2 == null -> AsmTypes.OBJECT_TYPE
type1 == type2 -> type1
else -> AsmTypes.OBJECT_TYPE
}
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? =
if (value is TrackedReferenceValue) {
checkRefValuesUsages(insn, listOf(value))
value
}
else {
super.copyOperation(insn, value)
}
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? {
checkRefValuesUsages(insn, listOf(value))
return super.unaryOperation(insn, value)
}
override fun binaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue): BasicValue? {
checkRefValuesUsages(insn, listOf(value1, value2))
return super.binaryOperation(insn, value1, value2)
}
override fun ternaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue, value3: BasicValue): BasicValue? {
checkRefValuesUsages(insn, listOf(value1, value2, value3))
return super.ternaryOperation(insn, value1, value2, value3)
}
override fun naryOperation(insn: AbstractInsnNode, values: List<BasicValue>): BasicValue? {
checkRefValuesUsages(insn, values)
return super.naryOperation(insn, values)
}
protected open fun checkRefValuesUsages(insn: AbstractInsnNode, values: List<BasicValue>) {
values.forEach { value ->
if (value is TaintedTrackedReferenceValue) {
value.descriptors.forEach { it.onUseAsTainted() }
}
}
values.forEachIndexed { pos, value ->
if (value is TrackedReferenceValue) {
processRefValueUsage(value, insn, pos)
}
}
}
protected abstract fun processRefValueUsage(value: TrackedReferenceValue, insn: AbstractInsnNode, position: Int)
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.captured
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.org.objectweb.asm.Type
interface ReferenceValueDescriptor {
fun onUseAsTainted()
}
abstract class TrackedReferenceValue(type: Type): StrictBasicValue(type) {
abstract val descriptors: Set<ReferenceValueDescriptor>
}
class ProperTrackedReferenceValue(type: Type, val descriptor: ReferenceValueDescriptor) : TrackedReferenceValue(type) {
override val descriptors: Set<ReferenceValueDescriptor>
get() = setOf(descriptor)
override fun equals(other: Any?): Boolean =
other === this ||
other is ProperTrackedReferenceValue && other.descriptor == this.descriptor
override fun hashCode(): Int =
descriptor.hashCode()
override fun toString(): String =
"[$descriptor]"
}
class TaintedTrackedReferenceValue(type: Type, override val descriptors: Set<ReferenceValueDescriptor>) : TrackedReferenceValue(type) {
override fun equals(other: Any?): Boolean =
other === this ||
other is TaintedTrackedReferenceValue && other.descriptors == this.descriptors
override fun hashCode(): Int =
descriptors.hashCode()
override fun toString(): String =
"!$descriptors"
}

View File

@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.optimization.common;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.AsmUtil;
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
import org.jetbrains.org.objectweb.asm.Handle;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
@@ -136,7 +137,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
case NEW:
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
default:
throw new Error("Internal error.");
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
}
}
@@ -221,7 +222,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
case PUTFIELD:
return null;
default:
throw new Error("Internal error.");
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
}
}
@@ -340,7 +341,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
case IFNONNULL:
return null;
default:
throw new Error("Internal error.");
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
}
}

View File

@@ -52,7 +52,7 @@ open class StrictBasicValue(type: Type?) : BasicValue(type) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
if (other == null || other::class.java != this::class.java) return false
if (!super.equals(other)) return false
other as StrictBasicValue

View File

@@ -17,8 +17,10 @@
package org.jetbrains.kotlin.codegen.optimization.common
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
val AbstractInsnNode.isMeaningful: Boolean get() =
@@ -50,9 +52,7 @@ fun MethodNode.prepareForEmitting() {
// local variables with live ranges starting after last meaningful instruction lead to VerifyError
localVariables = localVariables.filter { lv ->
InsnSequence(lv.start, lv.end).any { insn ->
insn.isMeaningful
}
InsnSequence(lv.start, lv.end).any(AbstractInsnNode::isMeaningful)
}
// We should remove linenumbers after last meaningful instruction
@@ -71,10 +71,64 @@ fun MethodNode.prepareForEmitting() {
fun MethodNode.removeEmptyCatchBlocks() {
tryCatchBlocks = tryCatchBlocks.filter { tcb ->
InsnSequence(tcb.start, tcb.end).any { insn ->
insn.isMeaningful
InsnSequence(tcb.start, tcb.end).any(AbstractInsnNode::isMeaningful)
}
}
fun MethodNode.removeUnusedLocalVariables() {
val used = BooleanArray(maxLocals) { false }
for (insn in instructions) {
when (insn) {
is VarInsnNode -> {
val varIndex = insn.`var`
used[varIndex] = true
if (insn.isSize2LoadStoreOperation()) {
used[varIndex + 1] = true
}
}
is IincInsnNode ->
used[insn.`var`] = true
}
}
for (localVar in localVariables) {
val varIndex = localVar.index
used[varIndex] = true
val type = Type.getType(localVar.desc)
if (type.size == 2) {
used[varIndex + 1] = true
}
}
if (used.all { it }) return
val remapping = IntArray(maxLocals) { 0 }
var lastUnused = 0
for (i in remapping.indices) {
remapping[i] = lastUnused
if (used[i]) {
lastUnused++
}
}
remapLocalVariables(remapping)
}
private fun VarInsnNode.isSize2LoadStoreOperation() =
opcode == LLOAD || opcode == DLOAD || opcode == LSTORE || opcode == DSTORE
fun MethodNode.remapLocalVariables(remapping: IntArray) {
for (insn in instructions.toArray()) {
when (insn) {
is VarInsnNode ->
insn.`var` = remapping[insn.`var`]
is IincInsnNode ->
insn.`var` = remapping[insn.`var`]
}
}
for (localVariableNode in localVariables) {
localVariableNode.index = remapping[localVariableNode.index]
}
}
inline fun AbstractInsnNode.findNextOrNull(predicate: (AbstractInsnNode) -> Boolean): AbstractInsnNode? {
@@ -119,9 +173,16 @@ val AbstractInsnNode.intConstant: Int? get() =
fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEach { add(it) } }
fun AbstractInsnNode.isStoreOperation(): Boolean = getOpcode() in Opcodes.ISTORE..Opcodes.ASTORE
fun AbstractInsnNode.isLoadOperation(): Boolean = getOpcode() in Opcodes.ILOAD..Opcodes.ALOAD
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
val AbstractInsnNode?.insnText get() = InlineCodegenUtil.getInsnText(this)
val AbstractInsnNode?.debugText get() =
if (this == null) "<null>" else "${this.javaClass.simpleName}: $insnText"
if (this == null) "<null>" else "${this::class.java.simpleName}: $insnText"
internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.isInsn(opcode: Int, condition: T.() -> Boolean): Boolean =
takeInsnIf(opcode, condition) != null
internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.takeInsnIf(opcode: Int, condition: T.() -> Boolean): T? =
takeIf { it.opcode == opcode }?.safeAs<T>()?.takeIf { it.condition() }

View File

@@ -58,16 +58,9 @@ internal class FixStackAnalyzer(
for (marker in context.fakeAlwaysFalseIfeqMarkers) {
val next = marker.next
if (next is JumpInsnNode) {
val nop = InsnNode(Opcodes.NOP)
expectedStackNode[next.label] = nop
method.instructions.insert(next, nop)
method.instructions.remove(marker)
method.instructions.remove(next)
context.nodesToRemoveOnCleanup.add(nop)
expectedStackNode[next.label] = marker
}
}
context.fakeAlwaysFalseIfeqMarkers.clear()
}
private val analyzer = InternalAnalyzer(owner, method, context)

View File

@@ -39,8 +39,6 @@ internal class FixStackContext(val methodNode: MethodNode) {
val openingInlineMethodMarker = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
var consistentInlineMarkers: Boolean = true; private set
val nodesToRemoveOnCleanup = arrayListOf<AbstractInsnNode>()
init {
saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode)
isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty()

View File

@@ -39,31 +39,51 @@ class FixStackMethodTransformer : MethodTransformer() {
}
if (context.isAnalysisRequired()) {
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
analyzer.analyze()
methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize
val actions = arrayListOf<() -> Unit>()
transformBreakContinueGotos(methodNode, context, actions, analyzer)
transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer)
actions.forEach { it() }
analyzeAndTransformBreakContinueGotos(context, internalClassName, methodNode)
removeAlwaysFalseIfeqMarkers(context, methodNode)
analyzeAndTransformSaveRestoreStack(context, internalClassName, methodNode)
}
context.fakeAlwaysTrueIfeqMarkers.forEach { marker ->
replaceAlwaysTrueIfeqWithGoto(methodNode, marker)
}
removeAlwaysTrueIfeqMarkers(context, methodNode)
removeAlwaysFalseIfeqMarkers(context, methodNode)
}
private fun analyzeAndTransformBreakContinueGotos(context: FixStackContext, internalClassName: String, methodNode: MethodNode) {
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
analyzer.analyze()
methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize
val actions = arrayListOf<() -> Unit>()
transformBreakContinueGotos(methodNode, context, actions, analyzer)
actions.forEach { it() }
}
private fun analyzeAndTransformSaveRestoreStack(context: FixStackContext, internalClassName: String, methodNode: MethodNode) {
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
analyzer.analyze()
val actions = arrayListOf<() -> Unit>()
transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer)
actions.forEach { it() }
}
private fun removeAlwaysFalseIfeqMarkers(context: FixStackContext, methodNode: MethodNode) {
context.fakeAlwaysFalseIfeqMarkers.forEach { marker ->
removeAlwaysFalseIfeq(methodNode, marker)
}
context.fakeAlwaysFalseIfeqMarkers.clear()
}
context.nodesToRemoveOnCleanup.forEach {
methodNode.instructions.remove(it)
private fun removeAlwaysTrueIfeqMarkers(context: FixStackContext, methodNode: MethodNode) {
context.fakeAlwaysTrueIfeqMarkers.forEach { marker ->
replaceAlwaysTrueIfeqWithGoto(methodNode, marker)
}
context.fakeAlwaysTrueIfeqMarkers.clear()
}
private fun transformBreakContinueGotos(

View File

@@ -26,7 +26,7 @@ fun <V : Value> Frame<V>.top(): V? =
peek(0)
fun <V : Value> Frame<V>.peek(offset: Int): V? =
if (stackSize >= offset) getStack(stackSize - offset - 1) else null
if (stackSize > offset) getStack(stackSize - offset - 1) else null
class SavedStackDescriptor(
val savedValues: List<BasicValue>,

View File

@@ -0,0 +1,106 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.nullCheck
import org.jetbrains.kotlin.codegen.optimization.boxing.*
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
class NullabilityInterpreter : OptimizationBasicInterpreter() {
override fun newOperation(insn: AbstractInsnNode): BasicValue? {
val defaultResult = super.newOperation(insn)
val resultType = defaultResult?.type
return when {
insn.opcode == Opcodes.ACONST_NULL ->
NullBasicValue
insn.opcode == Opcodes.NEW ->
NotNullBasicValue(resultType)
insn.opcode == Opcodes.LDC && resultType.isReferenceType() ->
NotNullBasicValue(resultType)
insn.isUnitInstance() ->
NotNullBasicValue(resultType)
else ->
defaultResult
}
}
private fun Type?.isReferenceType() =
this?.sort.let { it == Type.OBJECT || it == Type.ARRAY }
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
val defaultResult = super.unaryOperation(insn, value)
val resultType = defaultResult?.type
return when {
insn.opcode == Opcodes.CHECKCAST ->
value
insn.opcode == Opcodes.NEWARRAY || insn.opcode == Opcodes.ANEWARRAY ->
NotNullBasicValue(resultType)
else ->
defaultResult
}
}
override fun naryOperation(insn: AbstractInsnNode, values: List<BasicValue>): BasicValue? {
val defaultResult = super.naryOperation(insn, values)
val resultType = defaultResult?.type
return when {
insn.isBoxing() ->
NotNullBasicValue(resultType)
insn.isIteratorMethodCallOfProgression(values) ->
ProgressionIteratorBasicValue.byProgressionClassType(values[0].type)
insn.isNextMethodCallOfProgressionIterator(values) ->
NotNullBasicValue(resultType)
else ->
defaultResult
}
}
override fun merge(v: BasicValue, w: BasicValue): BasicValue =
when {
v is NullBasicValue && w is NullBasicValue ->
NullBasicValue
v is NullBasicValue || w is NullBasicValue ->
StrictBasicValue.REFERENCE_VALUE
v is ProgressionIteratorBasicValue && w is ProgressionIteratorBasicValue ->
mergeNotNullValuesOfSameKind(v, w)
v is ProgressionIteratorBasicValue && w is NotNullBasicValue ->
NotNullBasicValue.NOT_NULL_REFERENCE_VALUE
w is ProgressionIteratorBasicValue && v is NotNullBasicValue ->
NotNullBasicValue.NOT_NULL_REFERENCE_VALUE
v is NotNullBasicValue && w is NotNullBasicValue ->
mergeNotNullValuesOfSameKind(v, w)
else ->
super.merge(v, w)
}
private fun mergeNotNullValuesOfSameKind(v: StrictBasicValue, w: StrictBasicValue) =
if (v.type == w.type) v else NotNullBasicValue.NOT_NULL_REFERENCE_VALUE
}
fun TypeInsnNode.getObjectType(): Type =
Type.getObjectType(desc)

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.nullCheck
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.boxing.ProgressionIteratorBasicValue
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.InsnNode
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
class RedundantNullCheckMethodTransformer : MethodTransformer() {
private val deadCodeElimination = DeadCodeEliminationMethodTransformer()
override fun transform(internalClassName: String, methodNode: MethodNode) {
while (runSingleNullCheckEliminationPass(internalClassName, methodNode)) {
deadCodeElimination.transform(internalClassName, methodNode)
}
}
private fun isAlwaysFalse(opcode: Int, nullability: Nullability) =
(opcode == Opcodes.IFNULL && nullability == Nullability.NOT_NULL) ||
(opcode == Opcodes.IFNONNULL && nullability == Nullability.NULL)
private fun isAlwaysTrue(opcode: Int, nullability: Nullability) =
(opcode == Opcodes.IFNULL && nullability == Nullability.NULL) ||
(opcode == Opcodes.IFNONNULL && nullability == Nullability.NOT_NULL)
private fun runSingleNullCheckEliminationPass(internalClassName: String, methodNode: MethodNode): Boolean {
val insnList = methodNode.instructions
val instructions = insnList.toArray()
val nullCheckIfs = instructions.mapNotNullTo(SmartList<JumpInsnNode>()) {
it.safeAs<JumpInsnNode>()?.takeIf {
it.opcode == Opcodes.IFNULL ||
it.opcode == Opcodes.IFNONNULL
}
}
if (nullCheckIfs.isEmpty()) return false
val frames = analyze(internalClassName, methodNode, NullabilityInterpreter())
val redundantNullCheckIfs = nullCheckIfs.mapNotNull { insn ->
frames[instructions.indexOf(insn)]?.top()?.let { top ->
val nullability = top.getNullability()
if (nullability == Nullability.NULLABLE)
null
else
Pair(insn, nullability)
}
}
if (redundantNullCheckIfs.isEmpty()) return false
for ((insn, nullability) in redundantNullCheckIfs) {
val previous = insn.previous
when (previous?.opcode) {
Opcodes.ALOAD, Opcodes.DUP ->
insnList.remove(previous)
else ->
insnList.insert(previous, InsnNode(Opcodes.POP))
}
when {
isAlwaysTrue(insn.opcode, nullability) ->
insnList.set(insn, JumpInsnNode(Opcodes.GOTO, insn.label))
isAlwaysFalse(insn.opcode, nullability) ->
insnList.remove(insn)
}
}
return true
}
}

View File

@@ -0,0 +1,367 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.nullCheck
import org.jetbrains.kotlin.codegen.coroutines.withInstructionAdapter
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.isInsn
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.*
class RedundantNullCheckV2MethodTransformer : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) {
while (TransformerPass(internalClassName, methodNode).run()) {}
}
private class TransformerPass(val internalClassName: String, val methodNode: MethodNode) {
private var changes = false
private fun AbstractInsnNode.getIndex() =
methodNode.instructions.indexOf(this)
fun run(): Boolean {
val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode()
eliminateRedundantChecks(checkedReferenceTypes)
return changes
}
private fun analyzeTypesAndRemoveDeadCode(): Map<AbstractInsnNode, Type> {
val insns = methodNode.instructions.toArray()
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
val checkedReferenceTypes = HashMap<AbstractInsnNode, Type>()
for (i in insns.indices) {
val insn = insns[i]
val frame = frames[i]
if (insn.isInstanceOfOrNullCheck()) {
checkedReferenceTypes[insn] = frame?.top()?.type ?: continue
}
else if (insn.isCheckParameterNotNull()) {
checkedReferenceTypes[insn] = frame?.peek(1)?.type ?: continue
}
}
val dceResult = DeadCodeEliminationMethodTransformer().removeDeadCodeByFrames(methodNode, frames)
if (dceResult.hasRemovedAnything()) {
changes = true
}
return checkedReferenceTypes
}
private fun eliminateRedundantChecks(checkedReferenceTypes: Map<AbstractInsnNode, Type>) {
val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes)
val nullabilityMap = analyzeNullabilities()
nullabilityAssumptions.revert()
transformTrivialChecks(nullabilityMap)
}
private fun injectNullabilityAssumptions(checkedReferenceTypes: Map<AbstractInsnNode, Type>) =
NullabilityAssumptionsBuilder(checkedReferenceTypes).injectNullabilityAssumptions()
private fun analyzeNullabilities(): Map<AbstractInsnNode, Nullability> {
val frames = analyze(internalClassName, methodNode, NullabilityInterpreter())
val insns = methodNode.instructions.toArray()
val nullabilityMap = HashMap<AbstractInsnNode, Nullability>()
for (i in insns.indices) {
val nullability = frames[i]?.top()?.getNullability() ?: continue
if (nullability == Nullability.NULLABLE) continue
val insn = insns[i]
if (insn.isInstanceOfOrNullCheck()) {
nullabilityMap[insn] = nullability
}
}
return nullabilityMap
}
private fun transformTrivialChecks(nullabilityMap: Map<AbstractInsnNode, Nullability>) {
for ((insn, nullability) in nullabilityMap) {
when (insn.opcode) {
Opcodes.IFNULL -> transformTrivialNullJump(insn as JumpInsnNode, nullability == Nullability.NULL)
Opcodes.IFNONNULL -> transformTrivialNullJump(insn as JumpInsnNode, nullability == Nullability.NOT_NULL)
Opcodes.INSTANCEOF -> transformInstanceOf(insn, nullability)
}
}
}
private fun transformTrivialNullJump(insn: JumpInsnNode, alwaysTrue: Boolean) {
changes = true
methodNode.instructions.run {
popReferenceValueBefore(insn)
if (alwaysTrue) {
set(insn, JumpInsnNode(Opcodes.GOTO, insn.label))
}
else {
remove(insn)
}
}
}
private fun transformInstanceOf(insn: AbstractInsnNode, nullability: Nullability) {
if (nullability != Nullability.NULL) return
if (ReifiedTypeInliner.isOperationReifiedMarker(insn.previous)) return
changes = true
val nextOpcode = insn.next?.opcode
if (nextOpcode == Opcodes.IFEQ || nextOpcode == Opcodes.IFNE)
transformNullInstanceOfWithJump(insn)
else
transformNullInstanceOf(insn)
}
private fun transformNullInstanceOf(insn: AbstractInsnNode) {
methodNode.instructions.run {
popReferenceValueBefore(insn)
set(insn, InsnNode(Opcodes.ICONST_0))
}
}
private fun transformNullInstanceOfWithJump(insn: AbstractInsnNode) {
methodNode.instructions.run {
popReferenceValueBefore(insn)
val jump = insn.next.assertedCast<JumpInsnNode> { "JumpInsnNode expected" }
remove(insn)
if (jump.opcode == Opcodes.IFEQ) {
set(jump, JumpInsnNode(Opcodes.GOTO, jump.label))
}
else {
remove(jump)
}
}
}
private inner class NullabilityAssumptionsBuilder(val checkedReferenceTypes: Map<AbstractInsnNode, Type>) {
private val checksDependingOnVariable = HashMap<Int, MutableList<AbstractInsnNode>>()
fun injectNullabilityAssumptions(): NullabilityAssumptions {
collectVariableDependentChecks()
return injectAssumptions()
}
private fun collectVariableDependentChecks() {
for (insn in methodNode.instructions) {
if (insn.isInstanceOfOrNullCheck()) {
val previous = insn.previous ?: continue
if (previous.opcode == Opcodes.ALOAD) {
addDependentCheck(insn, previous as VarInsnNode)
}
else if (previous.opcode == Opcodes.DUP) {
val previous2 = previous.previous ?: continue
if (previous2.opcode == Opcodes.ALOAD) {
addDependentCheck(insn, previous2 as VarInsnNode)
}
}
}
else if (insn.isCheckParameterNotNull()) {
val ldcInsn = insn.previous ?: continue
if (ldcInsn.opcode != Opcodes.LDC) continue
val aLoadInsn = ldcInsn.previous ?: continue
if (aLoadInsn.opcode != Opcodes.ALOAD) continue
addDependentCheck(insn, aLoadInsn as VarInsnNode)
}
}
}
private fun addDependentCheck(insn: AbstractInsnNode, aLoadInsn: VarInsnNode) {
checksDependingOnVariable.getOrPut(aLoadInsn.`var`) {
SmartList<AbstractInsnNode>()
}.add(insn)
}
private fun injectAssumptions(): NullabilityAssumptions {
val nullabilityAssumptions = NullabilityAssumptions()
for ((varIndex, dependentChecks) in checksDependingOnVariable) {
for (checkInsn in dependentChecks) {
val varType = checkedReferenceTypes[checkInsn]
?: throw AssertionError("No var type @${checkInsn.getIndex()}")
nullabilityAssumptions.injectAssumptionsForCheck(varIndex, checkInsn, varType)
}
}
return nullabilityAssumptions
}
private fun NullabilityAssumptions.injectAssumptionsForCheck(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
when (insn.opcode) {
Opcodes.IFNULL,
Opcodes.IFNONNULL ->
injectAssumptionsForNullCheck(varIndex, insn as JumpInsnNode, varType)
Opcodes.INVOKESTATIC -> {
assert(insn.isCheckParameterNotNull()) { "Expected non-null parameter check @${insn.getIndex()}"}
injectAssumptionsForParameterNotNullCheck(varIndex, insn, varType)
}
Opcodes.INSTANCEOF ->
injectAssumptionsForInstanceOfCheck(varIndex, insn, varType)
}
}
private fun NullabilityAssumptions.injectAssumptionsForNullCheck(varIndex: Int, insn: JumpInsnNode, varType: Type) {
// ALOAD v
// IFNULL L
// <...> -- v is not null here
// L:
// <...> -- v is null here
val jumpsIfNull = insn.opcode == Opcodes.IFNULL
val originalLabel = insn.label
originalLabels[insn] = originalLabel
insn.label = synthetic(LabelNode(Label()))
val insertAfterNull = if (jumpsIfNull) insn.label else insn
val insertAfterNonNull = if (jumpsIfNull) insn else insn.label
methodNode.instructions.run {
add(insn.label)
insert(insertAfterNull, listOfSynthetics {
aconst(null)
store(varIndex, varType)
if (jumpsIfNull) {
goTo(originalLabel.label)
}
})
insert(insertAfterNonNull, listOfSynthetics {
anew(varType)
store(varIndex, varType)
if (!jumpsIfNull) {
goTo(originalLabel.label)
}
})
}
}
private fun NullabilityAssumptions.injectAssumptionsForParameterNotNullCheck(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
// ALOAD v
// LDC param_name
// INVOKESTATIC checkParameterIsNotNull
// <...> -- v is not null here (otherwise an exception was thrown)
methodNode.instructions.insert(insn, listOfSynthetics {
anew(varType)
store(varIndex, varType)
})
}
private fun NullabilityAssumptions.injectAssumptionsForInstanceOfCheck(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
// ALOAD v
// INSTANCEOF T
// IFEQ L
// <...> -- v is not null here (because it is an instance of T)
// L:
// <...> -- v is something else here (maybe null)
val next = insn.next ?: return
if (next.opcode != Opcodes.IFEQ && next.opcode != Opcodes.IFNE) return
if (next !is JumpInsnNode) return
val jumpsIfInstance = next.opcode == Opcodes.IFNE
val originalLabel: LabelNode?
val insertAfterNotNull: AbstractInsnNode
if (jumpsIfInstance) {
originalLabel = next.label
originalLabels[next] = next.label
val newLabel = synthetic(LabelNode(Label()))
methodNode.instructions.add(newLabel)
next.label = newLabel
insertAfterNotNull = newLabel
}
else {
originalLabel = null
insertAfterNotNull = next
}
methodNode.instructions.run {
insert(insertAfterNotNull, listOfSynthetics {
anew(varType)
store(varIndex, varType)
if (originalLabel != null) {
goTo(originalLabel.label)
}
})
}
}
}
inner class NullabilityAssumptions {
val originalLabels = HashMap<JumpInsnNode, LabelNode>()
val syntheticInstructions = ArrayList<AbstractInsnNode>()
fun <T : AbstractInsnNode> synthetic(insn: T): T {
syntheticInstructions.add(insn)
return insn
}
inline fun listOfSynthetics(block: InstructionAdapter.() -> Unit): InsnList {
val insnList = withInstructionAdapter(block)
for (insn in insnList) {
synthetic(insn)
}
return insnList
}
fun revert() {
methodNode.instructions.run {
syntheticInstructions.forEach { remove(it) }
}
for ((jumpInsn, originalLabel) in originalLabels) {
jumpInsn.label = originalLabel
}
}
}
}
}
internal fun AbstractInsnNode.isInstanceOfOrNullCheck() =
opcode == Opcodes.INSTANCEOF || opcode == Opcodes.IFNULL || opcode == Opcodes.IFNONNULL
internal fun AbstractInsnNode.isCheckParameterNotNull() =
isInsn<MethodInsnNode>(Opcodes.INVOKESTATIC) {
owner == "kotlin/jvm/internal/Intrinsics" &&
name == "checkParameterIsNotNull" &&
desc == "(Ljava/lang/Object;Ljava/lang/String;)V"
}
internal fun InsnList.popReferenceValueBefore(insn: AbstractInsnNode) {
val prev = insn.previous
when (prev?.opcode) {
Opcodes.ACONST_NULL,
Opcodes.DUP,
Opcodes.ALOAD ->
remove(prev)
else ->
insertBefore(insn, InsnNode(Opcodes.POP))
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.optimization.nullCheck
import org.jetbrains.kotlin.codegen.optimization.boxing.ProgressionIteratorBasicValue
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
class NotNullBasicValue(type: Type?) : StrictBasicValue(type) {
override fun equals(other: Any?): Boolean = other is NotNullBasicValue
// We do not differ not-nullable values, so we should always return the same hashCode
// Actually it doesn't really matter because analyzer is not supposed to store values in hashtables
override fun hashCode() = 0
companion object {
val NOT_NULL_REFERENCE_VALUE = NotNullBasicValue(StrictBasicValue.REFERENCE_VALUE.type)
}
}
object NullBasicValue : StrictBasicValue(AsmTypes.OBJECT_TYPE)
enum class Nullability {
NULL, NOT_NULL, NULLABLE;
fun isNull() = this == NULL
fun isNotNull() = this == NOT_NULL
}
fun BasicValue.getNullability(): Nullability =
when (this) {
is NullBasicValue -> Nullability.NULL
is NotNullBasicValue -> Nullability.NOT_NULL
is ProgressionIteratorBasicValue -> Nullability.NOT_NULL
else -> Nullability.NULLABLE
}

View File

@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.load.java.lazy.types.RawTypeImpl;
import org.jetbrains.kotlin.load.kotlin.JavaFlexibleTypeDeserializer;
import org.jetbrains.kotlin.load.kotlin.TypeSignatureMappingKt;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.serialization.AnnotationSerializer;
import org.jetbrains.kotlin.serialization.ProtoBuf;
import org.jetbrains.kotlin.serialization.SerializerExtension;
@@ -77,7 +78,7 @@ public class JvmSerializerExtension extends SerializerExtension {
}
@Override
public void serializePackage(@NotNull ProtoBuf.Package.Builder proto) {
public void serializePackage(@NotNull FqName packageFqName, @NotNull ProtoBuf.Package.Builder proto) {
if (!moduleName.equals(JvmAbi.DEFAULT_MODULE_NAME)) {
proto.setExtension(JvmProtoBuf.packageModuleName, stringTable.getStringIndex(moduleName));
}

View File

@@ -44,7 +44,7 @@ class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
val lastRecord = records.lastOrNull()
if (lastRecord != null && lastRecord.isTrivial()) {
lastRecord.setRange(lastRecord.range + 1)
lastRecord.range = lastRecord.range + 1
}
else records.add(Record.newBuilder())
}
@@ -93,12 +93,12 @@ class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
else {
val predefinedIndex = JvmNameResolver.getPredefinedStringIndex(string)
if (predefinedIndex != null) {
record.setPredefinedIndex(predefinedIndex)
record.predefinedIndex = predefinedIndex
// TODO: move all records with predefined names to the end and do not write associated strings for them (since they are ignored)
strings.add("")
}
else {
record.setOperation(Record.Operation.DESC_TO_CLASS_ID)
record.operation = Record.Operation.DESC_TO_CLASS_ID
strings.add("L${string.replace('.', '$')};")
}
}

View File

@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
import org.jetbrains.org.objectweb.asm.Opcodes
import java.io.File
class GenerationState @JvmOverloads constructor(
@@ -70,8 +69,9 @@ class GenerationState @JvmOverloads constructor(
abstract class GenerateClassFilter {
abstract fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean
abstract fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean
abstract fun shouldGeneratePackagePart(jetFile: KtFile): Boolean
abstract fun shouldGeneratePackagePart(ktFile: KtFile): Boolean
abstract fun shouldGenerateScript(script: KtScript): Boolean
open fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject)
companion object {
@JvmField val GENERATE_ALL: GenerateClassFilter = object : GenerateClassFilter() {
@@ -81,7 +81,7 @@ class GenerationState @JvmOverloads constructor(
override fun shouldGenerateScript(script: KtScript): Boolean = true
override fun shouldGeneratePackagePart(jetFile: KtFile): Boolean = true
override fun shouldGeneratePackagePart(ktFile: KtFile): Boolean = true
}
}
}
@@ -92,7 +92,8 @@ class GenerationState @JvmOverloads constructor(
val incrementalCacheForThisTarget: IncrementalCache?
val packagesWithObsoleteParts: Set<FqName>
val obsoleteMultifileClasses: List<FqName>
val deserializationConfiguration: DeserializationConfiguration = CompilerDeserializationConfiguration(configuration)
val deserializationConfiguration: DeserializationConfiguration =
CompilerDeserializationConfiguration(configuration.languageVersionSettings)
init {
val icComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
@@ -113,7 +114,7 @@ class GenerationState @JvmOverloads constructor(
}
}
val extraJvmDiagnosticsTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "For extra diagnostics in ${this.javaClass}", false)
val extraJvmDiagnosticsTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "For extra diagnostics in ${this::class.java}", false)
private val interceptedBuilderFactory: ClassBuilderFactory
private var used = false
@@ -123,7 +124,8 @@ class GenerationState @JvmOverloads constructor(
extraJvmDiagnosticsTrace.bindingContext.diagnostics
}
val isJvm8Target: Boolean = configuration.get(JVMConfigurationKeys.JVM_TARGET) == JvmTarget.JVM_1_8
val target = configuration.get(JVMConfigurationKeys.JVM_TARGET) ?: JvmTarget.DEFAULT
val isJvm8Target: Boolean = target == JvmTarget.JVM_1_8
val isJvm8TargetWithDefaults: Boolean = isJvm8Target && configuration.getBoolean(JVMConfigurationKeys.JVM8_TARGET_WITH_DEFAULTS)
val generateDefaultImplsForJvm8: Boolean = configuration.getBoolean(JVMConfigurationKeys.INTERFACE_COMPATIBILITY)
@@ -162,7 +164,7 @@ class GenerationState @JvmOverloads constructor(
val rootContext: CodegenContext<*> = RootContext(this)
val classFileVersion: Int = if (isJvm8Target) Opcodes.V1_8 else Opcodes.V1_6
val classFileVersion: Int = target.bytecodeVersion
val generateParametersMetadata: Boolean = configuration.getBoolean(JVMConfigurationKeys.PARAMETERS_METADATA)

View File

@@ -192,6 +192,10 @@ public class KotlinTypeMapper {
return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
}
if (descriptor instanceof ConstructorDescriptor) {
return mapClass(((ConstructorDescriptor) descriptor).getConstructedClass());
}
DeclarationDescriptor container = descriptor.getContainingDeclaration();
if (container instanceof PackageFragmentDescriptor) {
String packageMemberOwner = internalNameForPackageMemberOwner((CallableMemberDescriptor) descriptor, publicFacade);
@@ -702,15 +706,14 @@ public class KotlinTypeMapper {
@NotNull
public CallableMethod mapToCallableMethod(@NotNull FunctionDescriptor descriptor, boolean superCall) {
if (descriptor instanceof TypeAliasConstructorDescriptor) {
return mapToCallableMethod(((TypeAliasConstructorDescriptor) descriptor).getUnderlyingConstructorDescriptor(), superCall);
}
if (descriptor instanceof ClassConstructorDescriptor) {
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor);
Type owner = mapClass(((ClassConstructorDescriptor) descriptor).getContainingDeclaration());
String defaultImplDesc = mapDefaultMethod(descriptor, OwnerKind.IMPLEMENTATION).getDescriptor();
return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null, false);
if (descriptor instanceof ConstructorDescriptor) {
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor.getOriginal());
Type owner = mapOwner(descriptor);
String defaultImplDesc = mapDefaultMethod(descriptor.getOriginal(), OwnerKind.IMPLEMENTATION).getDescriptor();
return new CallableMethod(
owner, owner, defaultImplDesc, method, INVOKESPECIAL,
null, null, null, false
);
}
if (descriptor instanceof LocalVariableAccessorDescriptor) {
@@ -958,7 +961,7 @@ public class KotlinTypeMapper {
if (!(descriptor instanceof ConstructorDescriptor) &&
descriptor.getVisibility() == Visibilities.INTERNAL &&
!descriptor.getAnnotations().hasAnnotation(KotlinBuiltIns.FQ_NAMES.publishedApi)) {
!DescriptorUtilsKt.isPublishedApi(descriptor)) {
return name + "$" + NameUtils.sanitizeAsJavaIdentifier(moduleName);
}
@@ -1027,31 +1030,28 @@ public class KotlinTypeMapper {
}
}
if (f instanceof TypeAliasConstructorDescriptor) {
return mapSignature(((TypeAliasConstructorDescriptor) f).getUnderlyingConstructorDescriptor(), kind, skipGenericSignature);
}
if (f instanceof FunctionImportedFromObject) {
return mapSignature(((FunctionImportedFromObject) f).getCallableFromObject(), kind, skipGenericSignature);
}
if (CoroutineCodegenUtilKt.isSuspendFunctionNotSuspensionView(f)) {
return mapSignature(CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(f), kind, skipGenericSignature);
}
if (f instanceof ConstructorDescriptor) {
return mapSignature(f, kind, f.getOriginal().getValueParameters(), skipGenericSignature);
}
return mapSignature(f, kind, f.getValueParameters(), skipGenericSignature);
return mapSignatureWithCustomParameters(f, kind, f.getValueParameters(), skipGenericSignature);
}
@NotNull
public JvmMethodGenericSignature mapSignature(
public JvmMethodGenericSignature mapSignatureWithCustomParameters(
@NotNull FunctionDescriptor f,
@NotNull OwnerKind kind,
@NotNull List<ValueParameterDescriptor> valueParameters,
boolean skipGenericSignature
) {
if (f instanceof FunctionImportedFromObject) {
return mapSignature(((FunctionImportedFromObject) f).getCallableFromObject(), kind, skipGenericSignature);
}
else if (f instanceof TypeAliasConstructorDescriptor) {
return mapSignature(((TypeAliasConstructorDescriptor) f).getUnderlyingConstructorDescriptor(), kind, valueParameters, skipGenericSignature);
}
checkOwnerCompatibility(f);
JvmSignatureWriter sw = skipGenericSignature || f instanceof AccessorForCallableDescriptor
@@ -1422,7 +1422,7 @@ public class KotlinTypeMapper {
List<ResolvedValueArgument> valueArguments = superCall.getValueArgumentsByIndex();
assert valueArguments != null : "Failed to arrange value arguments by index: " + superDescriptor;
List<JvmMethodParameterSignature> parameters = mapSignatureSkipGeneric(superDescriptor).getValueParameters();
List<JvmMethodParameterSignature> parameters = mapSignatureSkipGeneric(superDescriptor.getOriginal()).getValueParameters();
int params = parameters.size();
int args = valueArguments.size();
@@ -1504,4 +1504,13 @@ public class KotlinTypeMapper {
return null;
}
@NotNull
public String classInternalName(@NotNull ClassDescriptor classDescriptor) {
Type recordedType = typeMappingConfiguration.getPredefinedTypeForClass(classDescriptor);
if (recordedType != null) {
return recordedType.getInternalName();
}
return TypeSignatureMappingKt.computeInternalName(classDescriptor, typeMappingConfiguration);
}
}

View File

@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.serialization.builtins.BuiltInsSerializerExtension
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment.Companion.DOT_METADATA_FILE_EXTENSION
import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable
@@ -142,11 +141,11 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
protected inner class PackageSerializer(
private val classes: Collection<DeclarationDescriptor>,
private val members: Collection<DeclarationDescriptor>,
packageFqName: FqName,
private val packageFqName: FqName,
private val destFile: File
) {
private val proto = BuiltInsProtoBuf.BuiltIns.newBuilder()
private val extension = BuiltInsSerializerExtension(packageFqName)
private val proto = ProtoBuf.PackageFragment.newBuilder()
private val extension = BuiltInsSerializerExtension()
fun run() {
serializeClasses(classes)
@@ -171,7 +170,7 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
}
private fun serializeMembers(members: Collection<DeclarationDescriptor>) {
proto.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(members).build()
proto.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(packageFqName, members).build()
}
private fun serializeStringTable() {

View File

@@ -17,16 +17,8 @@
package org.jetbrains.kotlin.serialization.builtins
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
import org.jetbrains.kotlin.serialization.ProtoBuf
class BuiltInsSerializerExtension(
private val packageFqName: FqName
) : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
class BuiltInsSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
override fun shouldUseTypeTable(): Boolean = true
override fun serializePackage(proto: ProtoBuf.Package.Builder) {
proto.setExtension(BuiltInsProtoBuf.packageFqName, stringTable.getPackageFqNameIndex(packageFqName))
}
}

View File

@@ -37,10 +37,10 @@ found top-level declarations to <destination dir> (*.kotlin_builtins files)"""
val destDir = File(args[0])
val srcDirs = args.drop(1).map { File(it) }
val srcDirs = args.drop(1).map(::File)
assert(srcDirs.isNotEmpty()) { "At least one source directory should be specified" }
val missing = srcDirs.filterNot { it.exists() }
val missing = srcDirs.filterNot(File::exists)
assert(missing.isEmpty()) { "These source directories are missing: $missing" }
try {

View File

@@ -9,8 +9,7 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="util" />
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
<orderEntry type="library" exported="" name="cli-parser" level="project" />
<orderEntry type="library" name="jps" level="project" />
<orderEntry type="module" module-name="descriptor.loader.java" />
<orderEntry type="module" module-name="frontend.java" />
</component>
</module>

View File

@@ -17,8 +17,8 @@
package org.jetbrains.kotlin.cli.common.arguments;
import com.intellij.util.SmartList;
import com.sampullara.cli.Argument;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
import java.io.Serializable;
import java.util.List;
@@ -79,6 +79,9 @@ public abstract class CommonCompilerArguments implements Serializable {
@Argument(value = "Xno-check-impl", description = "Do not check presence of 'impl' modifier in multi-platform projects")
public boolean noCheckImpl;
@Argument(value = "Xskip-java-check", description = "Do not warn when running the compiler under Java 6 or 7")
public boolean noJavaVersionWarning;
@Argument(value = "Xcoroutines=warn")
public boolean coroutinesWarn;
@@ -96,6 +99,15 @@ public abstract class CommonCompilerArguments implements Serializable {
public List<String> unknownExtraFlags = new SmartList<String>();
@NotNull
public static CommonCompilerArguments createDefaultInstance() {
DummyImpl arguments = new DummyImpl();
arguments.coroutinesEnable = false;
arguments.coroutinesWarn = true;
arguments.coroutinesError = false;
return arguments;
}
@NotNull
public String executableScriptFileName() {
return "kotlinc";

View File

@@ -16,9 +16,9 @@
package org.jetbrains.kotlin.cli.common.arguments;
import com.sampullara.cli.Argument;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
import static org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.CALL;
import static org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.NO_CALL;
@@ -71,6 +71,13 @@ public class K2JSCompilerArguments extends CommonCompilerArguments {
@ValueDescription("<path>")
public String outputPostfix;
@NotNull
public static K2JSCompilerArguments createDefaultInstance() {
K2JSCompilerArguments arguments = new K2JSCompilerArguments();
arguments.moduleKind = K2JsArgumentConstants.MODULE_PLAIN;
return arguments;
}
@Override
@NotNull
public String executableScriptFileName() {

View File

@@ -16,8 +16,9 @@
package org.jetbrains.kotlin.cli.common.arguments;
import com.sampullara.cli.Argument;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
import org.jetbrains.kotlin.config.JvmTarget;
public class K2JVMCompilerArguments extends CommonCompilerArguments {
public static final long serialVersionUID = 0L;
@@ -113,10 +114,16 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
// Paths to output directories for friend modules.
public String[] friendPaths;
@NotNull
public static K2JVMCompilerArguments createDefaultInstance() {
K2JVMCompilerArguments arguments = new K2JVMCompilerArguments();
arguments.jvmTarget = JvmTarget.DEFAULT.getDescription();
return arguments;
}
@Override
@NotNull
public String executableScriptFileName() {
return "kotlinc-jvm";
}
}

View File

@@ -16,7 +16,7 @@
package org.jetbrains.kotlin.cli.common.arguments;
import com.sampullara.cli.Argument;
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
public class K2MetadataCompilerArguments extends CommonCompilerArguments {
public static final long serialVersionUID = 0L;

View File

@@ -17,7 +17,7 @@
package org.jetbrains.kotlin.cli.common.arguments
import com.intellij.util.xmlb.XmlSerializerUtil
import com.sampullara.cli.Args
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Args
import java.lang.reflect.Field
import java.lang.reflect.Modifier
import java.util.*
@@ -37,23 +37,23 @@ import java.util.*
}
}
fun <T : Any> copyBean(bean: T) = copyFields(bean, bean.javaClass.newInstance(), true, collectFieldsToCopy(bean.javaClass, false))
fun <T : Any> copyBean(bean: T) = copyFields(bean, bean::class.java.newInstance(), true, collectFieldsToCopy(bean::class.java, false))
fun <From : Any, To : From> mergeBeans(from: From, to: To): To {
// TODO: rewrite when updated version of com.intellij.util.xmlb is available on TeamCity
return copyFields(from, XmlSerializerUtil.createCopy(to), false, collectFieldsToCopy(from.javaClass, false))
return copyFields(from, XmlSerializerUtil.createCopy(to), false, collectFieldsToCopy(from::class.java, false))
}
fun <From : Any, To : Any> copyInheritedFields(from: From, to: To) = copyFields(from, to, true, collectFieldsToCopy(from.javaClass, true))
fun <From : Any, To : Any> copyInheritedFields(from: From, to: To) = copyFields(from, to, true, collectFieldsToCopy(from::class.java, true))
fun <From : Any, To : Any> copyFieldsSatisfying(from: From, to: To, predicate: (Field) -> Boolean) =
copyFields(from, to, true, collectFieldsToCopy(from.javaClass, false).filter(predicate))
copyFields(from, to, true, collectFieldsToCopy(from::class.java, false).filter(predicate))
private fun <From : Any, To : Any> copyFields(from: From, to: To, deepCopyWhenNeeded: Boolean, fieldsToCopy: List<Field>): To {
if (from == to) return to
for (fromField in fieldsToCopy) {
val toField = to.javaClass.getField(fromField.name)
val toField = to::class.java.getField(fromField.name)
val fromValue = fromField.get(from)
toField.set(to, if (deepCopyWhenNeeded) fromValue?.copyValueIfNeeded() else fromValue)
}
@@ -72,14 +72,14 @@ private fun Any.copyValueIfNeeded(): Any {
is DoubleArray -> Arrays.copyOf(this, size)
is BooleanArray -> Arrays.copyOf(this, size)
is Array<*> -> java.lang.reflect.Array.newInstance(javaClass.componentType, size).apply {
is Array<*> -> java.lang.reflect.Array.newInstance(this::class.java.componentType, size).apply {
this as Array<Any?>
(this@copyValueIfNeeded as Array<Any?>).forEachIndexed { i, value -> this[i] = value?.copyValueIfNeeded() }
}
is MutableCollection<*> -> (this as Collection<Any?>).mapTo(javaClass.newInstance() as MutableCollection<Any?>) { it?.copyValueIfNeeded() }
is MutableCollection<*> -> (this as Collection<Any?>).mapTo(this::class.java.newInstance() as MutableCollection<Any?>) { it?.copyValueIfNeeded() }
is MutableMap<*, *> -> (javaClass.newInstance() as MutableMap<Any?, Any?>).apply {
is MutableMap<*, *> -> (this::class.java.newInstance() as MutableMap<Any?, Any?>).apply {
for ((k, v) in this@copyValueIfNeeded.entries) {
put(k?.copyValueIfNeeded(), v?.copyValueIfNeeded())
}
@@ -89,7 +89,7 @@ private fun Any.copyValueIfNeeded(): Any {
}
}
private fun collectFieldsToCopy(clazz: Class<*>, inheritedOnly: Boolean): List<Field> {
fun collectFieldsToCopy(clazz: Class<*>, inheritedOnly: Boolean): List<Field> {
val fromFields = ArrayList<Field>()
var currentClass: Class<*>? = if (inheritedOnly) clazz.superclass else clazz

View File

@@ -0,0 +1,529 @@
/*
* Copyright (c) 2005, Sam Pullara. All Rights Reserved.
* You may modify and redistribute as long as this attribution remains.
*/
package org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.PrintStream;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class Args {
/**
* {@link ValueCreator} building object using a one arg constructor taking a {@link String} object as parameter
*/
public static final ValueCreator FROM_STRING_CONSTRUCTOR = new ValueCreator() {
public Object createValue(Class<?> type, String value) {
Object v = null;
try {
Constructor<?> init = type.getDeclaredConstructor(String.class);
v = init.newInstance(value);
} catch (NoSuchMethodException e) {
// ignore
} catch (Exception e) {
throw new IllegalArgumentException("Failed to convert " + value + " to type " + type.getName(), e);
}
return v;
}
};
public static final ValueCreator ENUM_CREATOR = new ValueCreator() {
@SuppressWarnings({"unchecked", "rawtypes"})
public Object createValue(Class type, String value) {
if (Enum.class.isAssignableFrom(type)) {
return Enum.valueOf(type, value);
}
return null;
}
};
private static final List<ValueCreator> DEFAULT_VALUE_CREATORS = Arrays.asList(Args.FROM_STRING_CONSTRUCTOR, Args.ENUM_CREATOR);
private static List<ValueCreator> valueCreators = new ArrayList<Args.ValueCreator>(DEFAULT_VALUE_CREATORS);
/**
* A convenience method for parsing and automatically producing error messages.
*
* @param target Either an instance or a class
* @param args The arguments you want to parse and populate
* @return The list of arguments that were not consumed
*/
public static List<String> parseOrExit(Object target, String[] args) {
try {
return parse(target, args);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
Args.usage(target);
System.exit(1);
throw e;
}
}
public static List<String> parse(Object target, String[] args) {
return parse(target, args, true);
}
/**
* Parse a set of arguments and populate the target with the appropriate values.
*
* @param target
* Either an instance or a class
* @param args
* The arguments you want to parse and populate
* @param failOnExtraFlags
* Throw an IllegalArgumentException if extra flags are present
* @return The list of arguments that were not consumed
*/
public static List<String> parse(Object target, String[] args, boolean failOnExtraFlags) {
List<String> arguments = new ArrayList<String>();
arguments.addAll(Arrays.asList(args));
Class<?> clazz;
if (target instanceof Class) {
clazz = (Class) target;
} else {
clazz = target.getClass();
try {
BeanInfo info = Introspector.getBeanInfo(clazz);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
processProperty(target, pd, arguments);
}
} catch (IntrospectionException e) {
// If its not a JavaBean we ignore it
}
}
// Check fields of 'target' class and its superclasses
for (Class<?> currentClazz = clazz; currentClazz != null; currentClazz = currentClazz.getSuperclass()) {
for (Field field : currentClazz.getDeclaredFields()) {
processField(target, field, arguments);
}
}
if (failOnExtraFlags) {
for (String argument : arguments) {
if (argument.startsWith("-")) {
throw new IllegalArgumentException("Invalid argument: " + argument);
}
}
}
return arguments;
}
private static void processField(Object target, Field field, List<String> arguments) {
Argument argument = field.getAnnotation(Argument.class);
if (argument != null) {
boolean set = false;
for (Iterator<String> i = arguments.iterator(); i.hasNext(); ) {
String arg = i.next();
String prefix = argument.prefix();
String delimiter = argument.delimiter();
if (arg.startsWith(prefix)) {
Object value;
String name = getName(argument, field);
String alias = getAlias(argument);
arg = arg.substring(prefix.length());
Class<?> type = field.getType();
if (arg.equals(name) || (alias != null && arg.equals(alias))) {
i.remove();
value = consumeArgumentValue(type, argument, i);
if (!set) {
setField(type, field, target, value, delimiter);
} else {
addArgument(type, field, target, value, delimiter);
}
set = true;
}
if (set && !type.isArray()) break;
}
}
if (!set && argument.required()) {
String name = getName(argument, field);
throw new IllegalArgumentException("You must set argument " + name);
}
}
}
private static void addArgument(Class type, Field field, Object target, Object value, String delimiter) {
try {
Object[] os = (Object[]) field.get(target);
Object[] vs = (Object[]) getValue(type, value, delimiter);
Object[] s = (Object[]) Array.newInstance(type.getComponentType(), os.length + vs.length);
System.arraycopy(os, 0, s, 0, os.length);
System.arraycopy(vs, 0, s, os.length, vs.length);
field.set(target, s);
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException("Could not set field " + field, iae);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Could not find constructor in class " + type.getName() + " that takes a string", e);
}
}
private static void addPropertyArgument(Class type, PropertyDescriptor property, Object target, Object value, String delimiter) {
try {
Object[] os = (Object[]) property.getReadMethod().invoke(target);
Object[] vs = (Object[]) getValue(type, value, delimiter);
Object[] s = (Object[]) Array.newInstance(type.getComponentType(), os.length + vs.length);
System.arraycopy(os, 0, s, 0, os.length);
System.arraycopy(vs, 0, s, os.length, vs.length);
property.getWriteMethod().invoke(target, (Object) s);
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException("Could not set property " + property, iae);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Could not find constructor in class " + type.getName() + " that takes a string", e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException("Failed to validate argument " + value + " for " + property);
}
}
private static void processProperty(Object target, PropertyDescriptor property, List<String> arguments) {
Method writeMethod = property.getWriteMethod();
if (writeMethod != null) {
Argument argument = writeMethod.getAnnotation(Argument.class);
if (argument != null) {
boolean set = false;
for (Iterator<String> i = arguments.iterator(); i.hasNext(); ) {
String arg = i.next();
String prefix = argument.prefix();
String delimiter = argument.delimiter();
if (arg.startsWith(prefix)) {
Object value;
String name = getName(argument, property);
String alias = getAlias(argument);
arg = arg.substring(prefix.length());
Class<?> type = property.getPropertyType();
if (arg.equals(name) || (alias != null && arg.equals(alias))) {
i.remove();
value = consumeArgumentValue(type, argument, i);
if (!set) {
setProperty(type, property, target, value, delimiter);
} else {
addPropertyArgument(type, property, target, value, delimiter);
}
set = true;
}
if (set && !type.isArray()) break;
}
}
if (!set && argument.required()) {
String name = getName(argument, property);
throw new IllegalArgumentException("You must set argument " + name);
}
}
}
}
/**
* Generate usage information based on the target annotations.
*
* @param target An instance or class.
*/
public static void usage(Object target) {
usage(System.err, target);
}
/**
* Generate usage information based on the target annotations.
*
* @param errStream A {@link java.io.PrintStream} to print the usage information to.
* @param target An instance or class.
*/
public static void usage(PrintStream errStream, Object target) {
Class<?> clazz;
if (target instanceof Class) {
clazz = (Class) target;
} else {
clazz = target.getClass();
}
errStream.println("Usage: " + clazz.getName());
for (Class<?> currentClazz = clazz; currentClazz != null; currentClazz = currentClazz.getSuperclass()) {
for (Field field : currentClazz.getDeclaredFields()) {
fieldUsage(errStream, target, field);
}
}
try {
BeanInfo info = Introspector.getBeanInfo(clazz);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
propertyUsage(errStream, target, pd);
}
} catch (IntrospectionException e) {
// If its not a JavaBean we ignore it
}
}
private static void fieldUsage(PrintStream errStream, Object target, Field field) {
Argument argument = field.getAnnotation(Argument.class);
if (argument != null) {
String name = getName(argument, field);
String alias = getAlias(argument);
String prefix = argument.prefix();
String delimiter = argument.delimiter();
String description = argument.description();
makeAccessible(field);
try {
Object defaultValue = field.get(target);
Class<?> type = field.getType();
propertyUsage(errStream, prefix, name, alias, type, delimiter, description, defaultValue);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Could not use thie field " + field + " as an argument field", e);
}
}
}
private static void propertyUsage(PrintStream errStream, Object target, PropertyDescriptor field) {
Method writeMethod = field.getWriteMethod();
if (writeMethod != null) {
Argument argument = writeMethod.getAnnotation(Argument.class);
if (argument != null) {
String name = getName(argument, field);
String alias = getAlias(argument);
String prefix = argument.prefix();
String delimiter = argument.delimiter();
String description = argument.description();
try {
Method readMethod = field.getReadMethod();
Object defaultValue;
if (readMethod == null) {
defaultValue = null;
} else {
defaultValue = readMethod.invoke(target, (Object[]) null);
}
Class<?> type = field.getPropertyType();
propertyUsage(errStream, prefix, name, alias, type, delimiter, description, defaultValue);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Could not use thie field " + field + " as an argument field", e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException("Could not get default value for " + field, e);
}
}
}
}
private static void propertyUsage(PrintStream errStream, String prefix, String name, String alias, Class<?> type, String delimiter, String description, Object defaultValue) {
StringBuilder sb = new StringBuilder(" ");
sb.append(prefix);
sb.append(name);
if (alias != null) {
sb.append(" (");
sb.append(prefix);
sb.append(alias);
sb.append(")");
}
if (type == Boolean.TYPE || type == Boolean.class) {
sb.append(" [flag] ");
sb.append(description);
} else {
sb.append(" [");
if (type.isArray()) {
String typeName = getTypeName(type.getComponentType());
sb.append(typeName);
sb.append("[");
sb.append(delimiter);
sb.append("]");
} else {
String typeName = getTypeName(type);
sb.append(typeName);
}
sb.append("] ");
sb.append(description);
if (defaultValue != null) {
sb.append(" (");
if (type.isArray()) {
List<Object> list = new ArrayList<Object>();
int len = Array.getLength(defaultValue);
for (int i = 0; i < len; i++) {
list.add(Array.get(defaultValue, i));
}
sb.append(list);
} else {
sb.append(defaultValue);
}
sb.append(")");
}
}
errStream.println(sb);
}
private static String getTypeName(Class<?> type) {
String typeName = type.getName();
int beginIndex = typeName.lastIndexOf(".");
typeName = typeName.substring(beginIndex + 1);
return typeName;
}
static String getName(Argument argument, PropertyDescriptor property) {
String name = argument.value();
if (name.equals("")) {
name = property.getName();
}
return name;
}
private static Object consumeArgumentValue(Class<?> type, Argument argument, Iterator<String> i) {
Object value;
if (type == Boolean.TYPE || type == Boolean.class) {
value = true;
} else {
if (i.hasNext()) {
value = i.next();
i.remove();
} else {
throw new IllegalArgumentException("Must have a value for non-boolean argument " + argument.value());
}
}
return value;
}
static void setProperty(Class<?> type, PropertyDescriptor property, Object target, Object value, String delimiter) {
try {
value = getValue(type, value, delimiter);
property.getWriteMethod().invoke(target, value);
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException("Could not set property " + property, iae);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Could not find constructor in class " + type.getName() + " that takes a string", e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException("Failed to validate argument " + value + " for " + property);
}
}
static String getAlias(Argument argument) {
String alias = argument.alias();
if (alias.equals("")) {
alias = null;
}
return alias;
}
static String getName(Argument argument, Field field) {
String name = argument.value();
if (name.equals("")) {
name = field.getName();
}
return name;
}
static void setField(Class<?> type, Field field, Object target, Object value, String delimiter) {
makeAccessible(field);
try {
value = getValue(type, value, delimiter);
field.set(target, value);
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException("Could not set field " + field, iae);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Could not find constructor in class " + type.getName() + " that takes a string", e);
}
}
private static Object getValue(Class<?> type, Object value, String delimiter) throws NoSuchMethodException {
if (type != String.class && type != Boolean.class && type != Boolean.TYPE) {
String string = (String) value;
if (type.isArray()) {
String[] strings = string.split(delimiter);
type = type.getComponentType();
if (type == String.class) {
value = strings;
} else {
Object[] array = (Object[]) Array.newInstance(type, strings.length);
for (int i = 0; i < array.length; i++) {
array[i] = createValue(type, strings[i]);
}
value = array;
}
} else {
value = createValue(type, string);
}
}
return value;
}
private static Object createValue(Class<?> type, String valueAsString) throws NoSuchMethodException {
for (ValueCreator valueCreator : valueCreators) {
Object createdValue = valueCreator.createValue(type, valueAsString);
if (createdValue != null) {
return createdValue;
}
}
throw new IllegalArgumentException(String.format("cannot instanciate any %s object using %s value", type.toString(), valueAsString));
}
private static void makeAccessible(AccessibleObject ao) {
if (ao instanceof Member) {
Member member = (Member) ao;
if (!Modifier.isPublic(member.getModifiers())) {
ao.setAccessible(true);
}
}
}
/**
* Creates a {@link ValueCreator} object able to create object assignable from given type,
* using a static one arg method which name is the the given one taking a String object as parameter
*
* @param compatibleType the base assignable for which this object will try to invoke the given method
* @param methodName the name of the one arg method taking a String as parameter that will be used to built a new value
* @return null if the object could not be created, the value otherwise
*/
public static ValueCreator byStaticMethodInvocation(final Class<?> compatibleType, final String methodName) {
return new ValueCreator() {
public Object createValue(Class<?> type, String value) {
Object v = null;
if (compatibleType.isAssignableFrom(type)) {
try {
Method m = type.getMethod(methodName, String.class);
return m.invoke(null, value);
} catch (NoSuchMethodException e) {
// ignore
} catch (Exception e) {
throw new IllegalArgumentException(String.format("could not invoke %s#%s to create an obejct from %s", type.toString(), methodName, value));
}
}
return v;
}
};
}
/**
* Allows external extension of the valiue creators.
*
* @param vc another value creator to take into account for trying to create values
*/
public static void registerValueCreator(ValueCreator vc) {
valueCreators.add(vc);
}
/**
* Cleanup of registered ValueCreators (mainly for tests)
*/
public static void resetValueCreators() {
valueCreators.clear();
valueCreators.addAll(DEFAULT_VALUE_CREATORS);
}
public static interface ValueCreator {
/**
* Creates a value object of the given type using the given string value representation;
*
* @param type the type to create an instance of
* @param value the string represented value of the object to create
* @return null if the object could not be created, the value otherwise
*/
public Object createValue(Class<?> type, String value);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2005, Sam Pullara. All Rights Reserved.
* You may modify and redistribute as long as this attribution remains.
*/
package org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Argument {
/**
* This is the actual command line argument itself
*/
String value() default "";
/**
* If this is true, then the argument must be set or the parse will fail
*/
boolean required() default false;
/**
* This is the prefix expected for the argument
*/
String prefix() default "-";
/**
* Each argument can have an alias
*/
String alias() default "";
/**
* A description of the argument that will appear in the usage method
*/
String description() default "";
/**
* A delimiter for arguments that are multi-valued.
*/
String delimiter() default ",";
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* Created by IntelliJ IDEA.
* <p/>
* User: samp
* Date: Nov 11, 2007
* Time: 3:42:27 PM
*/
public class PropertiesArgs {
/**
* Parse properties instead of String arguments. Any additional arguments need to be passed some other way.
* This is often used in a second pass when the property filename is passed on the command line. Because of
* required properties you must be careful to set them all in the property file.
*
* @param target Either an instance or a class
* @param arguments The properties that contain the arguments
*/
public static void parse(Object target, Properties arguments) {
Class clazz;
if (target instanceof Class) {
clazz = (Class) target;
} else {
clazz = target.getClass();
}
for (Field field : clazz.getDeclaredFields()) {
processField(target, field, arguments);
}
try {
BeanInfo info = Introspector.getBeanInfo(clazz);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
processProperty(target, pd, arguments);
}
} catch (IntrospectionException e) {
// If its not a JavaBean we ignore it
}
}
private static void processField(Object target, Field field, Properties arguments) {
Argument argument = field.getAnnotation(Argument.class);
if (argument != null) {
String name = Args.getName(argument, field);
String alias = Args.getAlias(argument);
Class type = field.getType();
Object value = arguments.get(name);
if (value == null && alias != null) {
value = arguments.get(alias);
}
if (value != null) {
if (type == Boolean.TYPE || type == Boolean.class) {
value = true;
}
Args.setField(type, field, target, value, argument.delimiter());
} else {
if (argument.required()) {
throw new IllegalArgumentException("You must set argument " + name);
}
}
}
}
private static void processProperty(Object target, PropertyDescriptor property, Properties arguments) {
Method writeMethod = property.getWriteMethod();
if (writeMethod != null) {
Argument argument = writeMethod.getAnnotation(Argument.class);
if (argument != null) {
String name = Args.getName(argument, property);
String alias = Args.getAlias(argument);
Object value = arguments.get(name);
if (value == null && alias != null) {
value = arguments.get(alias);
}
if (value != null) {
Class type = property.getPropertyType();
if (type == Boolean.TYPE || type == Boolean.class) {
value = true;
}
Args.setProperty(type, property, target, value, argument.delimiter());
} else {
if (argument.required()) {
throw new IllegalArgumentException("You must set argument " + name);
}
}
}
}
}
}

View File

@@ -35,7 +35,7 @@ interface KotlinJsr223JvmInvocableScriptEngine : Invocable {
val evalState = state.asState(GenericReplEvaluatorState::class.java)
return evalState.history.map { it.item }.filter { it.instance != null }.reversed().ensureNotEmpty("no script ").let { history ->
if (receiverInstance != null) {
val receiverKlass = receiverClass ?: receiverInstance.javaClass.kotlin
val receiverKlass = receiverClass ?: receiverInstance::class.java.kotlin
val receiverInHistory = history.find { it.instance == receiverInstance } ?:
EvalClassWithInstanceAndLoader(receiverKlass, receiverInstance, receiverKlass.java.classLoader, history.first().invokeWrapper)
listOf(receiverInHistory) + history.filterNot { it == receiverInHistory }
@@ -54,7 +54,7 @@ interface KotlinJsr223JvmInvocableScriptEngine : Invocable {
override fun invokeMethod(thiz: Any?, name: String?, vararg args: Any?): Any? {
if (name == null) throw java.lang.NullPointerException("method name cannot be null")
if (thiz == null) throw IllegalArgumentException("cannot invoke method on the null object")
return invokeImpl(prioritizedHistory(thiz.javaClass.kotlin, thiz), name, args)
return invokeImpl(prioritizedHistory(thiz::class.java.kotlin, thiz), name, args)
}
private fun invokeImpl(prioritizedCallOrder: List<EvalClassWithInstanceAndLoader>, name: String, args: Array<out Any?>): Any? {

View File

@@ -26,7 +26,7 @@ fun makeScriptBaseName(codeLine: ReplCodeLine) =
fun renderReplStackTrace(cause: Throwable, startFromMethodName: String): String {
val newTrace = arrayListOf<StackTraceElement>()
var skip = true
for ((_, element) in cause.stackTrace.withIndex().reversed()) {
for (element in cause.stackTrace.reversed()) {
if ("${element.className}.${element.methodName}" == startFromMethodName) {
skip = false
}

View File

@@ -40,8 +40,9 @@ import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStat
import org.jetbrains.kotlin.utils.StringsKt;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import static org.jetbrains.kotlin.cli.common.ExitCode.*;
@@ -155,6 +156,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
}
reportUnknownExtraFlags(messageCollector, arguments);
reportUnsupportedJavaVersion(messageCollector, arguments);
GroupingMessageCollector groupingCollector = new GroupingMessageCollector(messageCollector);
@@ -232,8 +234,6 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
configuration.put(CLIConfigurationKeys.COMPILER_JAR_LOCATOR, locator);
}
configuration.put(CommonConfigurationKeys.SKIP_METADATA_VERSION_CHECK, arguments.skipMetadataVersionCheck);
setupLanguageVersionSettings(configuration, arguments);
}
@@ -247,11 +247,15 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
// If only "-api-version" is specified, language version is assumed to be the latest
languageVersion = LanguageVersion.LATEST;
}
if (apiVersion == null) {
// 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)
apiVersion = languageVersion;
}
else {
configuration.put(CLIConfigurationKeys.IS_API_VERSION_EXPLICIT, true);
}
if (apiVersion.compareTo(languageVersion) > 0) {
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
@@ -262,40 +266,33 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
);
}
List<LanguageFeature> extraLanguageFeatures = new ArrayList<LanguageFeature>(0);
Map<LanguageFeature, LanguageFeature.State> extraLanguageFeatures = new HashMap<LanguageFeature, LanguageFeature.State>(0);
if (arguments.multiPlatform) {
extraLanguageFeatures.add(LanguageFeature.MultiPlatformProjects);
}
if (arguments.noCheckImpl) {
extraLanguageFeatures.add(LanguageFeature.MultiPlatformDoNotCheckImpl);
extraLanguageFeatures.put(LanguageFeature.MultiPlatformProjects, LanguageFeature.State.ENABLED);
}
LanguageFeature coroutinesApplicabilityLevel = chooseCoroutinesApplicabilityLevel(configuration, arguments);
if (coroutinesApplicabilityLevel != null) {
extraLanguageFeatures.add(coroutinesApplicabilityLevel);
LanguageFeature.State coroutinesState = chooseCoroutinesApplicabilityLevel(configuration, arguments);
if (coroutinesState != null) {
extraLanguageFeatures.put(LanguageFeature.Coroutines, coroutinesState);
}
CommonConfigurationKeysKt.setLanguageVersionSettings(
configuration,
new LanguageVersionSettingsImpl(
languageVersion,
ApiVersion.createByLanguageVersion(apiVersion),
extraLanguageFeatures,
arguments.apiVersion != null
)
);
LanguageVersionSettingsImpl settings =
new LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(apiVersion), extraLanguageFeatures);
settings.switchFlag(AnalysisFlags.getSkipMetadataVersionCheck(), arguments.skipMetadataVersionCheck);
settings.switchFlag(AnalysisFlags.getMultiPlatformDoNotCheckImpl(), arguments.noCheckImpl);
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, settings);
}
@Nullable
private static LanguageFeature chooseCoroutinesApplicabilityLevel(
private static LanguageFeature.State chooseCoroutinesApplicabilityLevel(
@NotNull CompilerConfiguration configuration,
@NotNull CommonCompilerArguments arguments
) {
if (arguments.coroutinesError && !arguments.coroutinesWarn && !arguments.coroutinesEnable) {
return LanguageFeature.ErrorOnCoroutines;
return LanguageFeature.State.ENABLED_WITH_ERROR;
}
else if (arguments.coroutinesEnable && !arguments.coroutinesWarn && !arguments.coroutinesError) {
return LanguageFeature.DoNotWarnOnCoroutines;
return LanguageFeature.State.ENABLED;
}
else if (!arguments.coroutinesEnable && !arguments.coroutinesError) {
return null;
@@ -350,6 +347,16 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
}
}
private void reportUnsupportedJavaVersion(MessageCollector collector, A arguments) {
if (!SystemInfo.isJavaVersionAtLeast("1.8") && !arguments.noJavaVersionWarning) {
collector.report(
CompilerMessageSeverity.STRONG_WARNING,
"Running the Kotlin compiler under Java 6 or 7 is unsupported and will no longer be possible in a future update.",
CompilerMessageLocation.NO_LOCATION
);
}
}
@NotNull
protected abstract ExitCode doExecute(
@NotNull A arguments,

View File

@@ -29,6 +29,8 @@ 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<CompilerJarLocator> COMPILER_JAR_LOCATOR =

View File

@@ -16,11 +16,11 @@
package org.jetbrains.kotlin.cli.common;
import com.sampullara.cli.Argument;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments;
import org.jetbrains.kotlin.cli.common.arguments.ValueDescription;
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
import java.io.PrintStream;
import java.lang.reflect.Field;

View File

@@ -67,7 +67,7 @@ class ModuleVisibilityHelperImpl : ModuleVisibilityHelper {
private fun findModule(descriptor: DeclarationDescriptor, modules: Collection<Module>): Module? {
val sourceElement = getSourceElement(descriptor)
if (sourceElement is KotlinSourceElement) {
return modules.singleOrNull() ?: modules.firstOrNull { sourceElement.psi.getContainingKtFile().virtualFile.path in it.getSourceFiles() }
return modules.singleOrNull() ?: modules.firstOrNull { sourceElement.psi.containingKtFile.virtualFile.path in it.getSourceFiles() }
}
else {
return modules.firstOrNull { module ->

View File

@@ -34,14 +34,14 @@ fun OutputFileCollection.writeAll(outputDir: File, report: (file: OutputFile, so
}
}
private val REPORT_NOTHING = { file: OutputFile, sources: List<File>, output: File -> }
private val REPORT_NOTHING: (OutputFile, List<File>, File) -> Unit = { _, _, _ -> }
fun OutputFileCollection.writeAllTo(outputDir: File) {
writeAll(outputDir, REPORT_NOTHING)
}
fun OutputFileCollection.writeAll(outputDir: File, messageCollector: MessageCollector) {
writeAll(outputDir) { file, sources, output ->
writeAll(outputDir) { _, sources, output ->
messageCollector.report(CompilerMessageSeverity.OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output), CompilerMessageLocation.NO_LOCATION)
}
}

View File

@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.cli.jvm
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
@@ -120,19 +121,16 @@ object JvmRuntimeVersionsConsistencyChecker {
val actualApi = ApiVersion.parse(actualRuntimeVersion.toString())
if (actualApi != null) {
val inferredApiVersion =
if (@Suppress("DEPRECATION") languageVersionSettings.isApiVersionExplicit)
if (configuration.getBoolean(CLIConfigurationKeys.IS_API_VERSION_EXPLICIT))
languageVersionSettings.apiVersion
else
// "minOf" is needed in case when API version was inferred from language version and it's older than actualApi.
// For example, in "kotlinc-1.2 -language-version 1.0 -cp kotlin-runtime-1.1.jar" we should still infer API = 1.0
minOf(languageVersionSettings.apiVersion, actualApi)
// "minOf" is needed in case when API version was inferred from language version and it's older than actualApi.
// For example, in "kotlinc-1.2 -language-version 1.0 -cp kotlin-runtime-1.1.jar" we should still infer API = 1.0
val newSettings = LanguageVersionSettingsImpl(
languageVersionSettings.languageVersion,
inferredApiVersion,
languageVersionSettings.additionalFeatures,
isApiVersionExplicit = false
)
val newSettings = object : LanguageVersionSettings by languageVersionSettings {
override val apiVersion: ApiVersion get() = inferredApiVersion
}
messageCollector.issue(null, "Old runtime has been found in the classpath. " +
"Initial language version settings: $languageVersionSettings. " +

View File

@@ -35,7 +35,7 @@ object PluginCliParser {
?.map { File(it).toURI().toURL() }
?.toTypedArray()
?: arrayOf<URL>(),
javaClass.classLoader
this::class.java.classLoader
)
val componentRegistrars = ServiceLoader.load(ComponentRegistrar::class.java, classLoader).toMutableList()
@@ -50,7 +50,7 @@ object PluginCliParser {
configuration: CompilerConfiguration,
classLoader: ClassLoader
) {
val optionValuesByPlugin = arguments.pluginOptions?.map { parsePluginOption(it) }?.groupBy {
val optionValuesByPlugin = arguments.pluginOptions?.map(::parsePluginOption)?.groupBy {
if (it == null) throw CliOptionProcessingException("Wrong plugin option format: $it, should be ${CommonCompilerArguments.PLUGIN_OPTION_FORMAT}")
it.pluginId
} ?: mapOf()

View File

@@ -25,8 +25,9 @@ import com.intellij.util.Function
import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.LightClassBuilder
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
import org.jetbrains.kotlin.asJava.builder.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
@@ -44,7 +45,6 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import org.jetbrains.kotlin.utils.emptyOrSingletonList
import kotlin.properties.Delegates
/**
@@ -76,10 +76,20 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
trace.setKotlinCodeAnalyzer(codeAnalyzer)
}
override fun getContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
override fun createDataHolderForClass(
classOrObject: KtClassOrObject, builder: LightClassBuilder
): LightClassDataHolder.ForClass {
//force resolve companion for light class generation
bindingContext.get(BindingContext.CLASS, classOrObject)?.companionObjectDescriptor
return LightClassConstructionContext(bindingContext, module)
val (stub, bindingContext, diagnostics) = builder(getContext())
bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassDataHolder
return LightClassDataHolderImpl(
stub,
diagnostics
)
}
private fun getContext(): LightClassConstructionContext {
@@ -147,7 +157,7 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
val filesForFacade = findFilesForFacade(facadeFqName, scope)
if (filesForFacade.isEmpty()) return emptyList()
return emptyOrSingletonList<PsiClass>(
return listOfNotNull<PsiClass>(
KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope, filesForFacade))
}
@@ -164,8 +174,9 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
}
}
override fun getContextForFacade(files: Collection<KtFile>): LightClassConstructionContext {
return getContext()
override fun createDataHolderForFacade(files: Collection<KtFile>, builder: LightClassBuilder): LightClassDataHolder.ForFacade {
val (stub, _, diagnostics) = builder(getContext())
return LightClassDataHolderImpl(stub, diagnostics)
}
override fun createTrace(): BindingTraceContext {

View File

@@ -21,18 +21,17 @@ import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
import org.jetbrains.kotlin.utils.addToStdlib.check
import java.io.InputStream
class JvmCliVirtualFileFinder(
class CliVirtualFileFinder(
private val index: JvmDependenciesIndex,
private val scope: GlobalSearchScope
) : VirtualFileKotlinClassFinder() {
) : VirtualFileFinder() {
override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? =
findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class")
@@ -61,6 +60,6 @@ class JvmCliVirtualFileFinder(
private fun findBinaryClass(classId: ClassId, fileName: String): VirtualFile? =
index.findClass(classId, acceptedRootTypes = JavaRoot.OnlyBinary) { dir, _ ->
dir.findChild(fileName)?.check(VirtualFile::isValid)
}?.check { it in scope }
dir.findChild(fileName)?.takeIf(VirtualFile::isValid)
}?.takeIf { it in scope }
}

View File

@@ -18,10 +18,10 @@ package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinderFactory
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
// TODO: create different JvmDependenciesIndex instances for different sets of source roots to improve performance
class JvmCliVirtualFileFinderFactory(private val index: JvmDependenciesIndex) : JvmVirtualFileFinderFactory {
override fun create(scope: GlobalSearchScope): JvmVirtualFileFinder = JvmCliVirtualFileFinder(index, scope)
class CliVirtualFileFinderFactory(private val index: JvmDependenciesIndex) : VirtualFileFinderFactory {
override fun create(scope: GlobalSearchScope): VirtualFileFinder = CliVirtualFileFinder(index, scope)
}

View File

@@ -21,6 +21,7 @@ import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.SmartList
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.ModuleMapping
import org.jetbrains.kotlin.load.kotlin.PackageParts
@@ -33,7 +34,7 @@ class JvmPackagePartProvider(
) : PackagePartProvider {
private data class ModuleMappingInfo(val root: VirtualFile, val mapping: ModuleMapping)
private val deserializationConfiguration = CompilerDeserializationConfiguration(env.configuration)
private val deserializationConfiguration = CompilerDeserializationConfiguration(env.configuration.languageVersionSettings)
private val notLoadedRoots by lazy(LazyThreadSafetyMode.NONE) {
env.configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS)

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