Load JSR-305 annotations for libraries if it's enabled for any module

#KT-19303 Fixed
This commit is contained in:
Dmitry Jemerov
2017-08-01 19:38:04 +02:00
parent 4ca8d3d6cf
commit b423d58a14
12 changed files with 153 additions and 23 deletions
@@ -166,7 +166,7 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
override fun configureAnalysisFlags(): MutableMap<AnalysisFlag<*>, Any> {
val result = super.configureAnalysisFlags()
Jsr305State.values().firstOrNull { it.description == jsr305GlobalReportLevel }?.let {
Jsr305State.findByDescription(jsr305GlobalReportLevel)?.let {
result.put(AnalysisFlag.loadJsr305Annotations, it)
}
return result
@@ -68,5 +68,7 @@ enum class Jsr305State(
companion object {
@JvmField
val DEFAULT: Jsr305State = IGNORE
fun findByDescription(description: String?) = values().firstOrNull { it.description == description }
}
}
@@ -16,19 +16,39 @@
package org.jetbrains.kotlin.idea.compiler
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.TargetPlatformVersion
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.caches.resolve.LibraryInfo
import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo
import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.targetPlatform
object IDELanguageSettingsProvider : LanguageSettingsProvider {
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings {
return (moduleInfo as? ModuleSourceInfo)?.module?.languageVersionSettings ?: project.getLanguageVersionSettings()
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings =
when (moduleInfo) {
is ModuleSourceInfo -> moduleInfo.module.languageVersionSettings
is LibraryInfo -> project.getLanguageVersionSettings(extraAnalysisFlags = getExtraAnalysisFlags(project))
else -> project.getLanguageVersionSettings()
}
private fun getExtraAnalysisFlags(project: Project): Map<AnalysisFlag<*>, Any?> {
val map = mutableMapOf<AnalysisFlag<*>, Any>()
for (module in ModuleManager.getInstance(project).modules) {
val settings = KotlinFacetSettingsProvider.getInstance(project).getSettings(module) ?: continue
val compilerArguments = settings.compilerArguments as? K2JVMCompilerArguments ?: continue
val jsr305state = Jsr305State.findByDescription(compilerArguments.jsr305GlobalReportLevel)
if (jsr305state != null && jsr305state != Jsr305State.IGNORE) {
map.put(AnalysisFlag.loadJsr305Annotations, jsr305state)
break
}
}
return map
}
override fun getTargetPlatform(moduleInfo: ModuleInfo): TargetPlatformVersion {
@@ -74,7 +74,9 @@ fun Module.getAndCacheLanguageLevelByDependencies(): LanguageVersion {
return languageLevel
}
fun Project.getLanguageVersionSettings(contextModule: Module? = null): LanguageVersionSettings {
@JvmOverloads
fun Project.getLanguageVersionSettings(contextModule: Module? = null,
extraAnalysisFlags: Map<AnalysisFlag<*>, Any?> = emptyMap()): LanguageVersionSettings {
val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings
val languageVersion =
LanguageVersion.fromVersionString(arguments.languageVersion)
@@ -88,7 +90,9 @@ fun Project.getLanguageVersionSettings(contextModule: Module? = null): LanguageV
compilerSettings,
null
)
return LanguageVersionSettingsImpl(languageVersion, apiVersion, arguments.configureAnalysisFlags(), extraLanguageFeatures)
return LanguageVersionSettingsImpl(languageVersion, apiVersion,
arguments.configureAnalysisFlags() + extraAnalysisFlags,
extraLanguageFeatures)
}
val Module.languageVersionSettings: LanguageVersionSettings
+19
View File
@@ -0,0 +1,19 @@
package foo;
import javax.annotation.*;
@FieldsAreNullable
public class A {
public String field = null;
@Nonnull
public String nonNullField = "";
public String foo(String q, @Nonnull String x, @CheckForNull CharSequence y) {
return "";
}
@Nonnull
public String bar() {
return "";
}
}
@@ -0,0 +1,17 @@
package foo;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.CheckForNull;
import javax.annotation.meta.TypeQualifierDefault;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@CheckForNull
@TypeQualifierDefault({ElementType.FIELD})
public @interface FieldsAreNullable {
}
+5
View File
@@ -0,0 +1,5 @@
import foo.A
fun main(a: A) {
a.field<error descr="[UNSAFE_CALL] Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?">.</error>length
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.findUsages
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.stubs.createFacet
import org.junit.Test
class FindUsagesMultiModuleTest : AbstractFindUsagesMultiModuleTest() {
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.stubs.AbstractMultiHighlightingTest
import org.jetbrains.kotlin.idea.stubs.createFacet
import org.jetbrains.kotlin.test.TestJdkKind
abstract class AbstractMultiModuleHighlightingTest : AbstractMultiHighlightingTest() {
@@ -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.idea.highlighter
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.Jsr305State
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.stubs.createFacet
import org.jetbrains.kotlin.idea.test.KotlinJdkAndLibraryProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.test.MockLibraryUtil
class Jsr305HighlightingTest : KotlinLightCodeInsightFixtureTestCase() {
override fun getProjectDescriptor(): LightProjectDescriptor {
val foreignAnnotationsJar = MockLibraryUtil.compileJvmLibraryToJar("compiler/testData/foreignAnnotations/annotations", "foreign-annotations")
val libraryJar = MockLibraryUtil.compileJvmLibraryToJar("idea/testData/highlighterJsr305/library", "jsr305-library",
extraClasspath = listOf(foreignAnnotationsJar.absolutePath))
return object : KotlinJdkAndLibraryProjectDescriptor(
listOf(
ForTestCompileRuntime.runtimeJarForTests(),
foreignAnnotationsJar,
libraryJar
)
) {
override fun configureModule(module: Module, model: ModifiableRootModel) {
super.configureModule(module, model)
module.createFacet(TargetPlatformKind.Jvm(JvmTarget.JVM_1_8))
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(module)
(facetSettings.compilerArguments as K2JVMCompilerArguments).jsr305GlobalReportLevel = Jsr305State.ENABLE.description
}
}
}
fun testSimple() {
myFixture.configureByFile("A.kt")
myFixture.checkHighlighting()
}
override fun getTestDataPath() = "idea/testData/highlighterJsr305/project"
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.quickfix
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.stubs.createFacet
import org.junit.Test
class QuickFixMultiModuleTest : AbstractQuickFixMultiModuleTest() {
@@ -96,22 +96,6 @@ abstract class AbstractMultiModuleTest : DaemonAnalyzerTestCase() {
}, this, kind)
}
protected fun Module.createFacet(platformKind: TargetPlatformKind<*>? = null) {
val accessToken = WriteAction.start()
try {
val modelsProvider = IdeModifiableModelsProviderImpl(project)
getOrCreateFacet(modelsProvider, true).configuration.settings.initializeIfNeeded(
this,
modelsProvider.getModifiableRootModel(this),
platformKind
)
modelsProvider.commit()
}
finally {
accessToken.finish()
}
}
protected fun Module.enableMultiPlatform() {
createFacet()
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(this)
@@ -132,3 +116,19 @@ abstract class AbstractMultiModuleTest : DaemonAnalyzerTestCase() {
Assert.assertTrue(atLeastOneFile)
}
}
fun Module.createFacet(platformKind: TargetPlatformKind<*>? = null) {
val accessToken = WriteAction.start()
try {
val modelsProvider = IdeModifiableModelsProviderImpl(project)
getOrCreateFacet(modelsProvider, true).configuration.settings.initializeIfNeeded(
this,
modelsProvider.getModifiableRootModel(this),
platformKind
)
modelsProvider.commit()
}
finally {
accessToken.finish()
}
}