Remove 173 bunch files

This commit is contained in:
Vyacheslav Gerasimov
2019-01-14 15:34:41 +03:00
parent 96c21297b6
commit 818910267e
475 changed files with 0 additions and 82220 deletions
@@ -1,12 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.jvm.modules
import com.intellij.openapi.util.SystemInfo
fun isAtLeastJava9(): Boolean {
return SystemInfo.isJavaVersionAtLeast("9")
}
@@ -1,60 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
description = "Kotlin Daemon Client"
plugins {
kotlin("jvm")
id("jps-compatible")
}
jvmTarget = "1.6"
val nativePlatformVariants = listOf(
"windows-amd64",
"windows-i386",
"osx-amd64",
"osx-i386",
"linux-amd64",
"linux-i386",
"freebsd-amd64-libcpp",
"freebsd-amd64-libstdcpp",
"freebsd-i386-libcpp",
"freebsd-i386-libstdcpp"
)
dependencies {
compileOnly(project(":compiler:util"))
compileOnly(project(":compiler:cli-common"))
compileOnly(project(":compiler:daemon-common"))
compileOnly(project(":kotlin-reflect-api"))
compileOnly(project(":js:js.frontend"))
compileOnly(commonDep("net.rubygrapefruit", "native-platform"))
embeddedComponents(project(":compiler:daemon-common")) { isTransitive = false }
embeddedComponents(commonDep("net.rubygrapefruit", "native-platform"))
nativePlatformVariants.forEach {
embeddedComponents(commonDep("net.rubygrapefruit", "native-platform", "-$it"))
}
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
noDefaultJar()
runtimeJar(task<ShadowJar>("shadowJar")) {
from(mainSourceSet.output)
fromEmbeddedComponents()
}
sourcesJar()
javadocJar()
dist()
ideaPlugin()
publish()
@@ -1,142 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.asJava.builder
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.ClassFileViewProvider
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
import com.intellij.psi.impl.source.tree.TreeElement
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import java.lang.StringBuilder
data class LightClassBuilderResult(val stub: PsiJavaFileStub, val bindingContext: BindingContext, val diagnostics: Diagnostics)
fun buildLightClass(
packageFqName: FqName,
files: Collection<KtFile>,
generateClassFilter: GenerationState.GenerateClassFilter,
context: LightClassConstructionContext,
generate: (state: GenerationState, files: Collection<KtFile>) -> Unit
): LightClassBuilderResult {
val project = files.first().project
try {
val classBuilderFactory = KotlinLightClassBuilderFactory(createJavaFileStub(project, packageFqName, files))
val state = GenerationState.Builder(
project,
classBuilderFactory,
context.module,
context.bindingContext,
files.toList(),
context.languageVersionSettings?.let {
CompilerConfiguration().apply {
languageVersionSettings = it
isReadOnly = true
}
} ?: CompilerConfiguration.EMPTY
).generateDeclaredClassFilter(generateClassFilter).wantsDiagnostics(false).build()
state.beforeCompile()
generate(state, files)
val javaFileStub = classBuilderFactory.result()
ServiceManager.getService(project, StubComputationTracker::class.java)?.onStubComputed(javaFileStub, context)
return LightClassBuilderResult(javaFileStub, context.bindingContext, state.collectedExtraJvmDiagnostics)
}
catch (e: ProcessCanceledException) {
throw e
}
catch (e: RuntimeException) {
logErrorWithOSInfo(e, packageFqName, null)
throw e
}
}
private fun createJavaFileStub(project: Project, packageFqName: FqName, files: Collection<KtFile>): PsiJavaFileStub {
val javaFileStub = PsiJavaFileStubImpl(packageFqName.asString(), /*compiled = */true)
javaFileStub.psiFactory = ClsWrapperStubPsiFactory.INSTANCE
val manager = PsiManager.getInstance(project)
val virtualFile = getRepresentativeVirtualFile(files)
val fakeFile = object : ClsFileImpl(ClassFileViewProvider(manager, virtualFile)) {
override fun getStub() = javaFileStub
override fun getPackageName() = packageFqName.asString()
override fun isPhysical() = false
override fun appendMirrorText(indentLevel: Int, buffer: StringBuilder) {
if (files.size == 1) {
LOG.error("Mirror text should never be calculated for light classes generated from a single file")
}
super.appendMirrorText(indentLevel, buffer)
}
override fun setMirror(element: TreeElement) {
if (files.size == 1) {
LOG.error("Mirror element should never be set for light classes generated from a single file")
}
super.setMirror(element)
}
override fun getMirror(): PsiElement {
if (files.size == 1) {
LOG.error("Mirror element should never be calculated for light classes generated from a single file")
}
return super.getMirror()
}
override fun getText(): String {
return files.singleOrNull()?.text ?: super.getText()
}
}
javaFileStub.psi = fakeFile
return javaFileStub
}
private fun getRepresentativeVirtualFile(files: Collection<KtFile>): VirtualFile {
return files.first().viewProvider.virtualFile
}
private fun logErrorWithOSInfo(cause: Throwable?, fqName: FqName, virtualFile: VirtualFile?) {
val path = if (virtualFile == null) "<null>" else virtualFile.path
LOG.error(
"Could not generate LightClass for $fqName declared in $path\n" +
"System: ${SystemInfo.OS_NAME} ${SystemInfo.OS_VERSION} Java Runtime: ${SystemInfo.JAVA_RUNTIME_VERSION}",
cause
)
}
private val LOG = Logger.getInstance(LightClassBuilderResult::class.java)
@@ -1,86 +0,0 @@
/*
* Copyright 2010-2016 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.asJava.elements
import com.intellij.pom.java.LanguageLevel
import com.intellij.psi.ClassFileViewProvider
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.stubs.PsiClassHolderFileStub
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
open class FakeFileForLightClass(
val ktFile: KtFile,
private val lightClass: () -> KtLightClass,
private val stub: () -> PsiClassHolderFileStub<*>,
private val packageFqName: FqName = ktFile.packageFqName
) : ClsFileImpl(ClassFileViewProvider(ktFile.manager, ktFile.virtualFile ?:
ktFile.originalFile.virtualFile ?:
ktFile.viewProvider.virtualFile)) {
override fun getPackageName() = packageFqName.asString()
override fun getStub() = stub()
override fun getClasses() = arrayOf(lightClass())
override fun getNavigationElement() = ktFile
override fun accept(visitor: PsiElementVisitor) {
// Prevent access to compiled PSI
// TODO: More complex traversal logic may be implemented when necessary
}
// this should be equal to current compiler target language level
override fun getLanguageLevel() = LanguageLevel.JDK_1_6
override fun hashCode(): Int {
val thisClass = lightClass()
if (thisClass is KtLightClassForSourceDeclaration) return ktFile.hashCode()
return thisClass.hashCode()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is FakeFileForLightClass) return false
val thisClass = lightClass()
val anotherClass = other.lightClass()
if (thisClass is KtLightClassForSourceDeclaration) {
return anotherClass is KtLightClassForSourceDeclaration && ktFile == other.ktFile
}
return thisClass == anotherClass
}
override fun isEquivalentTo(another: PsiElement?) = this == another
override fun setPackageName(packageName: String) {
if (lightClass() is KtLightClassForFacade) {
ktFile.packageDirective?.fqName = FqName(packageName)
}
else {
super.setPackageName(packageName)
}
}
override fun isPhysical() = false
}
@@ -1,135 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.asJava.elements
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.*
import com.intellij.psi.impl.LanguageConstantExpressionEvaluator
import com.intellij.psi.impl.light.LightIdentifier
import com.intellij.psi.impl.light.LightTypeElement
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KtLightPsiArrayInitializerMemberValue(
override val kotlinOrigin: KtElement,
val lightParent: PsiElement,
private val arguments: (KtLightPsiArrayInitializerMemberValue) -> List<PsiAnnotationMemberValue>
) : KtLightElementBase(lightParent), PsiArrayInitializerMemberValue {
override fun getInitializers(): Array<PsiAnnotationMemberValue> = arguments(this).toTypedArray()
override fun getParent(): PsiElement = lightParent
override fun isPhysical(): Boolean = true
}
open class KtLightPsiLiteral(
override val kotlinOrigin: KtExpression,
val lightParent: PsiElement
) : KtLightElementBase(lightParent), PsiLiteralExpression {
override fun getValue(): Any? =
LanguageConstantExpressionEvaluator.INSTANCE.forLanguage(kotlinOrigin.language)?.computeConstantExpression(this, false)
override fun getType(): PsiType? {
val bindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(kotlinOrigin)
val kotlinType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, kotlinOrigin] ?: return null
val typeFqName = kotlinType.constructor.declarationDescriptor?.fqNameSafe?.asString() ?: return null
return psiType(typeFqName, kotlinOrigin)
}
override fun getParent(): PsiElement = lightParent
override fun isPhysical(): Boolean = true
override fun replace(newElement: PsiElement): PsiElement {
val value = (newElement as? PsiLiteral)?.value as? String ?: return this
kotlinOrigin.replace(KtPsiFactory(this).createExpression("\"${StringUtil.escapeStringCharacters(value)}\""))
return this
}
override fun getReference(): PsiReference? = references.singleOrNull()
override fun getReferences(): Array<out PsiReference> = kotlinOrigin.references
}
class KtLightPsiClassObjectAccessExpression(override val kotlinOrigin: KtClassLiteralExpression, lightParent: PsiElement) :
KtLightPsiLiteral(kotlinOrigin, lightParent), PsiClassObjectAccessExpression {
override fun getType(): PsiType {
val bindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(kotlinOrigin)
val (classId, arrayDimensions) = bindingContext[BindingContext.COMPILE_TIME_VALUE, kotlinOrigin]
?.toConstantValue(TypeUtils.NO_EXPECTED_TYPE)?.safeAs<KClassValue>()?.value ?: return PsiType.VOID
var type = psiType(classId.asSingleFqName().asString(), kotlinOrigin, boxPrimitiveType = arrayDimensions > 0) ?: return PsiType.VOID
repeat(arrayDimensions) {
type = type.createArrayType()
}
return type
}
override fun getOperand(): PsiTypeElement = LightTypeElement(kotlinOrigin.manager, type)
}
internal fun psiType(kotlinFqName: String, context: PsiElement, boxPrimitiveType: Boolean = false): PsiType {
if (!boxPrimitiveType) {
when (kotlinFqName) {
"kotlin.Int" -> return PsiType.INT
"kotlin.Long" -> return PsiType.LONG
"kotlin.Short" -> return PsiType.SHORT
"kotlin.Boolean" -> return PsiType.BOOLEAN
"kotlin.Byte" -> return PsiType.BYTE
"kotlin.Char" -> return PsiType.CHAR
"kotlin.Double" -> return PsiType.DOUBLE
"kotlin.Float" -> return PsiType.FLOAT
}
}
when (kotlinFqName) {
"kotlin.IntArray" -> return PsiType.INT.createArrayType()
"kotlin.LongArray" -> return PsiType.LONG.createArrayType()
"kotlin.ShortArray" -> return PsiType.SHORT.createArrayType()
"kotlin.BooleanArray" -> return PsiType.BOOLEAN.createArrayType()
"kotlin.ByteArray" -> return PsiType.BYTE.createArrayType()
"kotlin.CharArray" -> return PsiType.CHAR.createArrayType()
"kotlin.DoubleArray" -> return PsiType.DOUBLE.createArrayType()
"kotlin.FloatArray" -> return PsiType.FLOAT.createArrayType()
}
val javaFqName = JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(kotlinFqName))?.asSingleFqName()?.asString() ?: kotlinFqName
return PsiType.getTypeByName(javaFqName, context.project, context.resolveScope)
}
class KtLightPsiNameValuePair private constructor(
override val kotlinOrigin: KtElement,
val valueArgument: KtValueArgument,
lightParent: PsiElement,
private val argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue?
) : KtLightElementBase(lightParent),
PsiNameValuePair {
constructor(
valueArgument: KtValueArgument,
lightParent: PsiElement,
argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue?
) : this(valueArgument.asElement(), valueArgument, lightParent, argument)
override fun setValue(newValue: PsiAnnotationMemberValue): PsiAnnotationMemberValue =
throw UnsupportedOperationException("can't modify KtLightPsiNameValuePair")
override fun getNameIdentifier(): PsiIdentifier? = LightIdentifier(kotlinOrigin.manager, valueArgument.name)
override fun getName(): String? = valueArgument.getArgumentName()?.asName?.asString()
private val _value: PsiAnnotationMemberValue? by lazyPub { argument(this) }
override fun getValue(): PsiAnnotationMemberValue? = _value
override fun getLiteralValue(): String? = (getValue() as? PsiLiteralExpression)?.value?.toString()
}
@@ -1,425 +0,0 @@
/*
* Copyright 2010-2016 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.asJava.elements
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.annotations.NotNull
import org.jetbrains.annotations.Nullable
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.nullability
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.asJava.elements.lightAnnotations")
abstract class KtLightAbstractAnnotation(parent: PsiElement, computeDelegate: () -> PsiAnnotation) :
KtLightElementBase(parent), PsiAnnotation, KtLightElement<KtCallElement, PsiAnnotation> {
private val _clsDelegate: PsiAnnotation by lazyPub(computeDelegate)
override val clsDelegate: PsiAnnotation
get() {
if (!accessAnnotationsClsDelegateIsAllowed && ApplicationManager.getApplication().isUnitTestMode && this !is KtLightNonSourceAnnotation)
LOG.error("KtLightAbstractAnnotation clsDelegate requested for ${this.javaClass}")
return _clsDelegate
}
override fun getNameReferenceElement() = clsDelegate.nameReferenceElement
override fun getOwner() = parent as? PsiAnnotationOwner
override fun getMetaData() = clsDelegate.metaData
override fun getParameterList() = clsDelegate.parameterList
override fun canNavigate(): Boolean = super<KtLightElementBase>.canNavigate()
override fun canNavigateToSource(): Boolean = super<KtLightElementBase>.canNavigateToSource()
override fun navigate(requestFocus: Boolean) = super<KtLightElementBase>.navigate(requestFocus)
open fun fqNameMatches(fqName: String): Boolean = qualifiedName == fqName
}
class KtLightAnnotationForSourceEntry(
private val qualifiedName: String,
override val kotlinOrigin: KtCallElement,
parent: PsiElement,
computeDelegate: () -> PsiAnnotation
) : KtLightAbstractAnnotation(parent, computeDelegate) {
override fun getQualifiedName() = qualifiedName
override fun isPhysical() = true
override fun getName(): String? = null
override fun findAttributeValue(name: String?) = getAttributeValue(name, true)
override fun findDeclaredAttributeValue(name: String?): PsiAnnotationMemberValue? = getAttributeValue(name, false)
private fun getCallEntry(name: String): MutableMap.MutableEntry<ValueParameterDescriptor, ResolvedValueArgument>? {
val resolvedCall = kotlinOrigin.getResolvedCall() ?: return null
return resolvedCall.valueArguments.entries.find { (param, _) -> param.name.asString() == name } ?: return null
}
private fun getAttributeValue(name: String?, useDefault: Boolean): PsiAnnotationMemberValue? {
val name = name ?: "value"
val callEntry = getCallEntry(name) ?: return null
val valueArgument = callEntry.value.arguments.firstOrNull()
if (valueArgument != null) {
ktLightAnnotationParameterList.attributes.find { (it as KtLightPsiNameValuePair).valueArgument === valueArgument }?.let {
return it.value
}
}
if (useDefault && callEntry.key.declaresOrInheritsDefaultValue()) {
val psiElement = callEntry.key.source.getPsi()
when (psiElement) {
is KtParameter ->
return psiElement.defaultValue?.let { convertToLightAnnotationMemberValue(this, it) }
is PsiAnnotationMethod ->
return psiElement.defaultValue
}
}
return null
}
override fun getNameReferenceElement(): PsiJavaCodeReferenceElement? = KtLightPsiJavaCodeReferenceElement(
kotlinOrigin.navigationElement,
{
(kotlinOrigin as? KtAnnotationEntry)?.typeReference?.reference
?: (kotlinOrigin.calleeExpression?.nameReference)?.references?.firstOrNull()
},
{ super.getNameReferenceElement() }
)
private val ktLightAnnotationParameterList by lazyPub { KtLightAnnotationParameterList() }
override fun getParameterList(): PsiAnnotationParameterList = ktLightAnnotationParameterList
inner class KtLightAnnotationParameterList() : KtLightElementBase(this),
PsiAnnotationParameterList {
override val kotlinOrigin: KtElement? get() = null
private val _attributes: Array<PsiNameValuePair> by lazyPub {
this@KtLightAnnotationForSourceEntry.kotlinOrigin.valueArguments.map { makeLightPsiNameValuePair(it as KtValueArgument) }
.toTypedArray<PsiNameValuePair>()
}
private fun makeArrayInitializerIfExpected(pair: KtLightPsiNameValuePair): PsiAnnotationMemberValue? {
val valueArgument = pair.valueArgument
val name = valueArgument.name ?: "value"
val callEntry = getCallEntry(name) ?: return null
val valueArguments = callEntry.value.arguments
val argument = valueArguments.firstOrNull()?.getArgumentExpression() ?: return null
if (!callEntry.key.type.let { KotlinBuiltIns.isArrayOrPrimitiveArray(it) }) return null
if (argument !is KtStringTemplateExpression &&
argument !is KtConstantExpression &&
argument !is KtClassLiteralExpression &&
getAnnotationName(argument) == null
) {
return null
}
val parent = PsiTreeUtil.findCommonParent(valueArguments.map { it.getArgumentExpression() }) as KtElement
return KtLightPsiArrayInitializerMemberValue(parent, pair) { self ->
valueArguments.mapNotNull {
it.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) }
}
}
}
private fun makeLightPsiNameValuePair(valueArgument: KtValueArgument) = KtLightPsiNameValuePair(valueArgument, this) { self ->
makeArrayInitializerIfExpected(self)
?: self.valueArgument.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) }
}
override fun getAttributes(): Array<PsiNameValuePair> = _attributes
}
override fun delete() = kotlinOrigin.delete()
override fun toString() = "@$qualifiedName"
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || other::class.java != this::class.java) return false
return kotlinOrigin == (other as KtLightAnnotationForSourceEntry).kotlinOrigin
}
override fun hashCode() = kotlinOrigin.hashCode()
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
}
class KtLightNonSourceAnnotation(
parent: PsiElement, clsDelegate: PsiAnnotation
) : KtLightAbstractAnnotation(parent, { clsDelegate }) {
override val kotlinOrigin: KtAnnotationEntry? get() = null
override fun getQualifiedName() = kotlinOrigin?.name ?: clsDelegate.qualifiedName
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
override fun findAttributeValue(attributeName: String?) = clsDelegate.findAttributeValue(attributeName)
override fun findDeclaredAttributeValue(attributeName: String?) = clsDelegate.findDeclaredAttributeValue(attributeName)
}
class KtLightNonExistentAnnotation(parent: KtLightElement<*, *>) : KtLightElementBase(parent), PsiAnnotation {
override val kotlinOrigin get() = null
override fun toString() = this.javaClass.name
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
override fun getNameReferenceElement() = null
override fun findAttributeValue(attributeName: String?) = null
override fun getQualifiedName() = null
override fun getOwner() = parent as? PsiAnnotationOwner
override fun findDeclaredAttributeValue(attributeName: String?) = null
override fun getMetaData() = null
override fun getParameterList() = KtLightEmptyAnnotationParameterList(this)
override fun canNavigate(): Boolean = super<KtLightElementBase>.canNavigate()
override fun canNavigateToSource(): Boolean = super<KtLightElementBase>.canNavigateToSource()
override fun navigate(requestFocus: Boolean) = super<KtLightElementBase>.navigate(requestFocus)
}
class KtLightEmptyAnnotationParameterList(parent: PsiElement) : KtLightElementBase(parent), PsiAnnotationParameterList {
override val kotlinOrigin get() = null
override fun getAttributes(): Array<PsiNameValuePair> = emptyArray()
}
open class KtLightNullabilityAnnotation<D : KtLightElement<*, PsiModifierListOwner>>(val member: D, parent: PsiElement) :
KtLightAbstractAnnotation(parent, {
// searching for last because nullability annotations are generated after backend generates source annotations
getClsNullabilityAnnotation(member) ?: KtLightNonExistentAnnotation(member)
}) {
override fun fqNameMatches(fqName: String): Boolean {
if (!isNullabilityAnnotation(fqName)) return false
return super.fqNameMatches(fqName)
}
override val kotlinOrigin get() = null
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
override fun findAttributeValue(attributeName: String?) = null
override fun getQualifiedName(): String? {
val annotatedElement = member.takeIf(::isFromSources)?.kotlinOrigin
?: // it is out of our hands
return getClsNullabilityAnnotation(member)?.qualifiedName
// all data-class generated members are not-null
if (annotatedElement is KtClass && annotatedElement.isData()) return NotNull::class.java.name
if (annotatedElement is KtParameter) {
if (annotatedElement.containingClassOrObject?.isAnnotation() == true) return null
}
// don't annotate property setters
if (annotatedElement is KtValVarKeywordOwner && member is KtLightMethod && member.returnType == PsiType.VOID) return null
val kotlinType = getTargetType(annotatedElement) ?: return null
if (KotlinBuiltIns.isPrimitiveType(kotlinType) && (annotatedElement as? KtParameter)?.isVarArg != true) {
// no need to annotate them explicitly except the case when overriding reference-type makes it non-primitive for Jvm
if (!(annotatedElement is KtCallableDeclaration && annotatedElement.hasModifier(KtTokens.OVERRIDE_KEYWORD))) return null
val overriddenDescriptors =
(annotatedElement.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, annotatedElement] as? CallableMemberDescriptor)?.overriddenDescriptors
if (overriddenDescriptors?.all { it.returnType == kotlinType } == true) return null
}
if (kotlinType.isUnit() && (annotatedElement !is KtValVarKeywordOwner)) return null // not annotate unit-functions
if (kotlinType.isTypeParameter()) {
if (!TypeUtils.hasNullableSuperType(kotlinType)) return NotNull::class.java.name
if (!kotlinType.isMarkedNullable) return null
}
val nullability = kotlinType.nullability()
return when (nullability) {
TypeNullability.NOT_NULL -> NotNull::class.java.name
TypeNullability.NULLABLE -> Nullable::class.java.name
TypeNullability.FLEXIBLE -> null
}
}
internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this]
private fun getTargetType(annotatedElement: PsiElement): KotlinType? {
if (annotatedElement is KtTypeReference) {
annotatedElement.getType()?.let { return it }
}
if (annotatedElement is KtCallableDeclaration) {
annotatedElement.typeReference?.getType()?.let { return it }
}
if (annotatedElement is KtNamedFunction) {
annotatedElement.bodyExpression?.let { it.getType(it.analyze()) }?.let { return it }
}
if (annotatedElement is KtProperty) {
annotatedElement.initializer?.let { it.getType(it.analyze()) }?.let { return it }
annotatedElement.delegateExpression?.let { it.getType(it.analyze())?.arguments?.firstOrNull()?.type }?.let { return it }
}
annotatedElement.getParentOfType<KtProperty>(false)?.let {
it.typeReference?.getType() ?: it.initializer?.let { it.getType(it.analyze()) }
}?.let { return it }
return null
}
override fun getNameReferenceElement(): PsiJavaCodeReferenceElement? = null
override fun getParameterList(): PsiAnnotationParameterList = KtLightEmptyAnnotationParameterList(this)
override fun findDeclaredAttributeValue(attributeName: String?) = null
}
private fun getClsNullabilityAnnotation(member: KtLightElement<*, PsiModifierListOwner>): PsiAnnotation? {
if (!accessAnnotationsClsDelegateIsAllowed && ApplicationManager.getApplication().isUnitTestMode && isFromSources(member) && member.kotlinOrigin != null)
LOG.error("nullability should be retrieved from `kotlinOrigin`")
return member.clsDelegate.modifierList?.annotations?.findLast {
isNullabilityAnnotation(it.qualifiedName)
}
}
internal fun isNullabilityAnnotation(qualifiedName: String?) = qualifiedName in backendNullabilityAnnotations
private val backendNullabilityAnnotations = arrayOf(Nullable::class.java.name, NotNull::class.java.name)
private fun KtElement.analyze(): BindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(this)
private fun KtElement.getResolvedCall(): ResolvedCall<out CallableDescriptor>? {
if (!isValid) return null
val context = analyze()
return this.getResolvedCall(context)
}
fun convertToLightAnnotationMemberValue(lightParent: PsiElement, argument: KtExpression): PsiAnnotationMemberValue {
val argument = unwrapCall(argument)
when (argument) {
is KtClassLiteralExpression -> {
return KtLightPsiClassObjectAccessExpression(argument, lightParent)
}
is KtStringTemplateExpression, is KtConstantExpression -> {
return KtLightPsiLiteral(argument, lightParent)
}
is KtCallExpression -> {
val arguments = argument.valueArguments
val annotationName = argument.calleeExpression?.let { getAnnotationName(it) }
if (annotationName != null) {
return KtLightAnnotationForSourceEntry(
annotationName,
argument,
lightParent,
{ throw UnsupportedOperationException("cls delegate is not supported for nested annotations") })
}
val resolvedCall = argument.getResolvedCall()
if (resolvedCall != null && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall))
return KtLightPsiArrayInitializerMemberValue(
argument,
lightParent,
{ self ->
arguments.mapNotNull {
it.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) }
}
})
}
is KtCollectionLiteralExpression -> {
val arguments = argument.getInnerExpressions()
if (arguments.isNotEmpty())
return KtLightPsiArrayInitializerMemberValue(
argument,
lightParent,
{ self -> arguments.mapNotNull { convertToLightAnnotationMemberValue(self, it) } })
}
}
// everything else (like complex constant references) considered as PsiLiteral-s
return KtLightPsiLiteral(argument, lightParent)
}
private val KtExpression.nameReference: KtNameReferenceExpression?
get() = when {
this is KtConstructorCalleeExpression -> constructorReferenceExpression as? KtNameReferenceExpression
else -> this as? KtNameReferenceExpression
}
private fun unwrapCall(callee: KtExpression): KtExpression = when (callee) {
is KtDotQualifiedExpression -> callee.lastChild as? KtCallExpression ?: callee
else -> callee
}
private fun getAnnotationName(callee: KtExpression): String? {
val callee = unwrapCall(callee)
val resultingDescriptor = callee.getResolvedCall()?.resultingDescriptor
if (resultingDescriptor is ClassConstructorDescriptor) {
val ktClass = resultingDescriptor.constructedClass.source.getPsi() as? KtClass
if (ktClass?.isAnnotation() == true) return ktClass.fqName?.toString()
}
if (resultingDescriptor is JavaClassConstructorDescriptor) {
val psiClass = resultingDescriptor.constructedClass.source.getPsi() as? PsiClass
if (psiClass?.isAnnotationType == true) return psiClass.qualifiedName
}
return null
}
@TestOnly
var accessAnnotationsClsDelegateIsAllowed = false
@TestOnly
fun <T> withAllowedAnnotationsClsDelegate(body: () -> T): T {
val prev = accessAnnotationsClsDelegateIsAllowed
try {
accessAnnotationsClsDelegateIsAllowed = true
return body()
} finally {
accessAnnotationsClsDelegateIsAllowed = prev
}
}
@@ -1,49 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
testCompile(project(":core:descriptors"))
testCompile(project(":core:descriptors.jvm"))
testCompile(project(":core:deserialization"))
testCompile(project(":compiler:util"))
testCompile(project(":compiler:backend"))
testCompile(project(":compiler:fir:tree"))
testCompile(project(":compiler:fir:psi2fir"))
testCompile(project(":compiler:fir:cones"))
testCompile(project(":compiler:fir:resolve"))
testCompile(project(":compiler:fir:java"))
testCompile(project(":compiler:ir.ir2cfg"))
testCompile(project(":compiler:frontend"))
testCompile(project(":compiler:frontend.java"))
testCompile(project(":compiler:util"))
testCompile(project(":compiler:cli-common"))
testCompile(project(":compiler:cli"))
testCompile(project(":compiler:light-classes"))
testCompile(project(":compiler:serialization"))
testCompile(project(":kotlin-preloader"))
testCompile(project(":compiler:daemon-common"))
testCompile(project(":js:js.serializer"))
testCompile(project(":js:js.frontend"))
testCompile(project(":js:js.translator"))
testCompileOnly(project(":plugins:android-extensions-compiler"))
testCompile(project(":kotlin-test:kotlin-test-jvm"))
testCompile(projectTests(":compiler:tests-common-jvm6"))
testCompileOnly(project(":kotlin-reflect-api"))
testCompile(commonDep("junit:junit"))
testCompile(androidDxJar()) { isTransitive = false }
testCompileOnly(intellijCoreDep()) { includeJars("intellij-core") }
testCompile(intellijDep()) {
includeJars("openapi", "idea", "idea_rt", "guava", "trove4j", "picocontainer", "asm-all", "log4j", "jdom", "annotations", rootProject = rootProject)
isTransitive = false
}
}
sourceSets {
"main" { }
"test" { projectDefault() }
}
testsJar {}
File diff suppressed because it is too large Load Diff
@@ -1,337 +0,0 @@
/*
* Copyright 2000-2016 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.test.testFramework;
import com.intellij.core.CoreASTFactory;
import com.intellij.lang.*;
import com.intellij.lang.impl.PsiBuilderFactoryImpl;
import com.intellij.mock.*;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.fileTypes.FileTypeFactory;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.impl.CoreProgressManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.pom.PomModel;
import com.intellij.pom.core.impl.PomModelImpl;
import com.intellij.pom.tree.TreeAspect;
import com.intellij.psi.*;
import com.intellij.psi.impl.*;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistryImpl;
import com.intellij.psi.impl.source.text.BlockSupportImpl;
import com.intellij.psi.impl.source.text.DiffLog;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.testFramework.TestDataFile;
import com.intellij.util.CachedValuesManagerImpl;
import com.intellij.util.Function;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusFactory;
import junit.framework.TestCase;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.picocontainer.ComponentAdapter;
import org.picocontainer.MutablePicoContainer;
import java.io.File;
import java.io.IOException;
import java.util.Set;
@SuppressWarnings("ALL")
public abstract class KtParsingTestCase extends KtPlatformLiteFixture {
public static final Key<Document> HARD_REF_TO_DOCUMENT_KEY = Key.create("HARD_REF_TO_DOCUMENT_KEY");
protected String myFilePrefix = "";
protected String myFileExt;
protected final String myFullDataPath;
protected PsiFile myFile;
private MockPsiManager myPsiManager;
private PsiFileFactoryImpl myFileFactory;
protected Language myLanguage;
private final ParserDefinition[] myDefinitions;
private final boolean myLowercaseFirstLetter;
protected KtParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt, @NotNull ParserDefinition... definitions) {
this(dataPath, fileExt, false, definitions);
}
protected KtParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt, boolean lowercaseFirstLetter, @NotNull ParserDefinition... definitions) {
myDefinitions = definitions;
myFullDataPath = getTestDataPath() + "/" + dataPath;
myFileExt = fileExt;
myLowercaseFirstLetter = lowercaseFirstLetter;
}
@Override
protected void setUp() throws Exception {
super.setUp();
initApplication();
ComponentAdapter component = getApplication().getPicoContainer().getComponentAdapter(ProgressManager.class.getName());
Extensions.registerAreaClass("IDEA_PROJECT", null);
myProject = new MockProjectEx(getTestRootDisposable());
myPsiManager = new MockPsiManager(myProject);
myFileFactory = new PsiFileFactoryImpl(myPsiManager);
MutablePicoContainer appContainer = getApplication().getPicoContainer();
registerComponentInstance(appContainer, MessageBus.class, MessageBusFactory.newMessageBus(getApplication()));
final MockEditorFactory editorFactory = new MockEditorFactory();
registerComponentInstance(appContainer, EditorFactory.class, editorFactory);
registerComponentInstance(appContainer, FileDocumentManager.class, new MockFileDocumentManagerImpl(new Function<CharSequence, Document>() {
@Override
public Document fun(CharSequence charSequence) {
return editorFactory.createDocument(charSequence);
}
}, HARD_REF_TO_DOCUMENT_KEY));
registerComponentInstance(appContainer, PsiDocumentManager.class, new MockPsiDocumentManager());
registerApplicationService(PsiBuilderFactory.class, new PsiBuilderFactoryImpl());
registerApplicationService(DefaultASTFactory.class, new CoreASTFactory());
registerApplicationService(ReferenceProvidersRegistry.class, new ReferenceProvidersRegistryImpl());
registerApplicationService(ProgressManager.class, new CoreProgressManager());
myProject.registerService(CachedValuesManager.class, new CachedValuesManagerImpl(myProject, new PsiCachedValuesFactory(myPsiManager)));
myProject.registerService(PsiManager.class, myPsiManager);
this.registerExtensionPoint(FileTypeFactory.FILE_TYPE_FACTORY_EP, FileTypeFactory.class);
registerExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
for (ParserDefinition definition : myDefinitions) {
addExplicitExtension(LanguageParserDefinitions.INSTANCE, definition.getFileNodeType().getLanguage(), definition);
}
if (myDefinitions.length > 0) {
configureFromParserDefinition(myDefinitions[0], myFileExt);
}
// That's for reparse routines
final PomModelImpl pomModel = new PomModelImpl(myProject);
myProject.registerService(PomModel.class, pomModel);
new TreeAspect(pomModel);
}
public void configureFromParserDefinition(ParserDefinition definition, String extension) {
myLanguage = definition.getFileNodeType().getLanguage();
myFileExt = extension;
addExplicitExtension(LanguageParserDefinitions.INSTANCE, this.myLanguage, definition);
registerComponentInstance(
getApplication().getPicoContainer(), FileTypeManager.class,
new MockFileTypeManager(new MockLanguageFileType(myLanguage, myFileExt)));
}
protected <T> void addExplicitExtension(final LanguageExtension<T> instance, final Language language, final T object) {
instance.addExplicitExtension(language, object);
Disposer.register(myProject, new Disposable() {
@Override
public void dispose() {
instance.removeExplicitExtension(language, object);
}
});
}
@Override
protected <T> void registerExtensionPoint(final ExtensionPointName<T> extensionPointName, Class<T> aClass) {
super.registerExtensionPoint(extensionPointName, aClass);
Disposer.register(myProject, new Disposable() {
@Override
public void dispose() {
Extensions.getRootArea().unregisterExtensionPoint(extensionPointName.getName());
}
});
}
protected <T> void registerApplicationService(final Class<T> aClass, T object) {
getApplication().registerService(aClass, object);
Disposer.register(myProject, new Disposable() {
@Override
public void dispose() {
getApplication().getPicoContainer().unregisterComponent(aClass.getName());
}
});
}
public MockProjectEx getProject() {
return myProject;
}
public MockPsiManager getPsiManager() {
return myPsiManager;
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
myFile = null;
myProject = null;
myPsiManager = null;
}
protected String getTestDataPath() {
return PathManager.getHomePath();
}
@NotNull
public final String getTestName() {
return getTestName(myLowercaseFirstLetter);
}
protected boolean includeRanges() {
return false;
}
protected boolean skipSpaces() {
return false;
}
protected boolean checkAllPsiRoots() {
return true;
}
protected void doTest(boolean checkResult) {
String name = getTestName();
try {
String text = loadFile(name + "." + myFileExt);
myFile = createPsiFile(name, text);
ensureParsed(myFile);
assertEquals("light virtual file text mismatch", text, ((LightVirtualFile)myFile.getVirtualFile()).getContent().toString());
assertEquals("virtual file text mismatch", text, LoadTextUtil.loadText(myFile.getVirtualFile()));
assertEquals("doc text mismatch", text, myFile.getViewProvider().getDocument().getText());
assertEquals("psi text mismatch", text, myFile.getText());
ensureCorrectReparse(myFile);
if (checkResult){
checkResult(name, myFile);
}
else{
toParseTreeText(myFile, skipSpaces(), includeRanges());
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
protected void doTest(String suffix) throws IOException {
String name = getTestName();
String text = loadFile(name + "." + myFileExt);
myFile = createPsiFile(name, text);
ensureParsed(myFile);
assertEquals(text, myFile.getText());
checkResult(name + suffix, myFile);
}
protected void doCodeTest(String code) throws IOException {
String name = getTestName();
myFile = createPsiFile("a", code);
ensureParsed(myFile);
assertEquals(code, myFile.getText());
checkResult(myFilePrefix + name, myFile);
}
protected PsiFile createPsiFile(String name, String text) {
return createFile(name + "." + myFileExt, text);
}
protected PsiFile createFile(@NonNls String name, String text) {
LightVirtualFile virtualFile = new LightVirtualFile(name, myLanguage, text);
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET);
return createFile(virtualFile);
}
protected PsiFile createFile(LightVirtualFile virtualFile) {
return myFileFactory.trySetupPsiForFile(virtualFile, myLanguage, true, false);
}
protected void checkResult(@NonNls @TestDataFile String targetDataName, final PsiFile file) throws IOException {
doCheckResult(myFullDataPath, file, checkAllPsiRoots(), targetDataName, skipSpaces(), includeRanges());
}
public static void doCheckResult(String testDataDir,
PsiFile file,
boolean checkAllPsiRoots,
String targetDataName,
boolean skipSpaces,
boolean printRanges) throws IOException {
FileViewProvider provider = file.getViewProvider();
Set<Language> languages = provider.getLanguages();
if (!checkAllPsiRoots || languages.size() == 1) {
doCheckResult(testDataDir, targetDataName + ".txt", toParseTreeText(file, skipSpaces, printRanges).trim());
return;
}
for (Language language : languages) {
PsiFile root = provider.getPsi(language);
String expectedName = targetDataName + "." + language.getID() + ".txt";
doCheckResult(testDataDir, expectedName, toParseTreeText(root, skipSpaces, printRanges).trim());
}
}
protected void checkResult(String actual) throws IOException {
String name = getTestName();
doCheckResult(myFullDataPath, myFilePrefix + name + ".txt", actual);
}
protected void checkResult(@TestDataFile @NonNls String targetDataName, String actual) throws IOException {
doCheckResult(myFullDataPath, targetDataName, actual);
}
public static void doCheckResult(String fullPath, String targetDataName, String actual) throws IOException {
String expectedFileName = fullPath + File.separatorChar + targetDataName;
KtUsefulTestCase.assertSameLinesWithFile(expectedFileName, actual);
}
protected static String toParseTreeText(PsiElement file, boolean skipSpaces, boolean printRanges) {
return DebugUtil.psiToString(file, skipSpaces, printRanges);
}
protected String loadFile(@NonNls @TestDataFile String name) throws IOException {
return loadFileDefault(myFullDataPath, name);
}
public static String loadFileDefault(String dir, String name) throws IOException {
return FileUtil.loadFile(new File(dir, name), CharsetToolkit.UTF8, true).trim();
}
public static void ensureParsed(PsiFile file) {
file.accept(new PsiElementVisitor() {
@Override
public void visitElement(PsiElement element) {
element.acceptChildren(this);
}
});
}
public static void ensureCorrectReparse(@NotNull PsiFile file) {
String psiToStringDefault = DebugUtil.psiToString(file, false, false);
String fileText = file.getText();
DiffLog diffLog = (new BlockSupportImpl(file.getProject())).reparseRange(
file, file.getNode(), TextRange.allOf(fileText), fileText, new EmptyProgressIndicator(), fileText);
diffLog.performActualPsiChange(file);
TestCase.assertEquals(psiToStringDefault, DebugUtil.psiToString(file, false, false));
}
}
-13
View File
@@ -1,13 +0,0 @@
versions.intellijSdk=173.4674.33
versions.androidBuildTools=r23.0.1
versions.idea.NodeJS=172.3757.32
versions.jar.guava=21.0
versions.jar.groovy-all=2.4.12
versions.jar.lombok-ast=0.2.3
versions.jar.swingx-core=1.6.2
versions.jar.kxml2=2.3.0
versions.jar.streamex=0.6.5
versions.jar.gson=2.8.2
versions.jar.snappy-in-java=0.5.1
ignore.jar.lombok-ast-0.2.3=true
versions.gradle-api=4.0
@@ -1,18 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.core.formatter
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import com.intellij.psi.codeStyle.CommonCodeStyleSettingsManager
/**
* Method copyFrom is absent in 173.
* BUNCH: 181
*/
fun CommonCodeStyleSettings.copyFromEx(source: CommonCodeStyleSettings) {
@Suppress("IncompatibleAPI")
CommonCodeStyleSettingsManager.copy(source, this)
}
@@ -1,27 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.caches
import com.intellij.psi.search.PsiShortNamesCache
typealias PsiShortNamesCacheWrapper = PsiShortNamesCacheCompatibility
// Need to implement deprecated methods. Should be removed after abandoning 173 and AS 3.1 branch.
// BUNCH: 181
@Suppress("OverridingDeprecatedMember", "DEPRECATION")
abstract class PsiShortNamesCacheCompatibility : PsiShortNamesCache() {
override fun getAllClassNames(dest: com.intellij.util.containers.HashSet<String>) {
processAllClassNames(com.intellij.util.CommonProcessors.CollectProcessor(dest))
}
override fun getAllMethodNames(set: com.intellij.util.containers.HashSet<String>) {
java.util.Collections.addAll(set, *allMethodNames)
}
override fun getAllFieldNames(set: com.intellij.util.containers.HashSet<String>) {
java.util.Collections.addAll(set, *allFieldNames)
}
}
@@ -1,135 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android
import com.android.SdkConstants
import com.android.resources.ResourceType
import com.intellij.codeHighlighting.Pass
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler
import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.codeInsight.daemon.LineMarkerProvider
import com.intellij.codeInsight.navigation.NavigationUtil
import com.intellij.icons.AllIcons
import com.intellij.ide.highlighter.XmlFileType
import com.intellij.navigation.GotoRelatedItem
import com.intellij.openapi.editor.markup.GutterIconRenderer
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.xml.XmlAttributeValue
import com.intellij.ui.awt.RelativePoint
import com.intellij.util.Function
import org.jetbrains.android.dom.manifest.Manifest
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import java.awt.event.MouseEvent
import javax.swing.Icon
class KotlinAndroidLineMarkerProvider : LineMarkerProvider {
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? = null
override fun collectSlowLineMarkers(elements: List<PsiElement>, result: MutableCollection<LineMarkerInfo<PsiElement>>) {
elements.forEach {
(it as? KtClass)?.getLineMarkerInfo()?.let { marker -> result.add(marker) }
}
}
private fun KtClass.getLineMarkerInfo(): LineMarkerInfo<PsiElement>? {
val nameIdentifier = nameIdentifier ?: return null
val androidFacet = AndroidFacet.getInstance(this) ?: return null
val manifest = androidFacet.manifest ?: return null
val manifestItems = collectGoToRelatedManifestItems(manifest)
if (manifestItems.isEmpty() && !isClassWithLayoutXml()) {
return null
}
return LineMarkerInfo(
nameIdentifier,
nameIdentifier.textRange,
AllIcons.FileTypes.Xml,
Pass.LINE_MARKERS,
Function { "Related XML file" },
GutterIconNavigationHandler { e: MouseEvent, _: PsiElement ->
NavigationUtil
.getRelatedItemsPopup(
manifestItems + collectGoToRelatedLayoutItems(androidFacet),
"Go to Related Files")
.show(RelativePoint(e))
},
GutterIconRenderer.Alignment.RIGHT)
}
private fun KtClass.collectGoToRelatedLayoutItems(androidFacet: AndroidFacet): List<GotoRelatedItem> {
val resources = mutableSetOf<PsiFile>()
accept(object: KtVisitorVoid() {
override fun visitKtElement(element: KtElement) {
element.acceptChildren(this)
}
override fun visitReferenceExpression(expression: KtReferenceExpression) {
super.visitReferenceExpression(expression)
val resClassName = ResourceType.LAYOUT.getName()
val info = (expression as? KtSimpleNameExpression)?.let {
getReferredResourceOrManifestField(androidFacet, it, resClassName, true)
}
if (info == null || info.isFromManifest) {
return
}
val files = androidFacet
.localResourceManager
.findResourcesByFieldName(resClassName, info.fieldName)
.filterIsInstance<PsiFile>()
resources.addAll(files)
}
})
return resources.map { GotoRelatedLayoutItem(it) }
}
private fun KtClass.collectGoToRelatedManifestItems(manifest: Manifest): List<GotoRelatedItem> =
findComponentDeclarationInManifest(manifest)?.xmlAttributeValue?.let { listOf(GotoManifestItem(it)) } ?: emptyList()
private class GotoManifestItem(attributeValue: XmlAttributeValue) : GotoRelatedItem(attributeValue) {
override fun getCustomName(): String? = "AndroidManifest.xml"
override fun getCustomContainerName(): String? = ""
override fun getCustomIcon(): Icon? = XmlFileType.INSTANCE.icon
}
private class GotoRelatedLayoutItem(private val file: PsiFile) : GotoRelatedItem(file, "Layout Files") {
override fun getCustomContainerName(): String? = "(${file.containingDirectory.name})"
}
companion object {
private val CLASSES_WITH_LAYOUT_XML = arrayOf(
SdkConstants.CLASS_ACTIVITY,
SdkConstants.CLASS_FRAGMENT,
SdkConstants.CLASS_V4_FRAGMENT,
"android.widget.Adapter")
private fun KtClass.isClassWithLayoutXml(): Boolean {
val type = (unsafeResolveToDescriptor(BodyResolveMode.PARTIAL) as? ClassDescriptor)?.defaultType ?: return false
return CLASSES_WITH_LAYOUT_XML.any { type.isSubclassOf(it, true) }
}
}
}
@@ -1,270 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.resources.ResourceItem;
import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.common.resources.ResourceResolver;
import com.android.resources.ResourceType;
import com.android.tools.idea.configurations.Configuration;
import com.android.tools.idea.res.AppResourceRepository;
import com.android.tools.idea.res.LocalResourceRepository;
import com.android.tools.idea.res.ResourceHelper;
import com.android.tools.idea.ui.resourcechooser.ColorPicker;
import com.android.utils.XmlUtils;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ui.ColorIcon;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.JBUI;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import static com.android.SdkConstants.*;
import static com.android.SdkConstants.ANDROID_URI;
import static com.android.SdkConstants.ATTR_DRAWABLE;
import static com.android.tools.idea.uibuilder.property.renderer.NlDefaultRenderer.ICON_SIZE;
import static org.jetbrains.android.AndroidColorAnnotator.pickLayoutFile;
/**
* Contains copied privates from AndroidColorAnnotator, so we could use them for Kotlin AndroidResourceReferenceAnnotator
*/
public class ResourceReferenceAnnotatorUtil {
@Nullable
public static File pickBitmapFromXml(@NotNull File file, @NotNull ResourceResolver resourceResolver, @NotNull Project project) {
try {
String xml = Files.toString(file, Charsets.UTF_8);
Document document = XmlUtils.parseDocumentSilently(xml, true);
if (document != null && document.getDocumentElement() != null) {
Element root = document.getDocumentElement();
String tag = root.getTagName();
Element target = null;
String attribute = null;
if ("vector".equals(tag)) {
// Vectors are handled in the icon cache
return file;
}
else if ("bitmap".equals(tag) || "nine-patch".equals(tag)) {
target = root;
attribute = ATTR_SRC;
}
else if ("selector".equals(tag) ||
"level-list".equals(tag) ||
"layer-list".equals(tag) ||
"transition".equals(tag)) {
NodeList children = root.getChildNodes();
for (int i = children.getLength() - 1; i >= 0; i--) {
Node item = children.item(i);
if (item.getNodeType() == Node.ELEMENT_NODE && TAG_ITEM.equals(item.getNodeName())) {
target = (Element)item;
if (target.hasAttributeNS(ANDROID_URI, ATTR_DRAWABLE)) {
attribute = ATTR_DRAWABLE;
break;
}
}
}
}
else if ("clip".equals(tag) || "inset".equals(tag) || "scale".equals(tag)) {
target = root;
attribute = ATTR_DRAWABLE;
} else {
// <shape> etc - no bitmap to be found
return null;
}
if (attribute != null && target.hasAttributeNS(ANDROID_URI, attribute)) {
String src = target.getAttributeNS(ANDROID_URI, attribute);
ResourceValue value = resourceResolver.findResValue(src, false);
if (value != null) {
return ResourceHelper.resolveDrawable(resourceResolver, value, project);
}
}
}
} catch (Throwable ignore) {
// Not logging for now; afraid to risk unexpected crashes in upcoming preview. TODO: Re-enable.
//Logger.getInstance(AndroidColorAnnotator.class).warn(String.format("Could not read/render icon image %1$s", file), e);
}
return null;
}
/** Looks up the resource item of the given type and name for the given configuration, if any */
@Nullable
public static ResourceValue findResourceValue(ResourceType type,
String name,
boolean isFramework,
Module module,
Configuration configuration) {
if (isFramework) {
ResourceRepository frameworkResources = configuration.getFrameworkResources();
if (frameworkResources == null) {
return null;
}
if (!frameworkResources.hasResourceItem(type, name)) {
return null;
}
ResourceItem item = frameworkResources.getResourceItem(type, name);
return item.getResourceValue(type, configuration.getFullConfig(), false);
} else {
LocalResourceRepository appResources = AppResourceRepository.getAppResources(module, true);
if (appResources == null) {
return null;
}
if (!appResources.hasResourceItem(type, name)) {
return null;
}
return appResources.getConfiguredValue(type, name, configuration.getFullConfig());
}
}
/** Picks a suitable configuration to use for resource resolution */
@Nullable
public static Configuration pickConfiguration(AndroidFacet facet, Module module, PsiFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) {
return null;
}
VirtualFile parent = virtualFile.getParent();
if (parent == null) {
return null;
}
VirtualFile layout;
String parentName = parent.getName();
if (!parentName.startsWith(FD_RES_LAYOUT)) {
layout = pickLayoutFile(module, facet);
if (layout == null) {
return null;
}
} else {
layout = virtualFile;
}
return facet.getConfigurationManager().getConfiguration(layout);
}
public static class ColorRenderer extends GutterIconRenderer {
private final PsiElement myElement;
private final Color myColor;
ColorRenderer(@NotNull PsiElement element, @Nullable Color color) {
myElement = element;
myColor = color;
}
@NotNull
@Override
public Icon getIcon() {
Color color = getCurrentColor();
return JBUI.scale(color == null ? EmptyIcon.create(ICON_SIZE) : new ColorIcon(ICON_SIZE, color));
}
@Nullable
private Color getCurrentColor() {
if (myColor != null) {
return myColor;
} else if (myElement instanceof XmlTag) {
return ResourceHelper.parseColor(((XmlTag)myElement).getValue().getText());
} else if (myElement instanceof XmlAttributeValue) {
return ResourceHelper.parseColor(((XmlAttributeValue)myElement).getValue());
} else {
return null;
}
}
@Override
public AnAction getClickAction() {
if (myColor != null) { // Cannot set colors that were derived
return null;
}
return new AnAction() {
@Override
public void actionPerformed(AnActionEvent e) {
final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
if (editor != null) {
// Need ARGB support in platform color chooser; see
// https://youtrack.jetbrains.com/issue/IDEA-123498
//final Color color =
// ColorChooser.chooseColor(editor.getComponent(), AndroidBundle.message("android.choose.color"), getCurrentColor());
final Color color = ColorPicker.showDialog(editor.getComponent(), "Choose Color", getCurrentColor(), true, null, false);
if (color != null) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
if (myElement instanceof XmlTag) {
((XmlTag)myElement).getValue().setText(ResourceHelper.colorToString(color));
} else if (myElement instanceof XmlAttributeValue) {
XmlAttribute attribute = PsiTreeUtil.getParentOfType(myElement, XmlAttribute.class);
if (attribute != null) {
attribute.setValue(ResourceHelper.colorToString(color));
}
}
}
});
}
}
}
};
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ColorRenderer that = (ColorRenderer)o;
// TODO: Compare with modification count in app resources (if not framework)
if (myColor != null ? !myColor.equals(that.myColor) : that.myColor != null) return false;
if (!myElement.equals(that.myElement)) return false;
return true;
}
@Override
public int hashCode() {
int result = myElement.hashCode();
result = 31 * result + (myColor != null ? myColor.hashCode() : 0);
return result;
}
}
}
@@ -1,133 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.util.FilePaths
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.externalSystem.ExternalSystemModulePropertyManager
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDataService.CREATE_EMPTY_DIRECTORIES
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.util.containers.stream
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.gradle.KotlinCompilation
import org.jetbrains.kotlin.gradle.KotlinPlatform
import org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler
import org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService
import org.jetbrains.kotlin.idea.configuration.kotlinAndroidSourceSets
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import java.io.File
import java.io.IOException
class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<ModuleData, Void>() {
override fun getTargetDataKey() = ProjectKeys.MODULE
private fun shouldCreateEmptySourceRoots(
moduleDataNode: DataNode<ModuleData>,
module: Module
): Boolean {
val projectDataNode = ExternalSystemApiUtil.findParent(moduleDataNode, ProjectKeys.PROJECT) ?: return false
if (projectDataNode.getUserData<Boolean>(CREATE_EMPTY_DIRECTORIES) == true) return true
val projectSystemId = projectDataNode.data.owner
val externalSystemSettings = ExternalSystemApiUtil.getSettings(module.project, projectSystemId)
val path = ExternalSystemModulePropertyManager.getInstance(module).getRootProjectPath() ?: return false
return externalSystemSettings.getLinkedProjectSettings(path)?.isCreateEmptyContentRootDirectories ?: false
}
override fun postProcess(
toImport: MutableCollection<DataNode<ModuleData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (nodeToImport in toImport) {
val projectNode = ExternalSystemApiUtil.findParent(nodeToImport, ProjectKeys.PROJECT) ?: continue
val moduleData = nodeToImport.data
val module = modelsProvider.findIdeModule(moduleData) ?: continue
val shouldCreateEmptySourceRoots = shouldCreateEmptySourceRoots(nodeToImport, module)
val rootModel = modelsProvider.getModifiableRootModel(module)
val kotlinAndroidSourceSets = nodeToImport.kotlinAndroidSourceSets ?: continue
for (sourceSetInfo in kotlinAndroidSourceSets) {
val compilation = sourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
for (sourceSet in compilation.sourceSets) {
if (sourceSet.platform == KotlinPlatform.ANDROID) {
val sourceType = if (sourceSet.isTestModule) JavaSourceRootType.TEST_SOURCE else JavaSourceRootType.SOURCE
val resourceType = if (sourceSet.isTestModule) JavaResourceRootType.TEST_RESOURCE else JavaResourceRootType.RESOURCE
sourceSet.sourceDirs.forEach { addSourceRoot(it, sourceType, rootModel, shouldCreateEmptySourceRoots) }
sourceSet.resourceDirs.forEach { addSourceRoot(it, resourceType, rootModel, shouldCreateEmptySourceRoots) }
}
}
}
val androidModel = module.getAndroidModel(modelsProvider) ?: continue
val variantName = androidModel.selectedVariant.name
val activeSourceSetInfos = nodeToImport.kotlinAndroidSourceSets?.filter { it.kotlinModule.name.startsWith(variantName) } ?: emptyList()
for (activeSourceSetInfo in activeSourceSetInfos) {
val activeCompilation = activeSourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
for (sourceSet in activeCompilation.sourceSets) {
if (sourceSet.platform != KotlinPlatform.ANDROID) {
val sourceSetId = activeSourceSetInfo.sourceSetIdsByName[sourceSet.name] ?: continue
val sourceSetData = ExternalSystemApiUtil.findFirstRecursively(projectNode) {
(it.data as? ModuleData)?.id == sourceSetId
}?.data as? ModuleData ?: continue
val sourceSetModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
val existingEntry = rootModel.findModuleOrderEntry(sourceSetModule)
val dependencyScope = if (activeSourceSetInfo.isTestModule) DependencyScope.TEST else DependencyScope.COMPILE
if (existingEntry != null && existingEntry.scope == dependencyScope) continue
rootModel.addModuleOrderEntry(sourceSetModule).also { it.scope = dependencyScope }
}
}
}
val mainSourceSetInfo = activeSourceSetInfos.firstOrNull { it.kotlinModule.name == variantName }
if (mainSourceSetInfo != null) {
KotlinSourceSetDataService.configureFacet(moduleData, mainSourceSetInfo, nodeToImport, module, modelsProvider)
}
val kotlinFacet = KotlinFacet.get(module)
if (kotlinFacet != null) {
GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, nodeToImport) }
}
}
}
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
rootModel: ModifiableRootModel,
shouldCreateEmptySourceRoots: Boolean
) {
val parent = FilePaths.findParentContentEntry(sourceRoot, rootModel.contentEntries) ?: return
val url = FilePaths.pathToIdeaUrl(sourceRoot)
parent.addSourceFolder(url, type)
if (shouldCreateEmptySourceRoots) {
ExternalSystemApiUtil.doWriteAction {
try {
VfsUtil.createDirectoryIfMissing(sourceRoot.path)
} catch (e: IOException) {
LOG.warn(String.format("Unable to create directory for the path: %s", sourceRoot.path), e)
}
}
}
}
companion object {
private val LOG = Logger.getInstance(KotlinAndroidGradleMPPModuleDataService::class.java)
}
}
@@ -1,98 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.android.configure
import com.android.builder.model.AndroidProject
import com.android.builder.model.NativeAndroidProject
import com.android.tools.idea.IdeInfo
import com.android.tools.idea.gradle.ImportedModule
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys.IMPORTED_MODULE
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants
import com.intellij.openapi.externalSystem.util.Order
import org.gradle.tooling.model.idea.IdeaModule
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModelBuilder
import org.jetbrains.kotlin.gradle.KotlinPlatform
import org.jetbrains.kotlin.idea.configuration.KotlinAndroidSourceSetData
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
import org.jetbrains.kotlin.idea.configuration.kotlinSourceSet
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
@Order(ExternalSystemConstants.UNORDERED - 1)
class KotlinAndroidMPPGradleProjectResolver : AbstractProjectResolverExtension() {
private val isAndroidProject by lazy {
resolverCtx.hasModulesWithModel(AndroidProject::class.java)
|| resolverCtx.hasModulesWithModel(NativeAndroidProject::class.java)
}
override fun getToolingExtensionsClasses(): Set<Class<out Any>> {
return setOf(KotlinMPPGradleModelBuilder::class.java, Unit::class.java)
}
override fun getExtraProjectModelClasses(): Set<Class<out Any>> {
return setOf(KotlinMPPGradleModel::class.java)
}
override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData> {
return super.createModule(gradleModule, projectDataNode).also {
initializeModuleData(gradleModule, it, projectDataNode)
}
}
override fun populateModuleContentRoots(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
super.populateModuleContentRoots(gradleModule, ideModule)
if (IdeInfo.getInstance().isAndroidStudio || isAndroidProject) {
KotlinMPPGradleProjectResolver.populateContentRoots(gradleModule, ideModule, resolverCtx)
// Work around module disposal service which discards modules without accompanying ImportedModule instance
for (childNode in ExternalSystemApiUtil.getChildren(ideModule, GradleSourceSetData.KEY)) {
if (childNode.kotlinSourceSet == null) continue
val moduleName = childNode.data.internalName
val importedModule = ImportedModule(gradleModule)
importedModuleNameField.set(importedModule, moduleName)
ideModule.createChild(IMPORTED_MODULE, importedModule)
}
}
}
override fun populateModuleDependencies(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>, ideProject: DataNode<ProjectData>) {
super.populateModuleDependencies(gradleModule, ideModule, ideProject)
if (isAndroidProject) {
KotlinMPPGradleProjectResolver.populateModuleDependencies(gradleModule, ideProject, ideModule, resolverCtx)
}
}
private fun initializeModuleData(
gradleModule: IdeaModule,
mainModuleData: DataNode<ModuleData>,
projectDataNode: DataNode<ProjectData>
) {
if (!isAndroidProject) return
KotlinMPPGradleProjectResolver.initializeModuleData(gradleModule, mainModuleData, projectDataNode, resolverCtx)
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) ?: return
val androidSourceSets = mppModel
.targets
.asSequence()
.flatMap { it.compilations.asSequence() }
.filter { it.platform == KotlinPlatform.ANDROID }
.mapNotNull { KotlinMPPGradleProjectResolver.createSourceSetInfo(it, gradleModule, resolverCtx) }
.toList()
mainModuleData.createChild(KotlinAndroidSourceSetData.KEY, KotlinAndroidSourceSetData(androidSourceSets))
}
companion object {
val importedModuleNameField by lazy {
ImportedModule::class.java.getDeclaredField("myName").apply { isAccessible = true }
}
}
}
@@ -1,66 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.debugger
import com.android.dx.cf.direct.DirectClassFile
import com.android.dx.cf.direct.StdAttributeFactory
import com.android.dx.dex.DexOptions
import com.android.dx.dex.cf.CfOptions
import com.android.dx.dex.cf.CfTranslator
import com.android.dx.dex.file.ClassDefItem
import com.android.dx.dex.file.DexFile
import com.intellij.ide.plugins.DynamicallyLoaded
import org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.ClassToLoad
import java.lang.reflect.Modifier
class AndroidDexWrapper {
@Suppress("unused") // Used in AndroidOClassLoadingAdapter#dex
fun dex(classes: Collection<ClassToLoad>): ByteArray? {
val dexOptions = DexOptions()
val cfOptions = CfOptions()
val dexFile = DexFile(dexOptions)
val methodWithContext = CfTranslator::class.java.declaredMethods
.singleOrNull { it.name == "translate" && Modifier.isStatic(it.modifiers) && it.parameterCount == 6 }
val dxContext = methodWithContext?.let { Class.forName("com.android.dx.command.dexer.DxContext").newInstance() }
for ((_, relativeFileName, bytes) in classes) {
val cf = DirectClassFile(bytes, relativeFileName, true)
cf.setAttributeFactory(StdAttributeFactory.THE_ONE)
val classDef = if (methodWithContext != null) {
methodWithContext(
null,
dxContext,
cf,
bytes,
cfOptions,
dexOptions,
dexFile
) as ClassDefItem
} else {
CfTranslator.translate(cf, bytes, cfOptions, dexOptions, dexFile)
}
dexFile.add(classDef)
}
return dexFile.toDex(null, false)
}
}
@@ -1,72 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.debugger
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.AndroidDexer
import org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.ClassToLoad
import java.io.File
import java.net.URLClassLoader
import java.security.ProtectionDomain
class AndroidDexerImpl(val project: Project) : AndroidDexer {
private val cachedDexWrapper = CachedValuesManager.getManager(project).createCachedValue({
val dexWrapper = doGetAndroidDexFile()?.let { dexJarFile ->
val androidDexWrapperName = AndroidDexWrapper::class.java.canonicalName
val classBytes = this.javaClass.classLoader.getResource(
androidDexWrapperName.replace('.', '/') + ".class").readBytes()
val dexClassLoader = object : URLClassLoader(arrayOf(dexJarFile.toURI().toURL()), this::class.java.classLoader) {
init {
defineClass(androidDexWrapperName, classBytes, 0, classBytes.size, null as ProtectionDomain?)
}
}
Class.forName(androidDexWrapperName, true, dexClassLoader).newInstance()
}
CachedValueProvider.Result.createSingleDependency(dexWrapper, ProjectRootModificationTracker.getInstance(project))
}, /* trackValue = */ false)
override fun dex(classes: Collection<ClassToLoad>): ByteArray? {
val dexWrapper = cachedDexWrapper.value
val dexMethod = dexWrapper::class.java.methods.firstOrNull { it.name == "dex" } ?: return null
return dexMethod.invoke(dexWrapper, classes) as? ByteArray ?: return null
}
private fun doGetAndroidDexFile(): File? {
for (module in ModuleManager.getInstance(project).modules) {
val androidFacet = AndroidFacet.getInstance(module) ?: continue
val sdkData = androidFacet.sdkData ?: continue
val latestBuildTool = sdkData.getLatestBuildTool(/* allowPreview = */ false)
?: sdkData.getLatestBuildTool(/* allowPreview = */ true)
?: continue
val dxJar = File(latestBuildTool.location, "lib/dx.jar")
if (dxJar.exists()) {
return dxJar
}
}
return null
}
}
@@ -1,259 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.folding
import com.android.SdkConstants.*
import com.android.ide.common.resources.configuration.FolderConfiguration
import com.android.ide.common.resources.configuration.LocaleQualifier
import com.android.resources.ResourceType
import com.android.tools.idea.folding.AndroidFoldingSettings
import com.android.tools.idea.res.AppResourceRepository
import com.android.tools.idea.res.LocalResourceRepository
import com.intellij.lang.ASTNode
import com.intellij.lang.folding.FoldingBuilderEx
import com.intellij.lang.folding.FoldingDescriptor
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.editor.Document
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.SourceTreeToPsiMap
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.uast.*
import org.jetbrains.uast.visitor.AbstractUastVisitor
import java.util.regex.Pattern
class ResourceFoldingBuilder : FoldingBuilderEx() {
companion object {
// See lint's StringFormatDetector
private val FORMAT = Pattern.compile("%(\\d+\\$)?([-+#, 0(<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])")
private val FOLD_MAX_LENGTH = 60
private val FORCE_PROJECT_RESOURCE_LOADING = true
private val UNIT_TEST_MODE: Boolean = ApplicationManager.getApplication().isUnitTestMode
private val RESOURCE_TYPES = listOf(ResourceType.STRING,
ResourceType.DIMEN,
ResourceType.INTEGER,
ResourceType.PLURALS)
}
private val isFoldingEnabled = AndroidFoldingSettings.getInstance().isCollapseAndroidStrings
override fun getPlaceholderText(node: ASTNode): String? {
tailrec fun UElement.unwrapReferenceAndGetValue(resources: LocalResourceRepository): String? = when (this) {
is UQualifiedReferenceExpression -> selector.unwrapReferenceAndGetValue(resources)
is UCallExpression -> (valueArguments.firstOrNull() as? UReferenceExpression)?.getAndroidResourceValue(resources, this)
else -> (this as? UReferenceExpression)?.getAndroidResourceValue(resources)
}
val element = SourceTreeToPsiMap.treeElementToPsi(node) ?: return null
val appResources = getAppResources(element) ?: return null
val uastContext = ServiceManager.getService(element.project, UastContext::class.java) ?: return null
return uastContext.convertElement(element, null, null)?.unwrapReferenceAndGetValue(appResources)
}
override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array<FoldingDescriptor> {
if (root !is KtFile || quick && !UNIT_TEST_MODE || !isFoldingEnabled || AndroidFacet.getInstance(root) == null) {
return emptyArray()
}
val file = root.toUElement()
val result = arrayListOf<FoldingDescriptor>()
file?.accept(object : AbstractUastVisitor() {
override fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression): Boolean {
node.getFoldingDescriptor()?.let { result.add(it) }
return super.visitSimpleNameReferenceExpression(node)
}
})
return result.toTypedArray()
}
override fun isCollapsedByDefault(node: ASTNode): Boolean = isFoldingEnabled
private fun UReferenceExpression.getFoldingDescriptor(): FoldingDescriptor? {
val resolved = resolve() ?: return null
val resourceType = resolved.getAndroidResourceType() ?: return null
if (resourceType !in RESOURCE_TYPES) return null
fun UElement.createFoldingDescriptor() = psi?.let { psi ->
val dependencies: Set<PsiElement> = setOf(psi)
FoldingDescriptor(psi.node, psi.textRange, null, dependencies)
}
val element = uastParent as? UQualifiedReferenceExpression ?: this
val getResourceValueCall = (element.uastParent as? UCallExpression)?.takeIf { it.isFoldableGetResourceValueCall() }
if (getResourceValueCall != null) {
val qualifiedCall = getResourceValueCall.uastParent as? UQualifiedReferenceExpression
if (qualifiedCall?.selector == getResourceValueCall) {
return qualifiedCall.createFoldingDescriptor()
}
return getResourceValueCall.createFoldingDescriptor()
}
return element.createFoldingDescriptor()
}
private fun UCallExpression.isFoldableGetResourceValueCall(): Boolean {
return methodName == "getString" ||
methodName == "getText" ||
methodName == "getInteger" ||
methodName?.startsWith("getDimension") ?: false ||
methodName?.startsWith("getQuantityString") ?: false
}
private fun PsiElement.getAndroidResourceType(): ResourceType? {
val elementType = parent as? PsiClass ?: return null
val elementPackage = elementType.parent as? PsiClass ?: return null
if (R_CLASS != elementPackage.name) return null
if (elementPackage.qualifiedName != "$ANDROID_PKG.$R_CLASS") {
return ResourceType.getEnum(elementType.name)
}
return null
}
private fun UReferenceExpression.getAndroidResourceValue(resources: LocalResourceRepository, call: UCallExpression? = null): String? {
val resourceType = resolve()?.getAndroidResourceType() ?: return null
val referenceConfig = FolderConfiguration().apply { localeQualifier = LocaleQualifier("xx") }
val key = resolvedName ?: return null
val resourceValue = resources.getResourceValue(resourceType, key, referenceConfig) ?: return null
val text = if (call != null) formatArguments(call, resourceValue) else resourceValue
if (resourceType == ResourceType.STRING || resourceType == ResourceType.PLURALS) {
return '"' + StringUtil.shortenTextWithEllipsis(text, FOLD_MAX_LENGTH - 2, 0) + '"'
}
else if (text.length <= 1) {
// Don't just inline empty or one-character replacements: they can't be expanded by a mouse click
// so are hard to use without knowing about the folding keyboard shortcut to toggle folding.
// This is similar to how IntelliJ 14 handles call parameters
return key + ": " + text
}
return StringUtil.shortenTextWithEllipsis(text, FOLD_MAX_LENGTH, 0)
}
private tailrec fun LocalResourceRepository.getResourceValue(
type: ResourceType,
name: String,
referenceConfig: FolderConfiguration): String? {
val value = getConfiguredValue(type, name, referenceConfig)?.value ?: return null
if (!value.startsWith('@')) {
return value
}
val (referencedTypeName, referencedName) = value.substring(1).split('/').takeIf { it.size == 2 } ?: return value
val referencedType = ResourceType.getEnum(referencedTypeName) ?: return value
return getResourceValue(referencedType, referencedName, referenceConfig)
}
// Converted from com.android.tools.idea.folding.InlinedResource#insertArguments
private fun formatArguments(callExpression: UCallExpression, formatString: String): String {
if (!formatString.contains('%')) {
return formatString
}
val args = callExpression.valueArguments
if (args.isEmpty() || !args.first().isPsiValid) {
return formatString
}
val matcher = FORMAT.matcher(formatString)
var index = 0
var prevIndex = 0
var nextNumber = 1
var start = 0
val sb = StringBuilder(2 * formatString.length)
while (true) {
if (matcher.find(index)) {
if ("%" == matcher.group(6)) {
index = matcher.end()
continue
}
val matchStart = matcher.start()
// Make sure this is not an escaped '%'
while (prevIndex < matchStart) {
val c = formatString[prevIndex]
if (c == '\\') {
prevIndex++
}
prevIndex++
}
if (prevIndex > matchStart) {
// We're in an escape, ignore this result
index = prevIndex
continue
}
index = matcher.end()
// Shouldn't throw a number format exception since we've already
// matched the pattern in the regexp
val number: Int
var numberString: String? = matcher.group(1)
if (numberString != null) {
// Strip off trailing $
numberString = numberString.substring(0, numberString.length - 1)
number = Integer.parseInt(numberString)
nextNumber = number + 1
}
else {
number = nextNumber++
}
if (number > 0 && number < args.size) {
val argExpression = args[number]
var value: Any? = argExpression.evaluate()
if (value == null) {
value = args[number].asSourceString()
}
for (i in start..matchStart - 1) {
sb.append(formatString[i])
}
sb.append("{")
sb.append(value)
sb.append('}')
start = index
}
}
else {
var i = start
val n = formatString.length
while (i < n) {
sb.append(formatString[i])
i++
}
break
}
}
return sb.toString()
}
private fun getAppResources(element: PsiElement): LocalResourceRepository? = ModuleUtilCore.findModuleForPsiElement(element)?.let {
AppResourceRepository.getAppResources(it, FORCE_PROJECT_RESOURCE_LOADING)
}
}
@@ -1,78 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.inspection
import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtPsiUtil.isUnsafeCast
import org.jetbrains.kotlin.psi.psiUtil.addTypeArgument
class TypeParameterFindViewByIdInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
val compileSdk = AndroidFacet.getInstance(session.file)?.androidModuleInfo?.buildSdkVersion?.apiLevel
if (compileSdk == null || compileSdk < 26) {
return KtVisitorVoid()
}
return object : KtVisitorVoid() {
override fun visitCallExpression(expression: KtCallExpression) {
super.visitCallExpression(expression)
if (expression.calleeExpression?.text != "findViewById" || expression.typeArguments.isNotEmpty()) {
return
}
val parentCast = (expression.parent as? KtBinaryExpressionWithTypeRHS)?.takeIf { isUnsafeCast(it) } ?: return
val typeText = parentCast.right?.getTypeTextWithoutQuestionMark() ?: return
val callableDescriptor = expression.resolveToCall()?.resultingDescriptor ?: return
if (callableDescriptor.name.asString() != "findViewById" || callableDescriptor.typeParameters.size != 1) {
return
}
holder.registerProblem(
parentCast,
"Can be converted to findViewById<$typeText>(...)",
ConvertCastToFindViewByIdWithTypeParameter())
}
}
}
class ConvertCastToFindViewByIdWithTypeParameter : LocalQuickFix {
override fun getFamilyName(): String = "Convert cast to findViewById with type parameter"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val cast = descriptor.psiElement as? KtBinaryExpressionWithTypeRHS ?: return
val typeText = cast.right?.getTypeTextWithoutQuestionMark() ?: return
val call = cast.left as? KtCallExpression ?: return
val newCall = call.copy() as KtCallExpression
val typeArgument = KtPsiFactory(call).createTypeArgument(typeText)
newCall.addTypeArgument(typeArgument)
cast.replace(newCall)
}
}
companion object {
fun KtTypeReference.getTypeTextWithoutQuestionMark(): String? =
(typeElement as? KtNullableType)?.innerType?.text ?: typeElement?.text
}
}
@@ -1,147 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.navigation;
import com.android.resources.ResourceType;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlElement;
import org.jetbrains.android.dom.AndroidAttributeValue;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.dom.manifest.ManifestElementWithRequiredName;
import org.jetbrains.android.dom.resources.Attr;
import org.jetbrains.android.dom.resources.DeclareStyleable;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.resourceManagers.ResourceManager;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.android.AndroidUtilKt;
import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// TODO: ask for extension point
// this class is mostly copied from org.jetbrains.android.AndroidGotoDeclarationHandler
public class KotlinAndroidGotoDeclarationHandler implements GotoDeclarationHandler {
@Override
public PsiElement[] getGotoDeclarationTargets(@Nullable PsiElement sourceElement, int offset, Editor editor) {
KtSimpleNameExpression referenceExpression = GotoResourceHelperKt.getReferenceExpression(sourceElement);
if (referenceExpression == null) {
return null;
}
AndroidFacet facet = AndroidUtilKt.getAndroidFacetForFile(referenceExpression);
if (facet == null) {
return null;
}
AndroidResourceUtil.MyReferredResourceFieldInfo info = GotoResourceHelperKt.getInfo(referenceExpression, facet);
if (info == null) return null;
String nestedClassName = info.getClassName();
String fieldName = info.getFieldName();
List<PsiElement> resourceList = new ArrayList<PsiElement>();
if (info.isFromManifest()) {
collectManifestElements(nestedClassName, fieldName, facet, resourceList);
}
else {
ResourceManager manager = info.isSystem()
? facet.getSystemResourceManager(false)
: facet.getLocalResourceManager();
if (manager == null) {
return null;
}
manager.collectLazyResourceElements(nestedClassName, fieldName, false, referenceExpression, resourceList);
if (manager instanceof LocalResourceManager) {
LocalResourceManager lrm = (LocalResourceManager) manager;
if (nestedClassName.equals(ResourceType.ATTR.getName())) {
for (Attr attr : lrm.findAttrs(fieldName)) {
resourceList.add(attr.getName().getXmlAttributeValue());
}
}
else if (nestedClassName.equals(ResourceType.STYLEABLE.getName())) {
for (DeclareStyleable styleable : lrm.findStyleables(fieldName)) {
resourceList.add(styleable.getName().getXmlAttributeValue());
}
for (Attr styleable : lrm.findStyleableAttributesByFieldName(fieldName)) {
resourceList.add(styleable.getName().getXmlAttributeValue());
}
}
}
}
if (resourceList.size() > 1) {
// Sort to ensure the output is stable, and to prefer the base folders
Collections.sort(resourceList, AndroidResourceUtil.RESOURCE_ELEMENT_COMPARATOR);
}
return resourceList.toArray(new PsiElement[resourceList.size()]);
}
private static void collectManifestElements(
@NotNull String nestedClassName,
@NotNull String fieldName,
@NotNull AndroidFacet facet,
@NotNull List<PsiElement> result
) {
Manifest manifest = facet.getManifest();
if (manifest == null) {
return;
}
List<? extends ManifestElementWithRequiredName> list;
if ("permission".equals(nestedClassName)) {
list = manifest.getPermissions();
}
else if ("permission_group".equals(nestedClassName)) {
list = manifest.getPermissionGroups();
}
else {
return;
}
for (ManifestElementWithRequiredName domElement : list) {
AndroidAttributeValue<String> nameAttribute = domElement.getName();
String name = nameAttribute.getValue();
if (AndroidUtils.equal(name, fieldName, false)) {
XmlElement psiElement = nameAttribute.getXmlAttributeValue();
if (psiElement != null) {
result.add(psiElement);
}
}
}
}
@Override
public String getActionText(DataContext context) {
return null;
}
}
@@ -1,84 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.lint
import com.intellij.codeInspection.InspectionProfileEntry
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
import com.intellij.util.PathUtil
import org.jetbrains.android.inspections.klint.AndroidLintInspectionBase
import org.jetbrains.kotlin.android.KotlinAndroidTestCase
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.InTextDirectivesUtils.findStringWithPrefixes
import java.io.File
abstract class AbstractKotlinLintTest : KotlinAndroidTestCase() {
override fun setUp() {
super.setUp()
AndroidLintInspectionBase.invalidateInspectionShortName2IssueMap()
(myFixture as CodeInsightTestFixtureImpl).setVirtualFileFilter { false } // Allow access to tree elements.
ConfigLibraryUtil.configureKotlinRuntime(myModule)
ConfigLibraryUtil.addLibrary(myModule, "androidExtensionsRuntime", "dist/kotlinc/lib", arrayOf("android-extensions-runtime.jar"))
}
override fun tearDown() {
ConfigLibraryUtil.unConfigureKotlinRuntime(myModule)
ConfigLibraryUtil.removeLibrary(myModule, "androidExtensionsRuntime")
super.tearDown()
}
fun doTest(path: String) {
val ktFile = File(path)
val fileText = ktFile.readText()
val mainInspectionClassName = findStringWithPrefixes(fileText, "// INSPECTION_CLASS: ") ?: error("Empty class name")
val dependencies = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// DEPENDENCY: ")
val inspectionClassNames = mutableListOf(mainInspectionClassName)
for (i in 2..100) {
val className = findStringWithPrefixes(ktFile.readText(), "// INSPECTION_CLASS$i: ") ?: break
inspectionClassNames += className
}
myFixture.enableInspections(*inspectionClassNames.map { className ->
val inspectionClass = Class.forName(className)
inspectionClass.newInstance() as InspectionProfileEntry
}.toTypedArray())
val additionalResourcesDir = File(ktFile.parentFile, getTestName(true))
if (additionalResourcesDir.exists()) {
for (file in additionalResourcesDir.listFiles()) {
if (file.isFile) {
myFixture.copyFileToProject(file.absolutePath, file.name)
}
else if (file.isDirectory) {
myFixture.copyDirectoryToProject(file.absolutePath, file.name)
}
}
}
val virtualFile = myFixture.copyFileToProject(ktFile.absolutePath, "src/${PathUtil.getFileName(path)}")
myFixture.configureFromExistingVirtualFile(virtualFile)
dependencies.forEach { dependency ->
val (dependencyFile, dependencyTargetPath) = dependency.split(" -> ").map(String::trim)
myFixture.copyFileToProject("${PathUtil.getParentPath(path)}/$dependencyFile", "src/$dependencyTargetPath")
}
myFixture.checkHighlighting(true, false, true)
}
}
@@ -1,62 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.quickfix
import com.intellij.codeInspection.InspectionProfileEntry
import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.PathUtil
import org.jetbrains.android.inspections.klint.AndroidLintInspectionBase
import org.jetbrains.kotlin.android.KotlinAndroidTestCase
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import java.io.File
abstract class AbstractAndroidLintQuickfixTest : KotlinAndroidTestCase() {
override fun setUp() {
AndroidLintInspectionBase.invalidateInspectionShortName2IssueMap()
super.setUp()
}
fun doTest(path: String) {
val fileText = FileUtil.loadFile(File(path), true)
val intentionText = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// INTENTION_TEXT: ") ?: error("Empty intention text")
val mainInspectionClassName = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// INSPECTION_CLASS: ") ?: error("Empty inspection class name")
val dependency = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// DEPENDENCY: ")
val intentionAvailable = !InTextDirectivesUtils.isDirectiveDefined(fileText, "// INTENTION_NOT_AVAILABLE")
val inspection = Class.forName(mainInspectionClassName).newInstance() as InspectionProfileEntry
myFixture.enableInspections(inspection)
val sourceFile = myFixture.copyFileToProject(path, "src/${PathUtil.getFileName(path)}")
myFixture.configureFromExistingVirtualFile(sourceFile)
if (dependency != null) {
val (dependencyFile, dependencyTargetPath) = dependency.split(" -> ").map(String::trim)
myFixture.copyFileToProject("${PathUtil.getParentPath(path)}/$dependencyFile", "src/$dependencyTargetPath")
}
if (intentionAvailable) {
val intention = myFixture.getAvailableIntention(intentionText) ?: error("Failed to find intention")
myFixture.launchAction(intention)
myFixture.checkResultByFile(path + ".expected")
}
else {
assertNull("Intention should not be available", myFixture.availableIntentions.find { it.text == intentionText })
}
}
}
@@ -1,107 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.configuration
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ExternalLibraryDescriptor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder
interface GradleBuildScriptManipulator<out Psi : PsiFile> {
val scriptFile: Psi
val preferNewSyntax: Boolean
fun isConfiguredWithOldSyntax(kotlinPluginName: String): Boolean
fun isConfigured(kotlinPluginExpression: String): Boolean
fun configureModuleBuildScript(
kotlinPluginName: String,
kotlinPluginExpression: String,
stdlibArtifactName: String,
version: String,
jvmTarget: String?
): Boolean
fun configureProjectBuildScript(kotlinPluginName: String, version: String): Boolean
fun changeCoroutineConfiguration(coroutineOption: String): PsiElement?
fun changeLanguageFeatureConfiguration(feature: LanguageFeature, state: LanguageFeature.State, forTests: Boolean): PsiElement?
fun changeLanguageVersion(version: String, forTests: Boolean): PsiElement?
fun changeApiVersion(version: String, forTests: Boolean): PsiElement?
fun addKotlinLibraryToModuleBuildScript(
scope: DependencyScope,
libraryDescriptor: ExternalLibraryDescriptor
)
fun getKotlinStdlibVersion(): String?
// For settings.gradle/settings.gradle.kts
fun addMavenCentralPluginRepository()
fun addPluginRepository(repository: RepositoryDescription)
fun addResolutionStrategy(pluginId: String)
}
// Kept for compatibility reasons (pre-181.3 IDEAs)
val BuildScriptDataBuilder.gradleVersion get() = GradleVersion.version("0.0")
fun fetchGradleVersion(psiFile: PsiFile): GradleVersion {
return gradleVersionFromFile(psiFile) ?: GradleVersion.current()
}
private fun gradleVersionFromFile(psiFile: PsiFile): GradleVersion? {
return null
}
val MIN_GRADLE_VERSION_FOR_NEW_PLUGIN_SYNTAX = GradleVersion.version("4.4")
fun GradleBuildScriptManipulator<*>.useNewSyntax(kotlinPluginName: String, gradleVersion: GradleVersion): Boolean {
if (!preferNewSyntax) return false
if (gradleVersion < MIN_GRADLE_VERSION_FOR_NEW_PLUGIN_SYNTAX) return false
if (isConfiguredWithOldSyntax(kotlinPluginName)) return false
val fileText = runReadAction { scriptFile.text }
val hasOldApply = fileText.contains("apply plugin:")
return !hasOldApply
}
private val MIN_GRADLE_VERSION_FOR_API_AND_IMPLEMENTATION = GradleVersion.version("3.4")
fun GradleVersion.scope(directive: String): String {
if (this < MIN_GRADLE_VERSION_FOR_API_AND_IMPLEMENTATION) {
return when (directive) {
"implementation" -> "compile"
"testImplementation" -> "testCompile"
else -> throw IllegalArgumentException("Unknown directive `$directive`")
}
}
return directive
}
@@ -1,77 +0,0 @@
/*
* Copyright 2010-2016 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
import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory
import com.intellij.testFramework.ThreadTracker
import java.lang.reflect.Modifier
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.atomic.AtomicBoolean
/*
Workaround for ThreadTracker.checkLeak() failures on TeamCity.
Currently TeamCity runs tests in classloader without boot.jar where IdeaForkJoinWorkerThreadFactory is defined. That
makes ForkJoinPool.commonPool() silently ignores java.util.concurrent.ForkJoinPool.common.threadFactory
(because of java.lang.ClassNotFoundException) option during factory initialization.
Standard names for ForkJoinPool threads doesn't pass ThreadTracker.checkLeak() check and that ruins tests constantly.
As it's allowed to reorder tests on TeamCity and any test can be first at some point, this patch should be applied at
some common place.
*/
object ThreadTrackerPatcherForTeamCityTesting {
private val patched = AtomicBoolean(false)
fun patchThreadTracker() {
if (patched.get()) return
patched.compareAndSet(false, true)
IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool()
// Check setup was successful and patching isn't needed
val commonPoolFactoryName = ForkJoinPool.commonPool().factory::class.java.name
if (commonPoolFactoryName == IdeaForkJoinWorkerThreadFactory::class.java.name) {
return
}
try {
val wellKnownOffendersField = try {
ThreadTracker::class.java.getDeclaredField("wellKnownOffenders")
}
catch (communityPropertyNotFoundEx: NoSuchFieldException) {
ThreadTracker::class.java.declaredFields.single {
Modifier.isStatic(it.modifiers) && MutableSet::class.java.isAssignableFrom(it.type)
}
}
wellKnownOffendersField.isAccessible = true
@Suppress("UNCHECKED_CAST")
val wellKnownOffenders = wellKnownOffendersField.get(null) as MutableSet<String>
wellKnownOffenders.add("ForkJoinPool.commonPool-worker-")
println("Patching ThreadTracker was successful")
}
catch (e: NoSuchFieldException) {
println("Patching ThreadTracker failed: " + e)
}
catch (e: IllegalAccessException) {
println("Patching ThreadTracker failed: " + e)
}
}
}
@@ -1,56 +0,0 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.options.Configurable
import com.intellij.openapi.options.SimpleConfigurable
import com.intellij.openapi.util.Getter
import com.intellij.util.xmlb.XmlSerializerUtil
import com.intellij.xdebugger.XDebuggerUtil
import com.intellij.xdebugger.settings.DebuggerSettingsCategory
import com.intellij.xdebugger.settings.XDebuggerSettings
import org.jetbrains.kotlin.idea.debugger.stepping.KotlinSteppingConfigurableUi
@State(name = "KotlinDebuggerSettings", storages = arrayOf(Storage("kotlin_debug.xml")))
class KotlinDebuggerSettings : XDebuggerSettings<KotlinDebuggerSettings>("kotlin_debugger"), Getter<KotlinDebuggerSettings> {
var DEBUG_RENDER_DELEGATED_PROPERTIES: Boolean = true
var DEBUG_DISABLE_KOTLIN_INTERNAL_CLASSES: Boolean = true
var DEBUG_IS_FILTER_FOR_STDLIB_ALREADY_ADDED: Boolean = false
companion object {
fun getInstance(): KotlinDebuggerSettings {
return XDebuggerUtil.getInstance()?.getDebuggerSettings(KotlinDebuggerSettings::class.java)!!
}
}
override fun createConfigurables(category: DebuggerSettingsCategory): Collection<Configurable?> {
return when (category) {
DebuggerSettingsCategory.STEPPING ->
listOf(SimpleConfigurable.create(
"reference.idesettings.debugger.kotlin.stepping",
"Kotlin",
KotlinSteppingConfigurableUi::class.java,
this))
DebuggerSettingsCategory.DATA_VIEWS ->
listOf(SimpleConfigurable.create(
"reference.idesettings.debugger.kotlin.data.view",
"Kotlin",
KotlinDelegatedPropertyRendererConfigurableUi::class.java,
this))
else -> listOf()
}
}
override fun getState() = this
override fun get() = this
override fun loadState(state: KotlinDebuggerSettings?) {
if (state != null) XmlSerializerUtil.copyBean<KotlinDebuggerSettings>(state, this)
}
}
@@ -1,442 +0,0 @@
/*
* Copyright 2010-2016 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.injection
import com.intellij.codeInsight.AnnotationUtil
import com.intellij.lang.injection.MultiHostInjector
import com.intellij.lang.injection.MultiHostRegistrar
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.text.StringUtilRt
import com.intellij.patterns.PatternCondition
import com.intellij.patterns.PatternConditionPlus
import com.intellij.patterns.PsiClassNamePatternCondition
import com.intellij.patterns.ValuePatternCondition
import com.intellij.psi.*
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiTreeUtil
import org.intellij.plugins.intelliLang.Configuration
import org.intellij.plugins.intelliLang.inject.InjectorUtils
import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport
import org.intellij.plugins.intelliLang.inject.TemporaryPlacesRegistry
import org.intellij.plugins.intelliLang.inject.config.BaseInjection
import org.intellij.plugins.intelliLang.inject.config.InjectionPlace
import org.intellij.plugins.intelliLang.inject.java.JavaLanguageInjectionSupport
import org.intellij.plugins.intelliLang.util.AnnotationUtilEx
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.patterns.KotlinFunctionPattern
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.runInReadActionWithWriteActionPriority
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.util.aliasImportMap
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinLanguageInjector(
private val configuration: Configuration,
private val project: Project,
private val temporaryPlacesRegistry: TemporaryPlacesRegistry
) : MultiHostInjector {
companion object {
private val STRING_LITERALS_REGEXP = "\"([^\"]*)\"".toRegex()
private val ABSENT_KOTLIN_INJECTION = BaseInjection("ABSENT_KOTLIN_BASE_INJECTION")
}
private val kotlinSupport: KotlinLanguageInjectionSupport? by lazy {
ArrayList(InjectorUtils.getActiveInjectionSupports()).filterIsInstance(KotlinLanguageInjectionSupport::class.java).firstOrNull()
}
private data class KotlinCachedInjection(val modificationCount: Long, val baseInjection: BaseInjection)
private var KtStringTemplateExpression.cachedInjectionWithModification: KotlinCachedInjection? by UserDataProperty(
Key.create<KotlinCachedInjection>("CACHED_INJECTION_WITH_MODIFICATION"))
override fun getLanguagesToInject(registrar: MultiHostRegistrar, context: PsiElement) {
val ktHost: KtStringTemplateExpression = context as? KtStringTemplateExpression ?: return
if (!context.isValidHost) return
val support = kotlinSupport ?: return
if (!ProjectRootsUtil.isInProjectOrLibSource(ktHost.containingFile.originalFile)) return
val needImmediateAnswer = with(ApplicationManager.getApplication()) { isDispatchThread && !isUnitTestMode }
val kotlinCachedInjection = ktHost.cachedInjectionWithModification
val modificationCount = PsiManager.getInstance(project).modificationTracker.modificationCount
val baseInjection = when {
needImmediateAnswer -> {
// Can't afford long counting or typing will be laggy. Force cache reuse even if it's outdated.
kotlinCachedInjection?.baseInjection ?: ABSENT_KOTLIN_INJECTION
}
kotlinCachedInjection != null && (modificationCount == kotlinCachedInjection.modificationCount) ->
// Cache is up-to-date
kotlinCachedInjection.baseInjection
else -> {
fun computeAndCache(): BaseInjection {
val computedInjection = computeBaseInjection(ktHost, support, registrar) ?: ABSENT_KOTLIN_INJECTION
ktHost.cachedInjectionWithModification = KotlinCachedInjection(modificationCount, computedInjection)
return computedInjection
}
if (ApplicationManager.getApplication().isReadAccessAllowed && ProgressManager.getInstance().progressIndicatorNullable == null) {
// The action cannot be canceled by caller and by internal checkCanceled() calls.
// Force creating new indicator that is canceled on write action start, otherwise there might be lags in typing.
runInReadActionWithWriteActionPriority(::computeAndCache) ?: kotlinCachedInjection?.baseInjection ?: ABSENT_KOTLIN_INJECTION
}
else {
computeAndCache()
}
}
}
if (baseInjection == ABSENT_KOTLIN_INJECTION) {
return
}
val language = InjectorUtils.getLanguageByString(baseInjection.injectedLanguageId) ?: return
if (ktHost.hasInterpolation()) {
val file = ktHost.containingKtFile
val parts = splitLiteralToInjectionParts(baseInjection, ktHost) ?: return
if (parts.ranges.isEmpty()) return
InjectorUtils.registerInjection(language, parts.ranges, file, registrar)
InjectorUtils.registerSupport(support, false, registrar)
InjectorUtils.putInjectedFileUserData(registrar, InjectedLanguageUtil.FRANKENSTEIN_INJECTION,
if (parts.isUnparsable) java.lang.Boolean.TRUE else null)
}
else {
InjectorUtils.registerInjectionSimple(ktHost, baseInjection, support, registrar)
}
}
@Suppress("FoldInitializerAndIfToElvis")
private fun computeBaseInjection(
ktHost: KtStringTemplateExpression,
support: KotlinLanguageInjectionSupport,
registrar: MultiHostRegistrar): BaseInjection? {
val containingFile = ktHost.containingFile
val tempInjectedLanguage = temporaryPlacesRegistry.getLanguageFor(ktHost, containingFile)
if (tempInjectedLanguage != null) {
InjectorUtils.putInjectedFileUserData(registrar, LanguageInjectionSupport.TEMPORARY_INJECTED_LANGUAGE, tempInjectedLanguage)
return BaseInjection(support.id).apply {
injectedLanguageId = tempInjectedLanguage.id
prefix = tempInjectedLanguage.prefix
suffix = tempInjectedLanguage.suffix
}
}
return findInjectionInfo(ktHost)?.toBaseInjection(support)
}
override fun elementsToInjectIn(): List<Class<out PsiElement>> {
return listOf(KtStringTemplateExpression::class.java)
}
private fun findInjectionInfo(place: KtElement, originalHost: Boolean = true): InjectionInfo? {
return injectWithExplicitCodeInstruction(place)
?: injectWithCall(place)
?: injectReturnValue(place)
?: injectInAnnotationCall(place)
?: injectWithReceiver(place)
?: injectWithVariableUsage(place, originalHost)
}
private fun injectReturnValue(place: KtElement): InjectionInfo? {
val parent = place.parent
tailrec fun findReturnExpression(expression: PsiElement?): KtReturnExpression? = when (expression) {
is KtReturnExpression -> expression
is KtBinaryExpression -> findReturnExpression(expression.takeIf { it.operationToken == KtTokens.ELVIS }?.parent)
is KtContainerNodeForControlStructureBody, is KtIfExpression -> findReturnExpression(expression.parent)
else -> null
}
val returnExp = findReturnExpression(parent) ?: return null
if (returnExp.labeledExpression != null) return null
val callableDeclaration = PsiTreeUtil.getParentOfType(returnExp, KtDeclaration::class.java) as? KtCallableDeclaration ?: return null
if (callableDeclaration.annotationEntries.isEmpty()) return null
val descriptor = callableDeclaration.descriptor ?: return null
return injectionInfoByAnnotation(descriptor)
}
private fun injectWithExplicitCodeInstruction(host: KtElement): InjectionInfo? {
val support = kotlinSupport ?: return null
return InjectionInfo.fromBaseInjection(support.findCommentInjection(host)) ?: support.findAnnotationInjectionLanguageId(host)
}
private fun injectWithReceiver(host: KtElement): InjectionInfo? {
val qualifiedExpression = host.parent as? KtDotQualifiedExpression ?: return null
if (qualifiedExpression.receiverExpression != host) return null
val callExpression = qualifiedExpression.selectorExpression as? KtCallExpression ?: return null
val callee = callExpression.calleeExpression ?: return null
if (isAnalyzeOff()) return null
val kotlinInjections = configuration.getInjections(KOTLIN_SUPPORT_ID)
val calleeName = callee.text
val possibleNames = collectPossibleNames(kotlinInjections)
if (calleeName !in possibleNames) {
return null
}
for (reference in callee.references) {
ProgressManager.checkCanceled()
val resolvedTo = reference.resolve()
if (resolvedTo is KtFunction) {
val injectionInfo = findInjection(resolvedTo.receiverTypeReference, kotlinInjections)
if (injectionInfo != null) {
return injectionInfo
}
}
}
return null
}
private fun collectPossibleNames(injections: List<BaseInjection>): Set<String> {
val result = HashSet<String>()
for (injection in injections) {
val injectionPlaces = injection.injectionPlaces
for (place in injectionPlaces) {
val placeStr = place.toString()
val literals = STRING_LITERALS_REGEXP.findAll(placeStr).map { it.groupValues[1] }
result.addAll(literals)
}
}
return result
}
private fun injectWithVariableUsage(host: KtElement, originalHost: Boolean): InjectionInfo? {
// Given place is not original host of the injection so we stop to prevent stepping through indirect references
if (!originalHost) return null
val ktProperty = host.parent as? KtProperty ?: return null
if (ktProperty.initializer != host) return null
if (isAnalyzeOff()) return null
val searchScope = LocalSearchScope(arrayOf(ktProperty.containingFile), "", true)
return ReferencesSearch.search(ktProperty, searchScope).asSequence().mapNotNull { psiReference ->
val element = psiReference.element as? KtElement ?: return@mapNotNull null
findInjectionInfo(element, false)
}.firstOrNull()
}
private fun injectWithCall(host: KtElement): InjectionInfo? {
val ktHost: KtElement = host
val argument = ktHost.parent as? KtValueArgument ?: return null
val callExpression = PsiTreeUtil.getParentOfType(ktHost, KtCallElement::class.java) ?: return null
val callee = getNameReference(callExpression.calleeExpression) ?: return null
if (isAnalyzeOff()) return null
for (reference in callee.references) {
ProgressManager.checkCanceled()
val resolvedTo = reference.resolve()
if (resolvedTo is PsiMethod) {
val injectionForJavaMethod = injectionForJavaMethod(argument, resolvedTo)
if (injectionForJavaMethod != null) {
return injectionForJavaMethod
}
}
else if (resolvedTo is KtFunction) {
val injectionForJavaMethod = injectionForKotlinCall(argument, resolvedTo, reference)
if (injectionForJavaMethod != null) {
return injectionForJavaMethod
}
}
}
return null
}
private fun getNameReference(callee: KtExpression?): KtNameReferenceExpression? {
if (callee is KtConstructorCalleeExpression)
return callee.constructorReferenceExpression as? KtNameReferenceExpression
return callee as? KtNameReferenceExpression
}
private fun injectInAnnotationCall(host: KtElement): InjectionInfo? {
val argument = host.parent as? KtValueArgument ?: return null
val annotationEntry = argument.parent.parent as? KtCallElement ?: return null
if (!fastCheckInjectionsExists(annotationEntry)) return null
val calleeExpression = annotationEntry.calleeExpression ?: return null
val callee = getNameReference(calleeExpression)?.mainReference?.resolve()
when (callee) {
is PsiClass -> {
val psiClass = callee as? PsiClass ?: return null
val argumentName = argument.getArgumentName()?.asName?.identifier ?: "value"
val method = psiClass.findMethodsByName(argumentName, false).singleOrNull() ?: return null
return findInjection(method, configuration.getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID))
}
else -> return null
}
}
private fun injectionForJavaMethod(argument: KtValueArgument, javaMethod: PsiMethod): InjectionInfo? {
val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument)
val psiParameter = javaMethod.parameterList.parameters.getOrNull(argumentIndex) ?: return null
val injectionInfo = findInjection(psiParameter, configuration.getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID))
if (injectionInfo != null) {
return injectionInfo
}
val annotations = AnnotationUtilEx.getAnnotationFrom(
psiParameter,
configuration.advancedConfiguration.languageAnnotationPair,
true)
if (annotations.isNotEmpty()) {
return processAnnotationInjectionInner(annotations)
}
return null
}
private fun injectionForKotlinCall(argument: KtValueArgument, ktFunction: KtFunction, reference: PsiReference): InjectionInfo? {
val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument)
val ktParameter = ktFunction.valueParameters.getOrNull(argumentIndex) ?: return null
val patternInjection = findInjection(ktParameter, configuration.getInjections(KOTLIN_SUPPORT_ID))
if (patternInjection != null) {
return patternInjection
}
// Found psi element after resolve can be obtained from compiled declaration but annotations parameters are lost there.
// Search for original descriptor from reference.
val ktReference = reference as? KtReference ?: return null
val bindingContext = ktReference.element.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
val functionDescriptor = ktReference.resolveToDescriptors(bindingContext).singleOrNull() as? FunctionDescriptor ?: return null
val parameterDescriptor = functionDescriptor.valueParameters.getOrNull(argumentIndex) ?: return null
return injectionInfoByAnnotation(parameterDescriptor)
}
private fun injectionInfoByAnnotation(annotated: Annotated): InjectionInfo? {
val injectAnnotation = annotated.annotations.findAnnotation(FqName(AnnotationUtil.LANGUAGE)) ?: return null
val languageId = injectAnnotation.argumentValue("value")?.safeAs<StringValue>()?.value ?: return null
val prefix = injectAnnotation.argumentValue("prefix")?.safeAs<StringValue>()?.value
val suffix = injectAnnotation.argumentValue("suffix")?.safeAs<StringValue>()?.value
return InjectionInfo(languageId, prefix, suffix)
}
private fun findInjection(element: PsiElement?, injections: List<BaseInjection>): InjectionInfo? {
for (injection in injections) {
if (injection.acceptsPsiElement(element)) {
return InjectionInfo(injection.injectedLanguageId, injection.prefix, injection.suffix)
}
}
return null
}
private fun isAnalyzeOff(): Boolean {
return configuration.advancedConfiguration.dfaOption == Configuration.DfaOption.OFF
}
private fun processAnnotationInjectionInner(annotations: Array<PsiAnnotation>): InjectionInfo? {
val id = AnnotationUtilEx.calcAnnotationValue(annotations, "value")
val prefix = AnnotationUtilEx.calcAnnotationValue(annotations, "prefix")
val suffix = AnnotationUtilEx.calcAnnotationValue(annotations, "suffix")
return InjectionInfo(id, prefix, suffix)
}
private val injectableTargetClassShortNames = CachedValuesManager.getManager(project)
.createCachedValue({
CachedValueProvider.Result.create(HashSet<String>().apply {
for (injection in configuration.getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID)) {
for (injectionPlace in injection.injectionPlaces) {
for (targetClassFQN in retrieveJavaPlaceTargetClassesFQNs(injectionPlace)) {
add(StringUtilRt.getShortName(targetClassFQN))
}
}
}
for (injection in configuration.getInjections(org.jetbrains.kotlin.idea.injection.KOTLIN_SUPPORT_ID)) {
for (injectionPlace in injection.injectionPlaces) {
for (targetClassFQN in retrieveKotlinPlaceTargetClassesFQNs(injectionPlace)) {
add(StringUtilRt.getShortName(targetClassFQN))
}
}
}
}, configuration)
}, false)
private fun fastCheckInjectionsExists(annotationEntry: KtCallElement): Boolean {
val referencedName = getNameReference(annotationEntry.calleeExpression)?.getReferencedName() ?: return false
val annotationShortName = annotationEntry.containingKtFile.aliasImportMap()[referencedName].singleOrNull() ?: referencedName
return annotationShortName in injectableTargetClassShortNames.value
}
private fun retrieveJavaPlaceTargetClassesFQNs(place: InjectionPlace): Collection<String> {
val classCondition = place.elementPattern.condition.conditions.firstOrNull { it.debugMethodName == "definedInClass" }
as? PatternConditionPlus<*, *> ?: return emptyList()
val psiClassNamePatternCondition = classCondition.valuePattern.condition.conditions.
firstIsInstanceOrNull<PsiClassNamePatternCondition>() ?: return emptyList()
val valuePatternCondition = psiClassNamePatternCondition.namePattern.condition.conditions.firstIsInstanceOrNull<ValuePatternCondition<String>>() ?: return emptyList()
return valuePatternCondition.values
}
private fun retrieveKotlinPlaceTargetClassesFQNs(place: InjectionPlace): Collection<String> {
val classNames = SmartList<String>()
fun collect(condition: PatternCondition<*>) {
when (condition) {
is PatternConditionPlus<*, *> -> condition.valuePattern.condition.conditions.forEach { collect(it) }
is KotlinFunctionPattern.DefinedInClassCondition -> classNames.add(condition.fqName)
}
}
place.elementPattern.condition.conditions.forEach { collect(it) }
return classNames
}
}
-73
View File
@@ -1,73 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":core:util.runtime"))
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:util"))
compile(project(":compiler:cli-common"))
compile(project(":kotlin-build-common"))
compile(project(":js:js.frontend"))
compile(project(":idea"))
compile(project(":idea:idea-jvm"))
compile(project(":idea:idea-jps-common"))
compileOnly(intellijDep())
excludeInAndroidStudio(rootProject) { compileOnly(intellijPluginDep("maven")) }
testCompile(projectTests(":idea"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":idea:idea-test-framework"))
testCompileOnly(intellijDep())
testCompileOnly(intellijPluginDep("maven"))
testCompile(project(":idea:idea-native")) { isTransitive = false }
testRuntime(project(":kotlin-native:kotlin-native-library-reader")) { isTransitive = false }
testRuntime(project(":kotlin-native:kotlin-native-utils")) { isTransitive = false }
testRuntime(project(":kotlin-reflect"))
testRuntime(project(":idea:idea-jvm"))
testRuntime(project(":idea:idea-android"))
testRuntime(project(":plugins:android-extensions-ide"))
testRuntime(project(":plugins:lint"))
testRuntime(project(":sam-with-receiver-ide-plugin"))
testRuntime(project(":allopen-ide-plugin"))
testRuntime(project(":noarg-ide-plugin"))
testRuntime(project(":kotlin-scripting-idea"))
testRuntime(project(":kotlinx-serialization-ide-plugin"))
testRuntime(intellijDep())
// TODO: the order of the plugins matters here, consider avoiding order-dependency
testRuntime(intellijPluginDep("junit"))
testRuntime(intellijPluginDep("testng"))
testRuntime(intellijPluginDep("properties"))
testRuntime(intellijPluginDep("gradle"))
testRuntime(intellijPluginDep("Groovy"))
testRuntime(intellijPluginDep("coverage"))
testRuntime(intellijPluginDep("maven"))
testRuntime(intellijPluginDep("android"))
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
testsJar()
projectTest {
workingDir = rootDir
}
runtimeJar {
archiveName = "maven-ide.jar"
}
ideaPlugin()
@@ -1,424 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.maven
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.StoragePathMacros
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.*
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.util.AsyncResult
import com.intellij.util.PairConsumer
import com.intellij.util.PathUtil
import org.jdom.Element
import org.jdom.Text
import org.jetbrains.idea.maven.importing.MavenImporter
import org.jetbrains.idea.maven.importing.MavenRootModelAdapter
import org.jetbrains.idea.maven.model.MavenPlugin
import org.jetbrains.idea.maven.project.*
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.idea.facet.*
import org.jetbrains.kotlin.idea.framework.detectLibraryKind
import org.jetbrains.kotlin.idea.maven.configuration.KotlinMavenConfigurator
import org.jetbrains.kotlin.idea.platform.tooling
import org.jetbrains.kotlin.platform.IdePlatform
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.impl.isCommon
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.File
import java.util.*
interface MavenProjectImportHandler {
companion object : ProjectExtensionDescriptor<MavenProjectImportHandler>(
"org.jetbrains.kotlin.mavenProjectImportHandler",
MavenProjectImportHandler::class.java
)
operator fun invoke(facet: KotlinFacet, mavenProject: MavenProject)
}
class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID) {
companion object {
const val KOTLIN_PLUGIN_GROUP_ID = "org.jetbrains.kotlin"
const val KOTLIN_PLUGIN_ARTIFACT_ID = "kotlin-maven-plugin"
const val KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG = "sourceDirs"
}
override fun preProcess(
module: Module,
mavenProject: MavenProject,
changes: MavenProjectChanges,
modifiableModelsProvider: IdeModifiableModelsProvider
) {
}
override fun process(
modifiableModelsProvider: IdeModifiableModelsProvider,
module: Module,
rootModel: MavenRootModelAdapter,
mavenModel: MavenProjectsTree,
mavenProject: MavenProject,
changes: MavenProjectChanges,
mavenProjectToModuleName: MutableMap<MavenProject, String>,
postTasks: MutableList<MavenProjectsProcessorTask>
) {
if (changes.plugins) {
contributeSourceDirectories(mavenProject, module, rootModel)
}
}
override fun postProcess(
module: Module,
mavenProject: MavenProject,
changes: MavenProjectChanges,
modifiableModelsProvider: IdeModifiableModelsProvider
) {
super.postProcess(module, mavenProject, changes, modifiableModelsProvider)
if (changes.dependencies) {
scheduleDownloadStdlibSources(mavenProject, module)
val targetLibraryKind = detectPlatformByExecutions(mavenProject)?.tooling?.libraryKind
if (targetLibraryKind != null) {
modifiableModelsProvider.getModifiableRootModel(module).orderEntries().forEachLibrary { library ->
if ((library as LibraryEx).kind == null) {
val model = modifiableModelsProvider.getModifiableLibraryModel(library) as LibraryEx.ModifiableModelEx
detectLibraryKind(model.getFiles(OrderRootType.CLASSES))?.let { model.kind = it }
}
true
}
}
}
configureFacet(mavenProject, modifiableModelsProvider, module)
}
private fun scheduleDownloadStdlibSources(mavenProject: MavenProject, module: Module) {
// TODO: here we have to process all kotlin libraries but for now we only handle standard libraries
val artifacts = mavenProject.dependencyArtifactIndex.data[KOTLIN_PLUGIN_GROUP_ID]?.values?.flatMap { it.filter { it.isResolved } }
?: emptyList()
val librariesWithNoSources = ArrayList<Library>()
OrderEnumerator.orderEntries(module).forEachLibrary { library ->
if (library.modifiableModel.getFiles(OrderRootType.SOURCES).isEmpty()) {
librariesWithNoSources.add(library)
}
true
}
val libraryNames = librariesWithNoSources.mapTo(HashSet()) { it.name }
val toBeDownloaded = artifacts.filter { it.libraryName in libraryNames }
if (toBeDownloaded.isNotEmpty()) {
MavenProjectsManager.getInstance(module.project)
.scheduleArtifactsDownloading(listOf(mavenProject), toBeDownloaded, true, false, AsyncResult())
}
}
private fun configureJSOutputPaths(
mavenProject: MavenProject,
modifiableRootModel: ModifiableRootModel,
facetSettings: KotlinFacetSettings,
mavenPlugin: MavenPlugin
) {
fun parentPath(path: String): String =
File(path).absoluteFile.parentFile.absolutePath
val sharedOutputFile = mavenPlugin.configurationElement?.getChild("outputFile")?.text
val compilerModuleExtension = modifiableRootModel.getModuleExtension(CompilerModuleExtension::class.java) ?: return
val buildDirectory = mavenProject.buildDirectory
val executions = mavenPlugin.executions
executions.forEach {
val explicitOutputFile = it.configurationElement?.getChild("outputFile")?.text ?: sharedOutputFile
if (PomFile.KotlinGoals.Js in it.goals) {
// see org.jetbrains.kotlin.maven.K2JSCompilerMojo
val outputFilePath = PathUtil.toSystemDependentName(explicitOutputFile ?: "$buildDirectory/js/${mavenProject.mavenId.artifactId}.js")
compilerModuleExtension.setCompilerOutputPath(parentPath(outputFilePath))
facetSettings.productionOutputPath = outputFilePath
}
if (PomFile.KotlinGoals.TestJs in it.goals) {
// see org.jetbrains.kotlin.maven.KotlinTestJSCompilerMojo
val outputFilePath = PathUtil.toSystemDependentName(explicitOutputFile ?: "$buildDirectory/test-js/${mavenProject.mavenId.artifactId}-tests.js")
compilerModuleExtension.setCompilerOutputPathForTests(parentPath(outputFilePath))
facetSettings.testOutputPath = outputFilePath
}
}
}
private fun getCompilerArgumentsByConfigurationElement(
mavenProject: MavenProject,
configuration: Element?,
platform: IdePlatform<*, *>
): List<String> {
val arguments = platform.createArguments()
arguments.apiVersion = configuration?.getChild("apiVersion")?.text ?:
mavenProject.properties["kotlin.compiler.apiVersion"]?.toString()
arguments.languageVersion = configuration?.getChild("languageVersion")?.text ?:
mavenProject.properties["kotlin.compiler.languageVersion"]?.toString()
arguments.multiPlatform = configuration?.getChild("multiPlatform")?.text?.trim()?.toBoolean() ?: false
arguments.suppressWarnings = configuration?.getChild("nowarn")?.text?.trim()?.toBoolean() ?: false
configuration?.getChild("experimentalCoroutines")?.text?.trim()?.let {
arguments.coroutinesState = it
}
when (arguments) {
is K2JVMCompilerArguments -> {
arguments.classpath = configuration?.getChild("classpath")?.text
arguments.jdkHome = configuration?.getChild("jdkHome")?.text
arguments.jvmTarget = configuration?.getChild("jvmTarget")?.text ?:
mavenProject.properties["kotlin.compiler.jvmTarget"]?.toString()
arguments.javaParameters = configuration?.getChild("javaParameters")?.text?.toBoolean() ?: false
}
is K2JSCompilerArguments -> {
arguments.sourceMap = configuration?.getChild("sourceMap")?.text?.trim()?.toBoolean() ?: false
arguments.sourceMapPrefix = configuration?.getChild("sourceMapPrefix")?.text?.trim() ?: ""
arguments.sourceMapEmbedSources = configuration?.getChild("sourceMapEmbedSources")?.text?.trim() ?: "inlining"
arguments.outputFile = configuration?.getChild("outputFile")?.text
arguments.metaInfo = configuration?.getChild("metaInfo")?.text?.trim()?.toBoolean() ?: false
arguments.moduleKind = configuration?.getChild("moduleKind")?.text
arguments.main = configuration?.getChild("main")?.text
}
}
val additionalArgs = SmartList<String>().apply {
val argsElement = configuration?.getChild("args")
argsElement?.content?.forEach { argElement ->
when (argElement) {
is Text -> {
argElement.text?.let { addAll(splitArgumentString(it)) }
}
is Element -> {
if (argElement.name == "arg") {
addIfNotNull(argElement.text)
}
}
}
}
}
parseCommandLineArguments(additionalArgs, arguments)
return ArgumentUtils.convertArgumentsToStringList(arguments)
}
private val compilationGoals = listOf(
PomFile.KotlinGoals.Compile,
PomFile.KotlinGoals.TestCompile,
PomFile.KotlinGoals.Js,
PomFile.KotlinGoals.TestJs,
PomFile.KotlinGoals.MetaData
)
private fun configureFacet(mavenProject: MavenProject, modifiableModelsProvider: IdeModifiableModelsProvider, module: Module) {
val mavenPlugin = mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID) ?: return
val compilerVersion = mavenPlugin.version ?: LanguageVersion.LATEST_STABLE.versionString
val kotlinFacet = module.getOrCreateFacet(
modifiableModelsProvider,
false,
ExternalProjectSystemRegistry.MAVEN_EXTERNAL_SOURCE_ID
)
// TODO There should be a way to figure out the correct platform version
val platform = detectPlatform(mavenProject)?.defaultPlatform
kotlinFacet.configureFacet(compilerVersion, LanguageFeature.Coroutines.defaultState, platform, modifiableModelsProvider)
val facetSettings = kotlinFacet.configuration.settings
val configuredPlatform = kotlinFacet.configuration.settings.platform!!
val configuration = mavenPlugin.configurationElement
val sharedArguments = getCompilerArgumentsByConfigurationElement(mavenProject, configuration, configuredPlatform)
val executionArguments = mavenPlugin.executions
?.firstOrNull { it.goals.any { it in compilationGoals } }
?.configurationElement?.let { getCompilerArgumentsByConfigurationElement(mavenProject, it, configuredPlatform) }
parseCompilerArgumentsToFacet(sharedArguments, emptyList(), kotlinFacet, modifiableModelsProvider)
if (executionArguments != null) {
parseCompilerArgumentsToFacet(executionArguments, emptyList(), kotlinFacet, modifiableModelsProvider)
}
if (facetSettings.compilerArguments is K2JSCompilerArguments) {
configureJSOutputPaths(mavenProject, modifiableModelsProvider.getModifiableRootModel(module), facetSettings, mavenPlugin)
}
MavenProjectImportHandler.getInstances(module.project).forEach { it(kotlinFacet, mavenProject) }
setImplementedModuleName(kotlinFacet, mavenProject, module)
kotlinFacet.noVersionAutoAdvance()
}
private fun detectPlatform(mavenProject: MavenProject) =
detectPlatformByExecutions(mavenProject) ?: detectPlatformByLibraries(mavenProject)
private fun detectPlatformByExecutions(mavenProject: MavenProject): IdePlatformKind<*>? {
return mavenProject.findPlugin(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID)?.executions?.flatMap { it.goals }
?.mapNotNull { goal ->
when (goal) {
PomFile.KotlinGoals.Compile, PomFile.KotlinGoals.TestCompile -> JvmIdePlatformKind
PomFile.KotlinGoals.Js, PomFile.KotlinGoals.TestJs -> JsIdePlatformKind
PomFile.KotlinGoals.MetaData -> CommonIdePlatformKind
else -> null
}
}?.distinct()?.singleOrNull()
}
private fun detectPlatformByLibraries(mavenProject: MavenProject): IdePlatformKind<*>? {
for (kind in IdePlatformKind.ALL_KINDS) {
val mavenLibraryIds = kind.tooling.mavenLibraryIds
if (mavenLibraryIds.any { mavenProject.findDependencies(KOTLIN_PLUGIN_GROUP_ID, it).isNotEmpty() }) {
// TODO we could return here the correct version
return kind
}
}
return null
}
// TODO in theory it should work like this but it doesn't as it couldn't unmark source roots that are not roots anymore.
// I believe this is something should be done by the underlying maven importer implementation or somewhere else in the IDEA
// For now there is a contributeSourceDirectories implementation that deals with the issue
// see https://youtrack.jetbrains.com/issue/IDEA-148280
// override fun collectSourceRoots(mavenProject: MavenProject, result: PairConsumer<String, JpsModuleSourceRootType<*>>) {
// for ((type, dir) in collectSourceDirectories(mavenProject)) {
// val jpsType: JpsModuleSourceRootType<*> = when (type) {
// SourceType.PROD -> JavaSourceRootType.SOURCE
// SourceType.TEST -> JavaSourceRootType.TEST_SOURCE
// }
//
// result.consume(dir, jpsType)
// }
// }
private fun contributeSourceDirectories(mavenProject: MavenProject, module: Module, rootModel: MavenRootModelAdapter) {
val directories = collectSourceDirectories(mavenProject)
val toBeAdded = directories.map { it.second }.toSet()
val state = module.kotlinImporterComponent
val isNonJvmModule = mavenProject
.plugins
.asSequence()
.filter { it.isKotlinPlugin() }
.flatMap { it.executions.asSequence() }
.flatMap { it.goals.asSequence() }
.any { it in PomFile.KotlinGoals.CompileGoals && it !in PomFile.KotlinGoals.JvmGoals }
val prodSourceRootType: JpsModuleSourceRootType<*> = if (isNonJvmModule) KotlinSourceRootType.Source else JavaSourceRootType.SOURCE
val testSourceRootType: JpsModuleSourceRootType<*> = if (isNonJvmModule) KotlinSourceRootType.TestSource else JavaSourceRootType.TEST_SOURCE
for ((type, dir) in directories) {
if (rootModel.getSourceFolder(File(dir)) == null) {
val jpsType: JpsModuleSourceRootType<*> = when (type) {
SourceType.TEST -> testSourceRootType
SourceType.PROD -> prodSourceRootType
}
rootModel.addSourceFolder(dir, jpsType)
}
}
if (isNonJvmModule) {
mavenProject.sources.forEach { rootModel.addSourceFolder(it, KotlinSourceRootType.Source) }
mavenProject.testSources.forEach { rootModel.addSourceFolder(it, KotlinSourceRootType.TestSource) }
mavenProject.resources.forEach { rootModel.addSourceFolder(it.directory, KotlinResourceRootType.Resource) }
mavenProject.testResources.forEach { rootModel.addSourceFolder(it.directory, KotlinResourceRootType.TestResource) }
}
state.addedSources.filter { it !in toBeAdded }.forEach {
rootModel.unregisterAll(it, true, true)
state.addedSources.remove(it)
}
state.addedSources.addAll(toBeAdded)
}
private fun collectSourceDirectories(mavenProject: MavenProject): List<Pair<SourceType, String>> =
mavenProject.plugins.filter { it.isKotlinPlugin() }.flatMap { plugin ->
plugin.configurationElement.sourceDirectories().map { SourceType.PROD to it } +
plugin.executions.flatMap { execution ->
execution.configurationElement.sourceDirectories().map { execution.sourceType() to it }
}
}.distinct()
private fun setImplementedModuleName(kotlinFacet: KotlinFacet, mavenProject: MavenProject, module: Module) {
if (kotlinFacet.configuration.settings.platform.isCommon) {
kotlinFacet.configuration.settings.implementedModuleNames = emptyList()
} else {
val manager = MavenProjectsManager.getInstance(module.project)
val mavenDependencies = mavenProject.dependencies.mapNotNull { manager?.findProject(it) }
val implemented = mavenDependencies.filter { detectPlatformByExecutions(it).isCommon }
kotlinFacet.configuration.settings.implementedModuleNames = implemented.map { manager.findModule(it)?.name ?: it.displayName }
}
}
}
private fun MavenPlugin.isKotlinPlugin() =
groupId == KotlinMavenImporter.KOTLIN_PLUGIN_GROUP_ID && artifactId == KotlinMavenImporter.KOTLIN_PLUGIN_ARTIFACT_ID
private fun Element?.sourceDirectories(): List<String> =
this?.getChildren(KotlinMavenImporter.KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG)?.flatMap { it.children ?: emptyList() }?.map { it.textTrim }
?: emptyList()
private fun MavenPlugin.Execution.sourceType() =
goals.map { if (isTestGoalName(it)) SourceType.TEST else SourceType.PROD }
.distinct()
.singleOrNull() ?: SourceType.PROD
private fun isTestGoalName(goalName: String) = goalName.startsWith("test-")
private enum class SourceType {
PROD, TEST
}
@State(
name = "AutoImportedSourceRoots",
storages = [(Storage(id = "other", file = StoragePathMacros.MODULE_FILE))]
)
class KotlinImporterComponent : PersistentStateComponent<KotlinImporterComponent.State> {
class State(var directories: List<String> = ArrayList())
val addedSources: MutableSet<String> = Collections.synchronizedSet(HashSet<String>())
override fun loadState(state: State) {
addedSources.clear()
addedSources.addAll(state.directories)
}
override fun getState(): State {
return State(addedSources.sorted())
}
}
private val Module.kotlinImporterComponent: KotlinImporterComponent
get() = getComponent(KotlinImporterComponent::class.java) ?: throw IllegalStateException("No maven importer state configured")
@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>maventest</groupId>
<artifactId>maventest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<kotlin.version>$VERSION$</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jre8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>wrong-goal</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -1,16 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("UnusedImport")
package org.jetbrains.kotlin.idea.test
import com.intellij.codeInsight.CodeInsightTestCase
// Unneeded in 181, but used in 173
// BUNCH: 181
fun fixTemplates() {
CodeInsightTestCase.fixTemplates()
}
@@ -1,25 +0,0 @@
description = "Kotlin Gradle Tooling support"
plugins {
kotlin("jvm")
id("jps-compatible")
}
jvmTarget = "1.6"
dependencies {
compile(project(":kotlin-stdlib"))
compile(project(":compiler:cli-common"))
compile(intellijPluginDep("gradle"))
compileOnly(intellijDep()) { includeJars("slf4j-api-1.7.10") }
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
runtimeJar()
ideaPlugin()
@@ -1,434 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.logging.Logging
import org.jetbrains.plugins.gradle.model.*
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
import org.jetbrains.plugins.gradle.tooling.util.DependencyResolver
import org.jetbrains.plugins.gradle.tooling.util.DependencyResolverImpl
import org.jetbrains.plugins.gradle.tooling.util.SourceSetCachedFinder
import java.io.File
import java.lang.reflect.Method
class KotlinMPPGradleModelBuilder : ModelBuilderService {
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
return ErrorMessageBuilder
.create(project, e, "Gradle import errors")
.withDescription("Unable to build Kotlin project configuration")
}
override fun canBuild(modelName: String?): Boolean {
return modelName == KotlinMPPGradleModel::class.java.name
}
override fun buildAll(modelName: String, project: Project): Any? {
val dependencyResolver = DependencyResolverImpl(
project,
false,
false,
true,
SourceSetCachedFinder(project)
)
val sourceSets = buildSourceSets(dependencyResolver, project) ?: return null
val sourceSetMap = sourceSets.map { it.name to it }.toMap()
val targets = buildTargets(sourceSetMap, dependencyResolver, project) ?: return null
computeSourceSetsDeferredInfo(sourceSets, targets)
val coroutinesState = getCoroutinesState(project)
reportUnresolvedDependencies(targets)
return KotlinMPPGradleModelImpl(sourceSetMap, targets, ExtraFeaturesImpl(coroutinesState))
}
private fun reportUnresolvedDependencies(targets: Collection<KotlinTarget>) {
targets
.asSequence()
.flatMap { it.compilations.asSequence() }
.flatMap { it.dependencies.asSequence() }
.mapNotNull { (it as? UnresolvedExternalDependency)?.failureMessage }
.toSet()
.forEach { logger.warn(it) }
}
private fun getCoroutinesState(project: Project): String? {
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
val getExperimental = kotlinExt.javaClass.getMethodOrNull("getExperimental") ?: return null
val experimentalExt = getExperimental(kotlinExt) ?: return null
val getCoroutines = experimentalExt.javaClass.getMethodOrNull("getCoroutines") ?: return null
return getCoroutines(experimentalExt) as? String
}
private fun buildSourceSets(dependencyResolver: DependencyResolver, project: Project): Collection<KotlinSourceSetImpl>? {
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
val getSourceSets = kotlinExt.javaClass.getMethodOrNull("getSourceSets") ?: return null
@Suppress("UNCHECKED_CAST")
val sourceSets =
(getSourceSets(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
return sourceSets.mapNotNull { buildSourceSet(it, dependencyResolver, project) }
}
private fun buildSourceSet(
gradleSourceSet: Named,
dependencyResolver: DependencyResolver,
project: Project
): KotlinSourceSetImpl? {
val sourceSetClass = gradleSourceSet.javaClass
val getLanguageSettings = sourceSetClass.getMethodOrNull("getLanguageSettings") ?: return null
val getSourceDirSet = sourceSetClass.getMethodOrNull("getKotlin") ?: return null
val getResourceDirSet = sourceSetClass.getMethodOrNull("getResources") ?: return null
val getDependsOn = sourceSetClass.getMethodOrNull("getDependsOn") ?: return null
val languageSettings = getLanguageSettings(gradleSourceSet)?.let { buildLanguageSettings(it) } ?: return null
val sourceDirs = (getSourceDirSet(gradleSourceSet) as? SourceDirectorySet)?.srcDirs ?: emptySet()
val resourceDirs = (getResourceDirSet(gradleSourceSet) as? SourceDirectorySet)?.srcDirs ?: emptySet()
val dependencies = buildSourceSetDependencies(gradleSourceSet, dependencyResolver, project)
@Suppress("UNCHECKED_CAST")
val dependsOnSourceSets = (getDependsOn(gradleSourceSet) as? Set<Named>)?.mapTo(LinkedHashSet()) { it.name } ?: emptySet<String>()
return KotlinSourceSetImpl(gradleSourceSet.name, languageSettings, sourceDirs, resourceDirs, dependencies, dependsOnSourceSets)
}
private fun buildLanguageSettings(gradleLanguageSettings: Any): KotlinLanguageSettings? {
val languageSettingsClass = gradleLanguageSettings.javaClass
val getLanguageVersion = languageSettingsClass.getMethodOrNull("getLanguageVersion") ?: return null
val getApiVersion = languageSettingsClass.getMethodOrNull("getApiVersion") ?: return null
val getProgressiveMode = languageSettingsClass.getMethodOrNull("getProgressiveMode") ?: return null
val getEnabledLanguageFeatures = languageSettingsClass.getMethodOrNull("getEnabledLanguageFeatures") ?: return null
val getExperimentalAnnotationsInUse = languageSettingsClass.getMethodOrNull("getExperimentalAnnotationsInUse")
val getCompilerPluginArguments = languageSettingsClass.getMethodOrNull("getCompilerPluginArguments")
val getCompilerPluginClasspath = languageSettingsClass.getMethodOrNull("getCompilerPluginClasspath")
@Suppress("UNCHECKED_CAST")
return KotlinLanguageSettingsImpl(
getLanguageVersion(gradleLanguageSettings) as? String,
getApiVersion(gradleLanguageSettings) as? String,
getProgressiveMode(gradleLanguageSettings) as? Boolean ?: false,
getEnabledLanguageFeatures(gradleLanguageSettings) as? Set<String> ?: emptySet(),
getExperimentalAnnotationsInUse?.invoke(gradleLanguageSettings) as? Set<String> ?: emptySet(),
getCompilerPluginArguments?.invoke(gradleLanguageSettings) as? List<String> ?: emptyList(),
(getCompilerPluginClasspath?.invoke(gradleLanguageSettings) as? FileCollection)?.files ?: emptySet()
)
}
private fun buildDependencies(
dependencyHolder: Any,
dependencyResolver: DependencyResolver,
configurationNameAccessor: String,
scope: String,
project: Project
): Collection<KotlinDependency> {
val dependencyHolderClass = dependencyHolder.javaClass
val getConfigurationName = dependencyHolderClass.getMethodOrNull(configurationNameAccessor) ?: return emptyList()
val configurationName = getConfigurationName(dependencyHolder) as? String ?: return emptyList()
val configuration = project.configurations.findByName(configurationName) ?: return emptyList()
if (!configuration.isCanBeResolved) return emptyList()
val dependencyAdjuster = DependencyAdjuster(configuration, scope, project)
val resolvedDependencies = dependencyResolver
.resolveDependencies(configuration)
.apply {
forEach<ExternalDependency?> { (it as? AbstractExternalDependency)?.scope = scope }
}
.flatMap(dependencyAdjuster::adjustDependency)
val singleDependencyFiles = resolvedDependencies.mapNotNullTo(LinkedHashSet<File>()) {
(it as? FileCollectionDependency)?.files?.singleOrNull()
}
// Workaround for duplicated dependencies specified as a file collection (KT-26675)
// Drop this code when the issue is fixed in the platform
return resolvedDependencies.filter { dependency ->
if (dependency !is FileCollectionDependency) return@filter true
val files = dependency.files
if (files.size <= 1) return@filter true
(files.any { it !in singleDependencyFiles })
}
}
private fun buildTargets(
sourceSetMap: Map<String, KotlinSourceSet>,
dependencyResolver: DependencyResolver,
project: Project
): Collection<KotlinTarget>? {
return project.getTargets()?.mapNotNull { buildTarget(it, sourceSetMap, dependencyResolver, project) }
}
private fun buildTarget(
gradleTarget: Named,
sourceSetMap: Map<String, KotlinSourceSet>,
dependencyResolver: DependencyResolver,
project: Project
): KotlinTarget? {
val targetClass = gradleTarget.javaClass
val getPlatformType = targetClass.getMethodOrNull("getPlatformType") ?: return null
val getCompilations = targetClass.getMethodOrNull("getCompilations") ?: return null
val getDisambiguationClassifier = targetClass.getMethodOrNull("getDisambiguationClassifier") ?: return null
val platformId = (getPlatformType.invoke(gradleTarget) as? Named)?.name ?: return null
val platform = KotlinPlatform.byId(platformId) ?: return null
val disambiguationClassifier = getDisambiguationClassifier(gradleTarget) as? String
@Suppress("UNCHECKED_CAST")
val gradleCompilations =
(getCompilations.invoke(gradleTarget) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
val compilations = gradleCompilations.mapNotNull {
buildCompilation(it, disambiguationClassifier, sourceSetMap, dependencyResolver, project)
}
val jar = buildTargetJar(gradleTarget, project)
val target = KotlinTargetImpl(gradleTarget.name, null, disambiguationClassifier, platform, compilations, jar)
compilations.forEach { it.target = target }
return target
}
private fun buildTargetJar(gradleTarget: Named, project: Project): KotlinTargetJar? {
val targetClass = gradleTarget.javaClass
val getArtifactsTaskName = targetClass.getMethodOrNull("getArtifactsTaskName") ?: return null
val artifactsTaskName = getArtifactsTaskName(gradleTarget) as? String ?: return null
val jarTask = project.tasks.findByName(artifactsTaskName) ?: return null
val jarTaskClass = jarTask.javaClass
val getArchivePath = jarTaskClass.getMethodOrNull("getArchivePath")
val archiveFile = getArchivePath?.invoke(jarTask) as? File?
return KotlinTargetJarImpl(archiveFile)
}
private fun buildCompilation(
gradleCompilation: Named,
classifier: String?,
sourceSetMap: Map<String, KotlinSourceSet>,
dependencyResolver: DependencyResolver,
project: Project
): KotlinCompilationImpl? {
val compilationClass = gradleCompilation.javaClass
val getKotlinSourceSets = compilationClass.getMethodOrNull("getKotlinSourceSets") ?: return null
@Suppress("UNCHECKED_CAST")
val kotlinGradleSourceSets = (getKotlinSourceSets(gradleCompilation) as? Collection<Named>) ?: return null
val kotlinSourceSets = kotlinGradleSourceSets.mapNotNull { sourceSetMap[it.name] }
val getCompileKotlinTaskName = compilationClass.getMethodOrNull("getCompileKotlinTaskName") ?: return null
@Suppress("UNCHECKED_CAST")
val compileKotlinTaskName = (getCompileKotlinTaskName(gradleCompilation) as? String) ?: return null
val compileKotlinTask = project.tasks.findByName(compileKotlinTaskName) ?: return null
val output = buildCompilationOutput(gradleCompilation, compileKotlinTask) ?: return null
val arguments = buildCompilationArguments(compileKotlinTask) ?: return null
val dependencyClasspath = buildDependencyClasspath(compileKotlinTask)
val dependencies = buildCompilationDependencies(gradleCompilation, classifier, sourceSetMap, dependencyResolver, project)
return KotlinCompilationImpl(gradleCompilation.name, kotlinSourceSets, dependencies, output, arguments, dependencyClasspath)
}
private fun buildCompilationDependencies(
gradleCompilation: Named,
classifier: String?,
sourceSetMap: Map<String, KotlinSourceSet>,
dependencyResolver: DependencyResolver,
project: Project
): Set<KotlinDependency> {
return LinkedHashSet<KotlinDependency>().apply {
this += buildDependencies(
gradleCompilation, dependencyResolver, "getCompileDependencyConfigurationName", "COMPILE", project
)
this += buildDependencies(
gradleCompilation, dependencyResolver, "getRuntimeDependencyConfigurationName", "RUNTIME", project
)
this += sourceSetMap[compilationFullName(gradleCompilation.name, classifier)]?.dependencies ?: emptySet()
}
}
private fun buildSourceSetDependencies(
gradleSourceSet: Named,
dependencyResolver: DependencyResolver,
project: Project
): Set<KotlinDependency> {
return LinkedHashSet<KotlinDependency>().apply {
this += buildDependencies(
gradleSourceSet, dependencyResolver, "getApiMetadataConfigurationName", "COMPILE", project
)
this += buildDependencies(
gradleSourceSet, dependencyResolver, "getImplementationMetadataConfigurationName", "COMPILE", project
)
this += buildDependencies(
gradleSourceSet, dependencyResolver, "getCompileOnlyMetadataConfigurationName", "COMPILE", project
)
this += buildDependencies(
gradleSourceSet, dependencyResolver, "getRuntimeOnlyMetadataConfigurationName", "RUNTIME", project
)
}
}
@Suppress("UNCHECKED_CAST")
private fun safelyGetArguments(compileKotlinTask: Task, accessor: Method?) = try {
accessor?.invoke(compileKotlinTask) as? List<String>
} catch (e: Exception) {
logger.info(e.message, e)
null
} ?: emptyList()
private fun buildCompilationArguments(compileKotlinTask: Task): KotlinCompilationArguments? {
val compileTaskClass = compileKotlinTask.javaClass
val getCurrentArguments = compileTaskClass.getMethodOrNull("getSerializedCompilerArguments")
val getDefaultArguments = compileTaskClass.getMethodOrNull("getDefaultSerializedCompilerArguments")
val currentArguments = safelyGetArguments(compileKotlinTask, getCurrentArguments)
val defaultArguments = safelyGetArguments(compileKotlinTask, getDefaultArguments)
return KotlinCompilationArgumentsImpl(defaultArguments, currentArguments)
}
private fun buildDependencyClasspath(compileKotlinTask: Task): List<String> {
val abstractKotlinCompileClass =
compileKotlinTask.javaClass.classLoader.loadClass(AbstractKotlinGradleModelBuilder.ABSTRACT_KOTLIN_COMPILE_CLASS)
val getCompileClasspath =
abstractKotlinCompileClass.getDeclaredMethodOrNull("getCompileClasspath") ?: return emptyList()
@Suppress("UNCHECKED_CAST")
return (getCompileClasspath(compileKotlinTask) as? Collection<File>)?.map { it.path } ?: emptyList()
}
private fun buildCompilationOutput(
gradleCompilation: Named,
compileKotlinTask: Task
): KotlinCompilationOutput? {
val compilationClass = gradleCompilation.javaClass
val getOutput = compilationClass.getMethodOrNull("getOutput") ?: return null
val gradleOutput = getOutput(gradleCompilation) ?: return null
val gradleOutputClass = gradleOutput.javaClass
val getClassesDirs = gradleOutputClass.getMethodOrNull("getClassesDirs") ?: return null
val getResourcesDir = gradleOutputClass.getMethodOrNull("getResourcesDir") ?: return null
val compileKotlinTaskClass = compileKotlinTask.javaClass
val getDestinationDir = compileKotlinTaskClass.getMethodOrNull("getDestinationDir") ?: return null
val classesDirs = getClassesDirs(gradleOutput) as? FileCollection ?: return null
val resourcesDir = getResourcesDir(gradleOutput) as? File ?: return null
val destinationDir = getDestinationDir(compileKotlinTask) as? File
return KotlinCompilationOutputImpl(classesDirs.files, destinationDir, resourcesDir)
}
private fun computeSourceSetsDeferredInfo(
sourceSets: Collection<KotlinSourceSetImpl>,
targets: Collection<KotlinTarget>
) {
val sourceSetToCompilations = LinkedHashMap<KotlinSourceSet, MutableSet<KotlinCompilation>>()
for (target in targets) {
for (compilation in target.compilations) {
for (sourceSet in compilation.sourceSets) {
sourceSetToCompilations.getOrPut(sourceSet) { LinkedHashSet() } += compilation
}
}
}
for (sourceSet in sourceSets) {
val name = sourceSet.name
if (name == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) {
sourceSet.platform = KotlinPlatform.COMMON
sourceSet.isTestModule = false
continue
}
if (name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) {
sourceSet.platform = KotlinPlatform.COMMON
sourceSet.isTestModule = true
continue
}
val compilations = sourceSetToCompilations[sourceSet]
if (compilations != null) {
sourceSet.platform = compilations.map { it.platform }.distinct().singleOrNull() ?: KotlinPlatform.COMMON
sourceSet.isTestModule = compilations.all { it.isTestModule }
} else {
// TODO: change me after design about it
sourceSet.isTestModule = "Test" in sourceSet.name
}
}
}
private class DependencyAdjuster(
private val configuration: Configuration,
private val scope: String,
private val project: Project
) {
private val adjustmentMap = HashMap<ExternalDependency, List<ExternalDependency>>()
val dependenciesByProjectPath by lazy {
configuration
.resolvedConfiguration
.lenientConfiguration
.allModuleDependencies
.mapNotNull { dependency ->
val artifact = dependency.moduleArtifacts.firstOrNull {
it.id.componentIdentifier is ProjectComponentIdentifier
} ?: return@mapNotNull null
dependency to artifact
}
.groupBy { (it.second.id.componentIdentifier as ProjectComponentIdentifier).projectPath }
}
private fun wrapDependency(dependency: ExternalProjectDependency, newConfigurationName: String): ExternalProjectDependency {
return DefaultExternalProjectDependency(dependency).apply {
this.configurationName = newConfigurationName
val nestedDependencies = this.dependencies.flatMap(::adjustDependency)
this.dependencies.clear()
this.dependencies.addAll(nestedDependencies)
}
}
fun adjustDependency(dependency: ExternalDependency): List<ExternalDependency> {
return adjustmentMap.getOrPut(dependency) {
if (dependency !is ExternalProjectDependency
|| dependency.configurationName != Dependency.DEFAULT_CONFIGURATION
) return@getOrPut listOf(dependency)
val artifacts = dependenciesByProjectPath[dependency.projectPath] ?: return@getOrPut listOf(dependency)
val artifactConfiguration = artifacts.mapTo(LinkedHashSet()) {
it.first.configuration
}.singleOrNull() ?: return@getOrPut listOf(dependency)
val taskGetterName = when (scope) {
"COMPILE" -> "getApiElementsConfigurationName"
"RUNTIME" -> "getRuntimeElementsConfigurationName"
else -> return@getOrPut listOf(dependency)
}
val dependencyProject =
if (project.rootProject.path == dependency.projectPath)
project.rootProject
else
project.rootProject.getChildProjectByPath(dependency.projectPath)
val targets = dependencyProject?.getTargets() ?: return@getOrPut listOf(dependency)
val gradleTarget = targets.firstOrNull {
val getter = it.javaClass.getMethodOrNull(taskGetterName) ?: return@firstOrNull false
getter(it) == artifactConfiguration
} ?: return@getOrPut listOf(dependency)
val classifier = gradleTarget.javaClass.getMethodOrNull("getDisambiguationClassifier")?.invoke(gradleTarget) as? String
?: return@getOrPut listOf(dependency)
val platformDependency = if (classifier != KotlinTarget.METADATA_TARGET_NAME) {
wrapDependency(dependency, compilationFullName(KotlinCompilation.MAIN_COMPILATION_NAME, classifier))
} else null
val commonDependency = wrapDependency(dependency, KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
return if (platformDependency != null) listOf(platformDependency, commonDependency) else listOf(commonDependency)
}
}
}
companion object {
private val logger = Logging.getLogger(KotlinMPPGradleModelBuilder::class.java)
fun Project.getTargets(): Collection<Named>? {
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
val getTargets = kotlinExt.javaClass.getMethodOrNull("getTargets") ?: return null
@Suppress("UNCHECKED_CAST")
return (getTargets.invoke(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList()
}
}
}
private fun Project.getChildProjectByPath(path: String): Project? {
var project = this
for (name in path.split(":").asSequence().drop(1)) {
project = project.childProjects[name] ?: return null
}
return project
}
private fun Project.getTargets(): Collection<Named>? {
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
val getTargets = kotlinExt.javaClass.getMethodOrNull("getTargets") ?: return null
@Suppress("UNCHECKED_CAST")
return (getTargets.invoke(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList()
}
@@ -1,118 +0,0 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<externalAnnotator language="kotlin" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintExternalAnnotator"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintAddJavascriptInterface" displayName="addJavascriptInterface Called" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintAddJavascriptInterfaceInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintAllowAllHostnameVerifier" displayName="Insecure HostnameVerifier" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintAllowAllHostnameVerifierInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintAlwaysShowAction" displayName="Usage of showAsAction=always" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintAlwaysShowActionInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintAppCompatMethod" displayName="Using Wrong AppCompat Method" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintAppCompatMethodInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintAuthLeak" displayName="Code contains url auth" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintAuthLeakInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintBadHostnameVerifier" displayName="Insecure HostnameVerifier" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintBadHostnameVerifierInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintBatteryLife" displayName="Battery Life Issues" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintBatteryLifeInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintCommitPrefEdits" displayName="Missing commit() on SharedPreference editor" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintCommitPrefEditsInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintCommitTransaction" displayName="Missing commit() calls" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintCommitTransactionInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintCustomViewStyleable" displayName="Mismatched Styleable/Custom View Name" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintCustomViewStyleableInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintCutPasteId" displayName="Likely cut &amp; paste mistakes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintCutPasteIdInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintDefaultLocale" displayName="Implied default locale in case conversion" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintDefaultLocaleInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintDrawAllocation" displayName="Memory allocations within drawing code" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintDrawAllocationInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintEasterEgg" displayName="Code contains easter egg" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintEasterEggInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintExportedContentProvider" displayName="Content provider does not require permission" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintExportedContentProviderInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintExportedPreferenceActivity" displayName="PreferenceActivity should not be exported" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintExportedPreferenceActivityInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintExportedReceiver" displayName="Receiver does not require permission" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintExportedReceiverInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintExportedService" displayName="Exported service does not require permission" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintExportedServiceInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintFloatMath" displayName="Using FloatMath instead of Math" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintFloatMathInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintGetInstance" displayName="Cipher.getInstance with ECB" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintGetInstanceInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintGifUsage" displayName="Using .gif format for bitmaps is discouraged" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintGifUsageInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintGoogleAppIndexingApiWarning" displayName="Missing support for Google App Indexing Api" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintGoogleAppIndexingApiWarningInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintGoogleAppIndexingUrlError" displayName="URL not supported by app for Google App Indexing" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintGoogleAppIndexingUrlErrorInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintGoogleAppIndexingWarning" displayName="Missing support for Google App Indexing" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintGoogleAppIndexingWarningInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintGrantAllUris" displayName="Content provider shares everything" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintGrantAllUrisInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintHandlerLeak" displayName="Handler reference leaks" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintHandlerLeakInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconColors" displayName="Icon colors do not follow the recommended visual style" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconColorsInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconDensities" displayName="Icon densities validation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconDensitiesInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconDipSize" displayName="Icon density-independent size validation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconDipSizeInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconDuplicates" displayName="Duplicated icons under different names" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconDuplicatesInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconDuplicatesConfig" displayName="Identical bitmaps across various configurations" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconDuplicatesConfigInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconExpectedSize" displayName="Icon has incorrect size" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconExpectedSizeInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconExtension" displayName="Icon format does not match the file extension" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconExtensionInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconLauncherShape" displayName="The launcher icon shape should use a distinct silhouette" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconLauncherShapeInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconLocation" displayName="Image defined in density-independent drawable folder" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconLocationInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconMissingDensityFolder" displayName="Missing density folder" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconMissingDensityFolderInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconMixedNinePatch" displayName="Clashing PNG and 9-PNG files" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconMixedNinePatchInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconNoDpi" displayName="Icon appears in both -nodpi and dpi folders" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconNoDpiInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintIconXmlAndPng" displayName="Icon is specified both as .xml file and as a bitmap" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintIconXmlAndPngInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintInconsistentLayout" displayName="Inconsistent Layouts" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInconsistentLayoutInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintInflateParams" displayName="Layout Inflation without a Parent" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInflateParamsInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintInlinedApi" displayName="Using inlined constants on older versions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInlinedApiInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintInvalidUsesTagAttribute" displayName="Invalid name attribute for uses element." groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInvalidUsesTagAttributeInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintJavascriptInterface" displayName="Missing @JavascriptInterface on methods" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintJavascriptInterfaceInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintLocalSuppress" displayName="@SuppressLint on invalid element" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLocalSuppressInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintLogConditional" displayName="Unconditional Logging Calls" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLogConditionalInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintLogTagMismatch" displayName="Mismatched Log Tags" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLogTagMismatchInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintLongLogTag" displayName="Too Long Log Tags" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLongLogTagInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintMergeRootFrame" displayName="FrameLayout can be replaced with &lt;merge> tag" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintMergeRootFrameInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintMissingIntentFilterForMediaSearch" displayName="Missing intent-filter with action android.media.action.MEDIA_PLAY_FROM_SEARCH" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintMissingIntentFilterForMediaSearchInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintMissingMediaBrowserServiceIntentFilter" displayName="Missing intent-filter with action android.media.browse.MediaBrowserService." groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintMissingMediaBrowserServiceIntentFilterInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintMissingOnPlayFromSearch" displayName="Missing onPlayFromSearch." groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintMissingOnPlayFromSearchInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintMissingSuperCall" displayName="Missing Super Call" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintMissingSuperCallInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintNewApi" displayName="Calling new methods on older versions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintOverdraw" displayName="Overdraw: Painting regions more than once" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverdrawInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintOverride" displayName="Method conflicts with new inherited method" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverrideInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintOverrideAbstract" displayName="Not overriding abstract methods on older platforms" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverrideAbstractInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintPackageManagerGetSignatures" displayName="Potential Multiple Certificate Exploit" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintPackageManagerGetSignaturesInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintParcelClassLoader" displayName="Default Parcel Class Loader" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelClassLoaderInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintParcelCreator" displayName="Missing Parcelable CREATOR field" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintPendingBindings" displayName="Missing Pending Bindings" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintPendingBindingsInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintPluralsCandidate" displayName="Potential Plurals" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintPluralsCandidateInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintPrivateResource" displayName="Using private resources" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintPrivateResourceInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintRecycle" displayName="Missing recycle() calls" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRecycleInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintRecyclerView" displayName="RecyclerView Problems" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRecyclerViewInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintRegistered" displayName="Class is not registered in the manifest" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRegisteredInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintRequiredSize" displayName="Missing layout_width or layout_height attributes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRequiredSizeInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintRtlCompat" displayName="Right-to-left text compatibility issues" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRtlCompatInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintRtlEnabled" displayName="Using RTL attributes without enabling RTL support" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRtlEnabledInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintRtlHardcoded" displayName="Using left/right instead of start/end attributes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRtlHardcodedInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintRtlSymmetry" displayName="Padding and margin symmetry" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRtlSymmetryInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSdCardPath" displayName="Hardcoded reference to /sdcard" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSecureRandom" displayName="Using a fixed seed with SecureRandom" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSecureRandomInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintServiceCast" displayName="Wrong system service casts" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintServiceCastInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSetJavaScriptEnabled" displayName="Using setJavaScriptEnabled" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSetJavaScriptEnabledInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSetTextI18n" displayName="TextView Internationalization" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSetTextI18nInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSetWorldReadable" displayName="File.setReadable() used to make file world-readable" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSetWorldReadableInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSetWorldWritable" displayName="File.setWritable() used to make file world-writable" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSetWorldWritableInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintShiftFlags" displayName="Dangerous Flag Constant Declaration" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintShiftFlagsInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintShortAlarm" displayName="Short or Frequent Alarm" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintShortAlarmInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintShowToast" displayName="Toast created but not shown" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintShowToastInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSimpleDateFormat" displayName="Implied locale in date format" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSimpleDateFormatInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSQLiteString" displayName="Using STRING instead of TEXT" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSQLiteStringInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSSLCertificateSocketFactoryCreateSocket" displayName="Insecure call to SSLCertificateSocketFactory.createSocket()" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSSLCertificateSocketFactoryCreateSocketInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSSLCertificateSocketFactoryGetInsecure" displayName="Call to SSLCertificateSocketFactory.getInsecure()" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSSLCertificateSocketFactoryGetInsecureInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintStopShip" displayName="Code contains STOPSHIP marker" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintStopShipInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintStringFormatCount" displayName="Formatting argument types incomplete or inconsistent" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintStringFormatCountInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintStringFormatInvalid" displayName="Invalid format string" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintStringFormatInvalidInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintStringFormatMatches" displayName="String.format string doesn&apos;t match the XML format string" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintStringFormatMatchesInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSupportAnnotationUsage" displayName="Incorrect support annotation usage" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSupportAnnotationUsageInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSuspiciousImport" displayName="&apos;import android.R&apos; statement" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSuspiciousImportInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintSwitchIntDef" displayName="Missing @IntDef in Switch" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSwitchIntDefInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintTrustAllX509TrustManager" displayName="Insecure TLS/SSL trust manager" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintTrustAllX509TrustManagerInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUniqueConstants" displayName="Overlapping Enumeration Constants" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUniqueConstantsInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUnlocalizedSms" displayName="SMS phone number missing country code" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUnlocalizedSmsInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUnprotectedSMSBroadcastReceiver" displayName="Unprotected SMS BroadcastReceiver" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUnprotectedSMSBroadcastReceiverInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUnsafeDynamicallyLoadedCode" displayName="load used to dynamically load code" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUnsafeDynamicallyLoadedCodeInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUnsafeNativeCodeLocation" displayName="Native code outside library directory" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUnsafeNativeCodeLocationInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUnsafeProtectedBroadcastReceiver" displayName="Unsafe Protected BroadcastReceiver" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUnsafeProtectedBroadcastReceiverInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUnusedAttribute" displayName="Attribute unused on older versions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUnusedAttributeInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUseSparseArrays" displayName="HashMap can be replaced with SparseArray" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUseSparseArraysInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintUseValueOf" displayName="Should use valueOf instead of new" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUseValueOfInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintValidFragment" displayName="Fragment not instantiatable" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintValidFragmentInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintViewConstructor" displayName="Missing View constructors for XML inflation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintViewConstructorInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintViewHolder" displayName="View Holder Candidates" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintViewHolderInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintViewTag" displayName="Tagged object leaks" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintViewTagInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintWorldReadableFiles" displayName="openFileOutput() or similar call passing MODE_WORLD_READABLE" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintWorldReadableFilesInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintWorldWriteableFiles" displayName="openFileOutput() or similar call passing MODE_WORLD_WRITEABLE" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintWorldWriteableFilesInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintWrongCall" displayName="Using wrong draw/layout method" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintWrongCallInspection"/>
<globalInspection language="kotlin" hasStaticDescription="true" shortName="AndroidKLintWrongViewCast" displayName="Mismatched view type" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintWrongViewCastInspection"/>
<codeInspection.InspectionExtension implementation="org.jetbrains.android.inspections.klint.AndroidInspectionExtensionsFactory"/>
</extensions>
</idea-plugin>
-108
View File
@@ -1,108 +0,0 @@
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="android-lint.xml" xpointer="xpointer(/idea-plugin/*)"/>
<extensions defaultExtensionNs="com.intellij">
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.navigation.KotlinAndroidGotoDeclarationHandler"/>
<moduleService serviceInterface="org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager"
serviceImplementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidLayoutXmlFileManager"/>
<psi.treeChangePreprocessor implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidPsiTreeChangePreprocessor"/>
<errorHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsReportSubmitter"/>
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidGotoDeclarationHandler"/>
<localInspection implementationClass="org.jetbrains.kotlin.android.inspection.IllegalIdentifierInspection"
displayName="Illegal Android Identifier"
groupName="Kotlin Android"
enabledByDefault="true"
level="ERROR"/>
<localInspection implementationClass="org.jetbrains.kotlin.android.inspection.TypeParameterFindViewByIdInspection"
displayName="Cast can be converted to findViewById with type parameter"
groupName="Kotlin Android"
enabledByDefault="true"
cleanupTool="true"
level="WEAK WARNING"
language="kotlin" />
<codeInsight.lineMarkerProvider language="kotlin" implementationClass="org.jetbrains.kotlin.android.KotlinAndroidLineMarkerProvider"/>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.KotlinAndroidAddStringResource</className>
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.AddActivityToManifest</className>
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.AddServiceToManifest</className>
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.AddBroadcastReceiverToManifest</className>
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.ImplementParcelableAction</className>
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.RemoveParcelableAction</className>
<category>Kotlin Android</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.android.intention.RedoParcelableAction</className>
<category>Kotlin Android</category>
</intentionAction>
<codeInsight.unresolvedReferenceQuickFixProvider
implementation="org.jetbrains.kotlin.android.inspection.KotlinAndroidResourceQuickFixProvider"/>
<lang.foldingBuilder language="kotlin" implementationClass="org.jetbrains.kotlin.android.folding.ResourceFoldingBuilder" />
<annotator language="kotlin" implementationClass="org.jetbrains.kotlin.android.AndroidResourceReferenceAnnotator" />
<referencesSearch implementation="org.jetbrains.kotlin.AndroidExtensionsReferenceSearchExecutor"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleMPPModuleDataService"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<projectResolve implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsProjectResolverExtension"/>
<projectResolve implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidMPPGradleProjectResolver"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidExtensionsExpressionCodegenExtension"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.android.synthetic.AndroidExtensionPropertiesComponentContainerContributor"/>
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidOnDestroyClassBuilderInterceptorExtension"/>
<packageFragmentProviderExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidPackageFragmentProviderExtension"/>
<simpleNameReferenceExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidSimpleNameReferenceExtension"/>
<kotlinIndicesHelperExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidIndicesHelperExtension"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsGradleImportHandler"/>
<quickFixContributor implementation="org.jetbrains.kotlin.android.quickfix.AndroidQuickFixRegistrar"/>
<projectConfigurator implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleModuleConfigurator"/>
<gradleModelFacade implementation="org.jetbrains.kotlin.android.configure.AndroidGradleModelFacade"/>
<completionInformationProvider implementation="org.jetbrains.kotlin.AndroidExtensionsCompletionInformationProvider" />
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableCodegenExtension"/>
<syntheticResolveExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableResolveExtension"/>
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.codegen.ParcelableClinitClassBuilderInterceptorExtension"/>
<quickFixContributor implementation="org.jetbrains.kotlin.android.parcel.quickfixes.ParcelableQuickFixContributor"/>
<androidDexer implementation="org.jetbrains.kotlin.android.debugger.AndroidDexerImpl"/>
<highlighterExtension implementation="org.jetbrains.kotlin.android.AndroidHighlighterExtension"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin.android.model">
<androidModuleInfoProvider implementation="org.jetbrains.kotlin.android.model.impl.AndroidModuleInfoProviderImpl"/>
</extensions>
</idea-plugin>
-93
View File
@@ -1,93 +0,0 @@
<idea-plugin>
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSFrameworkSupportProvider"/>
<kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJavaFrameworkSupportProvider"/>
<kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSFrameworkSupportProvider"/>
<pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension" order="first"/>
<projectResolve implementation="org.jetbrains.kotlin.kapt.idea.KaptProjectResolverExtension" order="last"/>
<projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
<projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
<projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver"/>
</extensions>
<extensionPoints>
<extensionPoint qualifiedName="org.jetbrains.kotlin.gradleProjectImportHandler" area="IDEA_PROJECT"
interface="org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.gradleModelFacade"
interface="org.jetbrains.kotlin.idea.inspections.gradle.KotlinGradleModelFacade"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectSettingsDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.core.script.ReloadGradleTemplatesOnSync"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DifferentKotlinGradleVersionInspection"
displayName="Kotlin Gradle and IDE plugins versions are different"
groupName="Kotlin"
enabledByDefault="true"
language="Groovy"
hasStaticDescription="true"
level="WARNING"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DifferentStdlibGradleVersionInspection"
displayName="Kotlin library and Gradle plugin versions are different"
groupName="Kotlin"
enabledByDefault="true"
language="Groovy"
hasStaticDescription="true"
level="WARNING"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DeprecatedGradleDependencyInspection"
displayName="Deprecated library is used in Gradle"
groupName="Kotlin"
enabledByDefault="true"
cleanupTool="true"
language="Groovy"
hasStaticDescription="true"
level="WARNING"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.GradleKotlinxCoroutinesDeprecationInspection"
displayName="Incompatible kotlinx.coroutines dependency is used with Kotlin 1.3+ in Gradle"
groupPath="Kotlin,Migration"
groupName="Gradle"
enabledByDefault="true"
language="Groovy"
hasStaticDescription="true"
level="ERROR"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestClassGradleConfigurationProducer"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestMethodGradleConfigurationProducer"/>
<orderEnumerationHandlerFactory implementation="org.jetbrains.kotlin.android.KotlinAndroidGradleOrderEnumerationHandler$FactoryImpl" order="first"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.scripting.idea.plugin.ScriptingGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.kapt.idea.KaptGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.noarg.ide.NoArgGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverGradleProjectImportHandler"/>
<gradleProjectImportHandler implementation="org.jetbrains.kotlinx.serialization.idea.KotlinSerializationGradleImportHandler"/>
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator"/>
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinJsGradleModuleConfigurator"/>
<gradleModelFacade implementation="org.jetbrains.kotlin.idea.inspections.gradle.DefaultGradleModelFacade"/>
<scriptDefinitionContributor implementation="org.jetbrains.kotlin.idea.core.script.GradleScriptDefinitionsContributor" order="first"/>
<buildSystemTypeDetector implementation="org.jetbrains.kotlin.idea.configuration.GradleDetector"/>
</extensions>
</idea-plugin>
-73
View File
@@ -1,73 +0,0 @@
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" version="2" url="http://kotlinlang.org" allow-bundled-update="true">
<id>org.jetbrains.kotlin</id>
<name>Kotlin</name>
<description><![CDATA[
The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<br>
<a href="http://kotlinlang.org/docs/tutorials/getting-started.html">Getting Started in IntelliJ IDEA</a><br>
<a href="http://kotlinlang.org/docs/tutorials/kotlin-android.html">Getting Started in Android Studio</a><br>
<a href="http://slack.kotlinlang.org/">Public Slack</a><br>
<a href="https://youtrack.jetbrains.com/issues/KT">Issue tracker</a><br>
]]></description>
<version>@snapshot@</version>
<vendor url="http://www.jetbrains.com">JetBrains</vendor>
<idea-version since-build="173.1" until-build="173.*"/>
<depends>com.intellij.modules.platform</depends>
<depends>com.intellij.modules.remoteServers</depends>
<!-- required for Kotlin/Native plugin -->
<depends optional="true">org.jetbrains.kotlin.native.platform.deps</depends>
<depends optional="true" config-file="junit.xml">JUnit</depends>
<depends optional="true" config-file="gradle.xml">org.jetbrains.plugins.gradle</depends>
<depends optional="true" config-file="maven.xml">org.jetbrains.idea.maven</depends>
<depends optional="true" config-file="testng-j.xml">TestNG-J</depends>
<depends optional="true" config-file="kotlin-copyright.xml">com.intellij.copyright</depends>
<depends optional="true" config-file="android.xml">org.jetbrains.android</depends>
<depends optional="true" config-file="coverage.xml">Coverage</depends>
<depends optional="true" config-file="i18n.xml">com.intellij.java-i18n</depends>
<depends optional="true" config-file="injection.xml">org.intellij.intelliLang</depends>
<depends optional="true" config-file="decompiler.xml">org.jetbrains.java.decompiler</depends>
<depends optional="true" config-file="git4idea.xml">Git4Idea</depends>
<!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
<!-- CIDR-PLUGIN-PLACEHOLDER-START -->
<depends>com.intellij.modules.java</depends>
<depends optional="true" config-file="javaScriptDebug.xml">JavaScriptDebugger</depends>
<!-- CIDR-PLUGIN-PLACEHOLDER-END -->
<xi:include href="plugin-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
<!-- CIDR-PLUGIN-EXCLUDE-START -->
<xi:include href="jvm.xml" xpointer="xpointer(/idea-plugin/*)"/>
<!-- CIDR-PLUGIN-EXCLUDE-END -->
<xi:include href="tipsAndTricks.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="extensions/ide.xml" xpointer="xpointer(/idea-plugin/*)"/>
<project-components>
<component>
<!-- This is a workaround for IDEA < 183. For details, see IDEA-200525. -->
<implementation-class>org.jetbrains.kotlin.idea.caches.ProjectRootModificationTrackerFixer</implementation-class>
</component>
</project-components>
<extensionPoints>
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<projectService serviceInterface="org.jetbrains.kotlin.idea.core.script.ScriptModificationListener"
serviceImplementation="org.jetbrains.kotlin.idea.core.script.ScriptModificationListener"/>
</extensions>
<xi:include href="plugin-kotlin-extensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
</idea-plugin>
@@ -1,366 +0,0 @@
/*
* Copyright 2010-2016 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
import com.google.common.html.HtmlEscapers
import com.intellij.codeInsight.documentation.DocumentationManagerUtil
import com.intellij.codeInsight.javadoc.JavaDocInfoGeneratorFactory
import com.intellij.lang.documentation.AbstractDocumentationProvider
import com.intellij.lang.java.JavaDocumentationProvider
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper
import org.jetbrains.kotlin.idea.kdoc.KDocRenderer
import org.jetbrains.kotlin.idea.kdoc.findKDoc
import org.jetbrains.kotlin.idea.kdoc.isBoringBuiltinClass
import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.kdoc.psi.api.KDoc
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.deprecation.deprecatedByAnnotationReplaceWithExpression
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.utils.addToStdlib.constant
class HtmlClassifierNamePolicy(val base: ClassifierNamePolicy) : ClassifierNamePolicy {
override fun renderClassifier(classifier: ClassifierDescriptor, renderer: DescriptorRenderer): String {
if (DescriptorUtils.isAnonymousObject(classifier)) {
val supertypes = classifier.typeConstructor.supertypes
return buildString {
append("&lt;anonymous object")
if (supertypes.isNotEmpty()) {
append(" : ")
supertypes.joinTo(this) {
val ref = it.constructor.declarationDescriptor
if (ref != null)
renderClassifier(ref, renderer)
else
"&lt;ERROR CLASS&gt;"
}
}
append("&gt;")
}
}
val name = base.renderClassifier(classifier, renderer)
if (classifier.isBoringBuiltinClass())
return name
return buildString {
val ref = classifier.fqNameUnsafe.toString()
DocumentationManagerUtil.createHyperlink(this, ref, name, true)
}
}
}
class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() {
override fun getQuickNavigateInfo(element: PsiElement?, originalElement: PsiElement?): String? {
return if (element == null) null else getText(element, originalElement, true)
}
override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? {
return getText(element, originalElement, false)
}
override fun getDocumentationElementForLink(psiManager: PsiManager, link: String, context: PsiElement?): PsiElement? {
val navElement = context?.navigationElement as? KtElement ?: return null
val bindingContext = navElement.analyze(BodyResolveMode.PARTIAL)
val contextDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, navElement] ?: return null
val descriptors = resolveKDocLink(bindingContext, navElement.getResolutionFacade(),
contextDescriptor, null, link.split('.'))
val target = descriptors.firstOrNull() ?: return null
return DescriptorToSourceUtilsIde.getAnyDeclaration(psiManager.project, target)
}
override fun getDocumentationElementForLookupItem(psiManager: PsiManager, `object`: Any?, element: PsiElement?): PsiElement? {
if (`object` is DeclarationLookupObject) {
`object`.psiElement?.let { return it }
`object`.descriptor?.let { descriptor ->
return DescriptorToSourceUtilsIde.getAnyDeclaration(psiManager.project, descriptor)
}
}
return null
}
companion object {
private val LOG = Logger.getInstance(KotlinQuickDocumentationProvider::class.java)
private val DESCRIPTOR_RENDERER = DescriptorRenderer.HTML.withOptions {
classifierNamePolicy = HtmlClassifierNamePolicy(ClassifierNamePolicy.SHORT)
renderCompanionObjectName = true
}
private fun renderEnumSpecialFunction(element: KtClass, functionDescriptor: FunctionDescriptor, quickNavigation: Boolean): String {
var renderedDecl = DESCRIPTOR_RENDERER.render(functionDescriptor)
if (quickNavigation) return renderedDecl
val declarationDescriptor = element.resolveToDescriptorIfAny()
val enumDescriptor = declarationDescriptor?.getSuperClassNotAny() ?: return renderedDecl
val enumDeclaration =
DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, enumDescriptor) as? KtDeclaration ?: return renderedDecl
val enumSource = SourceNavigationHelper.getNavigationElement(enumDeclaration)
val functionName = functionDescriptor.fqNameSafe.shortName().asString()
val kdoc = enumSource.findDescendantOfType<KDoc> {
it.getChildrenOfType<KDocSection>().any { it.findTagByName(functionName) != null }
}
if (kdoc != null) {
val renderedComment = KDocRenderer.renderKDoc(kdoc.getDefaultSection())
if (renderedComment.startsWith("<p>")) {
renderedDecl += renderedComment
}
else {
renderedDecl = "$renderedDecl<br/>$renderedComment"
}
}
return renderedDecl
}
private fun renderEnum(element: KtClass, originalElement: PsiElement?, quickNavigation: Boolean): String? {
val referenceExpression = originalElement?.getNonStrictParentOfType<KtReferenceExpression>()
if (referenceExpression != null) {
// When caret on special enum function (e.g SomeEnum.values<caret>())
// element is not an KtReferenceExpression, but KtClass of enum
// so reference extracted from originalElement
val context = referenceExpression.analyze(BodyResolveMode.PARTIAL)
(context[BindingContext.REFERENCE_TARGET, referenceExpression] ?:
context[BindingContext.REFERENCE_TARGET, referenceExpression.getChildOfType<KtReferenceExpression>()])?.let {
if (it is FunctionDescriptor) // To protect from Some<caret>Enum.values()
return renderEnumSpecialFunction(element, it, quickNavigation)
}
}
return renderKotlinDeclaration(element, quickNavigation)
}
private fun getText(element: PsiElement, originalElement: PsiElement?, quickNavigation: Boolean): String? {
if (element is PsiWhiteSpace) {
val itElement = findElementWithText(originalElement, "it")
val itReference = itElement?.getParentOfType<KtNameReferenceExpression>(false)
if (itReference != null) {
return getText(itReference, originalElement, quickNavigation)
}
}
if (element is KtTypeReference) {
val declaration = element.parent
if (declaration is KtCallableDeclaration && declaration.receiverTypeReference == element) {
val thisElement = findElementWithText(originalElement, "this")
if (thisElement != null) {
return getText(declaration, originalElement, quickNavigation)
}
}
}
if (element is KtClass && element.isEnum()) {
// When caret on special enum function (e.g SomeEnum.values<caret>())
// element is not an KtReferenceExpression, but KtClass of enum
return renderEnum(element, originalElement, quickNavigation)
}
else if (element is KtEnumEntry && !quickNavigation) {
val ordinal = element.containingClassOrObject?.getBody()?.run { getChildrenOfType<KtEnumEntry>().indexOf(element) }
return buildString {
append(renderKotlinDeclaration(element, quickNavigation))
ordinal?.let {
wrapTag("b") {
append("Enum constant ordinal: $ordinal")
}
}
}
}
else if (element is KtDeclaration) {
return renderKotlinDeclaration(element, quickNavigation)
}
else if (element is KtNameReferenceExpression && element.getReferencedName() == "it") {
return renderKotlinImplicitLambdaParameter(element, quickNavigation)
}
else if (element is KtLightDeclaration<*, *>) {
val origin = element.kotlinOrigin ?: return null
return renderKotlinDeclaration(origin, quickNavigation)
}
if (quickNavigation) {
val referenceExpression = originalElement?.getNonStrictParentOfType<KtReferenceExpression>()
if (referenceExpression != null) {
val context = referenceExpression.analyze(BodyResolveMode.PARTIAL)
val declarationDescriptor = context[BindingContext.REFERENCE_TARGET, referenceExpression]
if (declarationDescriptor != null) {
return mixKotlinToJava(declarationDescriptor, element, originalElement)
}
}
}
else {
// This element was resolved to non-kotlin element, it will be rendered with own provider
}
return null
}
private fun renderKotlinDeclaration(declaration: KtExpression, quickNavigation: Boolean): String {
val context = declaration.analyze(BodyResolveMode.PARTIAL)
val declarationDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]
if (declarationDescriptor == null) {
LOG.info("Failed to find descriptor for declaration " + declaration.getElementTextWithContext())
return "No documentation available"
}
return renderKotlin(context, declarationDescriptor, quickNavigation, declaration)
}
private fun renderKotlinImplicitLambdaParameter(element: KtReferenceExpression, quickNavigation: Boolean): String? {
val context = element.analyze(BodyResolveMode.PARTIAL)
val target = element.mainReference.resolveToDescriptors(context).singleOrNull() as? ValueParameterDescriptor? ?: return null
return renderKotlin(context, target, quickNavigation, element)
}
private fun renderKotlin(
context: BindingContext,
declarationDescriptor: DeclarationDescriptor,
quickNavigation: Boolean,
ktElement: KtElement
): String {
@Suppress("NAME_SHADOWING")
var declarationDescriptor = declarationDescriptor
if (declarationDescriptor is ValueParameterDescriptor) {
val property = context[BindingContext.VALUE_PARAMETER_AS_PROPERTY, declarationDescriptor]
if (property != null) {
declarationDescriptor = property
}
}
var renderedDecl = DESCRIPTOR_RENDERER.withOptions {
withDefinedIn = !DescriptorUtils.isLocal(declarationDescriptor)
}.render(declarationDescriptor)
if (!quickNavigation) {
renderedDecl = "<pre>$renderedDecl</pre>"
}
val deprecationProvider = ktElement.getResolutionFacade().frontendService<DeprecationResolver>()
renderedDecl += renderDeprecationInfo(declarationDescriptor, deprecationProvider)
if (!quickNavigation) {
val comment = declarationDescriptor.findKDoc { DescriptorToSourceUtilsIde.getAnyDeclaration(ktElement.project, it) }
if (comment != null) {
val renderedComment = KDocRenderer.renderKDoc(comment)
if (renderedComment.startsWith("<p>")) {
renderedDecl += renderedComment
}
else {
renderedDecl = "$renderedDecl<br/>$renderedComment"
}
}
else {
if (declarationDescriptor is CallableDescriptor) { // If we couldn't find KDoc, try to find javadoc in one of super's
val psi = declarationDescriptor.findPsi() as? KtFunction
if (psi != null) {
val lightElement = LightClassUtil.getLightClassMethod(psi) // Light method for super's scan in javadoc info gen
val javaDocInfoGenerator = JavaDocInfoGeneratorFactory.create(psi.project, lightElement)
val builder = StringBuilder()
if (javaDocInfoGenerator.generateDocInfoCore(builder, false))
renderedDecl += builder.toString().substringAfter("</PRE>") // Cut off light method signature
}
}
}
}
return renderedDecl
}
private fun renderDeprecationInfo(
declarationDescriptor: DeclarationDescriptor,
deprecationResolver: DeprecationResolver
): String {
val deprecation = deprecationResolver.getDeprecations(declarationDescriptor).firstOrNull() ?: return ""
return buildString {
wrapTag("DL") {
deprecation.message?.let { message ->
wrapTag("DT") { wrapTag("b") { append("Deprecated:") } }
wrapTag("DD") {
append(message.htmlEscape())
}
}
deprecation.deprecatedByAnnotationReplaceWithExpression()?.let { replaceWith ->
wrapTag("DT") { wrapTag("b") { append("Replace with:") } }
wrapTag("DD") {
wrapTag("code") { append(replaceWith.htmlEscape()) }
}
}
}
}
}
private fun String.htmlEscape(): String = HtmlEscapers.htmlEscaper().escape(this)
private inline fun StringBuilder.wrap(prefix: String, postfix: String, crossinline body: () -> Unit) {
this.append(prefix)
body()
this.append(postfix)
}
private inline fun StringBuilder.wrapTag(tag: String, crossinline body: () -> Unit) {
wrap("<$tag>", "</$tag>", body)
}
private fun mixKotlinToJava(declarationDescriptor: DeclarationDescriptor, element: PsiElement, originalElement: PsiElement?): String? {
val originalInfo = JavaDocumentationProvider().getQuickNavigateInfo(element, originalElement)
if (originalInfo != null) {
val renderedDecl = constant { DESCRIPTOR_RENDERER.withOptions { withDefinedIn = false } }.render(declarationDescriptor)
return renderedDecl + "<br/>Java declaration:<br/>" + originalInfo
}
return null
}
private fun findElementWithText(element: PsiElement?, text: String): PsiElement? {
return when {
element == null -> null
element.text == text -> element
element.prevLeaf()?.text == text -> element.prevLeaf()
else -> null
}
}
}
}
@@ -1,44 +0,0 @@
/*
* Copyright 2010-2016 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.editor
import com.intellij.codeInsight.CodeInsightSettings
import com.intellij.codeInsight.editorActions.BackspaceHandlerDelegate
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtFile
class KotlinStringTemplateBackspaceHandler : BackspaceHandlerDelegate() {
override fun beforeCharDeleted(c: Char, file: PsiFile?, editor: Editor?) {
if (c != '{' || file !is KtFile || !CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return
val offset = editor?.caretModel?.offset ?: return
val highlighter = (editor as EditorEx).highlighter
val iterator = highlighter.createIterator(offset)
if (iterator.tokenType != KtTokens.LONG_TEMPLATE_ENTRY_END) return
iterator.retreat()
if (iterator.tokenType != KtTokens.LONG_TEMPLATE_ENTRY_START) return
editor.document.deleteString(offset, offset + 1)
}
override fun charDeleted(c: Char, file: PsiFile?, editor: Editor?): Boolean {
return false
}
}
@@ -1,323 +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.idea.kdoc
import com.intellij.codeInsight.documentation.DocumentationManagerUtil
import com.intellij.psi.PsiElement
import org.intellij.markdown.IElementType
import org.intellij.markdown.MarkdownElementTypes
import org.intellij.markdown.MarkdownTokenTypes
import org.intellij.markdown.ast.ASTNode
import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
import org.intellij.markdown.parser.MarkdownParser
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.wrapTag
import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
object KDocRenderer {
fun renderKDoc(docComment: KDocTag): String {
val content = docComment.getContent()
val result = StringBuilder()
result.append(markdownToHtml(content, allowSingleParagraph = true))
if (docComment is KDocSection) {
result.append("\n")
renderTag(docComment.findTagByName("receiver"), "Receiver", result)
val paramTags = docComment.findTagsByName("param").filter { it.getSubjectName() != null }
renderTagList(paramTags, "Parameters", result)
renderTag(docComment.findTagByName("return"), "Returns", result)
val throwsTags = (docComment.findTagsByName("exception").union(docComment.findTagsByName("throws")))
.filter { it.getSubjectName() != null }
renderTagList(throwsTags, "Throws", result)
renderTag(docComment.findTagByName("author"), "Author", result)
renderTag(docComment.findTagByName("since"), "Since", result)
renderSeeAlso(docComment, result)
val sampleTags = docComment.findTagsByName("sample").filter { it.getSubjectLink() != null }
renderSamplesList(sampleTags, result)
}
return result.toString()
}
private fun KDocLink.createHyperlink(to: StringBuilder) {
DocumentationManagerUtil.createHyperlink(to, getLinkText(), getLinkText(), false)
}
private fun KDocLink.getTargetElement(): PsiElement? {
return this.getChildrenOfType<KDocName>().last().mainReference.resolve()
}
private fun PsiElement.extractExampleText() = when (this) {
is KtDeclarationWithBody -> {
val bodyExpression = bodyExpression
when (bodyExpression) {
is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}")
else -> bodyExpression!!.text
}
}
else -> text
}
private fun trimCommonIndent(text: String): String {
fun String.leadingIndent() = indexOfFirst { !it.isWhitespace() }
val lines = text.split('\n')
val minIndent = lines.filter { it.trim().isNotEmpty() }.map(String::leadingIndent).min() ?: 0
return lines.joinToString("\n") { it.drop(minIndent) }
}
private fun renderSamplesList(sampleTags: List<KDocTag>, to: StringBuilder) {
if (sampleTags.isEmpty()) return
to.apply {
wrapTag("dl") {
append("<dt><b>Samples:</b></dt>")
sampleTags.forEach {
wrapTag("dd") {
it.getSubjectLink()?.let { subjectLink ->
subjectLink.createHyperlink(to)
val target = subjectLink.getTargetElement()
wrapTag("pre") {
wrapTag("code") {
if (target == null)
to.append("// Unresolved")
else {
to.append(trimCommonIndent(target.extractExampleText()))
}
}
}
}
}
}
}
}
}
private fun renderSeeAlso(docComment: KDocSection, to: StringBuilder) {
val seeTags = docComment.findTagsByName("see")
if (seeTags.isEmpty()) return
to.append("<DD><DL>")
to.append("<DT><b>").append("See Also:").append("</b>")
to.append("<DD>")
seeTags.forEachIndexed { index, tag ->
val subjectName = tag.getSubjectName()
if (subjectName != null) {
DocumentationManagerUtil.createHyperlink(to, subjectName, subjectName, false)
}
else {
to.append(tag.getContent())
}
if (index < seeTags.size - 1) {
to.append(", ")
}
}
to.append("</DD></DL></DD>")
}
private fun renderTagList(tags: List<KDocTag>, title: String, to: StringBuilder) {
if (tags.isEmpty()) {
return
}
to.append("<dl><dt><b>$title:</b></dt>")
tags.forEach {
to.append("<dd><code>${it.getSubjectName()}</code> - ${markdownToHtml(it.getContent().trimStart())}</dd>")
}
to.append("</dl>\n")
}
private fun renderTag(tag: KDocTag?, title: String, to: StringBuilder) {
if (tag != null) {
to.append("<dl><dt><b>$title:</b></dt>")
to.append("<dd>${markdownToHtml(tag.getContent())}</dd>")
to.append("</dl>\n")
}
}
fun markdownToHtml(markdown: String, allowSingleParagraph: Boolean = false): String {
val markdownTree = MarkdownParser(CommonMarkFlavourDescriptor()).buildMarkdownTreeFromString(markdown)
val markdownNode = MarkdownNode(markdownTree, null, markdown)
// Avoid wrapping the entire converted contents in a <p> tag if it's just a single paragraph
val maybeSingleParagraph = markdownNode.children.singleOrNull { it.type != MarkdownTokenTypes.EOL }
return if (maybeSingleParagraph != null && !allowSingleParagraph) {
maybeSingleParagraph.children.joinToString("") {
if (it.text == "\n") " " else it.toHtml()
}
}
else {
markdownNode.toHtml()
}
}
class MarkdownNode(val node: ASTNode, val parent: MarkdownNode?, val markdown: String) {
val children: List<MarkdownNode> = node.children.map { MarkdownNode(it, this, markdown) }
val endOffset: Int get() = node.endOffset
val startOffset: Int get() = node.startOffset
val type: IElementType get() = node.type
val text: String get() = markdown.substring(startOffset, endOffset)
fun child(type: IElementType): MarkdownNode? = children.firstOrNull { it.type == type }
}
private fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) {
action(this) {
for (child in children) {
child.visit(action)
}
}
}
private fun MarkdownNode.toHtml(): String {
if (node.type == MarkdownTokenTypes.WHITE_SPACE) {
return text // do not trim trailing whitespace
}
val sb = StringBuilder()
visit { node, processChildren ->
fun wrapChildren(tag: String, newline: Boolean = false) {
sb.append("<$tag>")
processChildren()
sb.append("</$tag>")
if (newline) sb.appendln()
}
val nodeType = node.type
val nodeText = node.text
when (nodeType) {
MarkdownElementTypes.UNORDERED_LIST -> wrapChildren("ul", newline = true)
MarkdownElementTypes.ORDERED_LIST -> wrapChildren("ol", newline = true)
MarkdownElementTypes.LIST_ITEM -> wrapChildren("li")
MarkdownElementTypes.EMPH -> wrapChildren("em")
MarkdownElementTypes.STRONG -> wrapChildren("strong")
MarkdownElementTypes.ATX_1 -> wrapChildren("h1")
MarkdownElementTypes.ATX_2 -> wrapChildren("h2")
MarkdownElementTypes.ATX_3 -> wrapChildren("h3")
MarkdownElementTypes.ATX_4 -> wrapChildren("h4")
MarkdownElementTypes.ATX_5 -> wrapChildren("h5")
MarkdownElementTypes.ATX_6 -> wrapChildren("h6")
MarkdownElementTypes.BLOCK_QUOTE -> wrapChildren("blockquote")
MarkdownElementTypes.PARAGRAPH -> {
sb.trimEnd()
wrapChildren("p", newline = true)
}
MarkdownElementTypes.CODE_SPAN -> {
val startDelimiter = node.child(MarkdownTokenTypes.BACKTICK)?.text
if (startDelimiter != null) {
val text = node.text.substring(startDelimiter.length).removeSuffix(startDelimiter)
sb.append("<code>").append(text.htmlEscape()).append("</code>")
}
}
MarkdownElementTypes.CODE_BLOCK,
MarkdownElementTypes.CODE_FENCE -> {
sb.trimEnd()
sb.append("<pre><code>")
processChildren()
sb.append("</code></pre>")
}
MarkdownElementTypes.SHORT_REFERENCE_LINK,
MarkdownElementTypes.FULL_REFERENCE_LINK -> {
val linkLabelNode = node.child(MarkdownElementTypes.LINK_LABEL)
val linkLabelContent = linkLabelNode?.children
?.dropWhile { it.type == MarkdownTokenTypes.LBRACKET }
?.dropLastWhile { it.type == MarkdownTokenTypes.RBRACKET }
if (linkLabelContent != null) {
val label = linkLabelContent.joinToString(separator = "") { it.text }
val linkText = node.child(MarkdownElementTypes.LINK_TEXT)?.toHtml() ?: label
DocumentationManagerUtil.createHyperlink(sb, label, linkText, true)
}
else {
sb.append(node.text)
}
}
MarkdownElementTypes.INLINE_LINK -> {
val label = node.child(MarkdownElementTypes.LINK_TEXT)?.toHtml()
val destination = node.child(MarkdownElementTypes.LINK_DESTINATION)?.text
if (label != null && destination != null) {
sb.append("<a href=\"$destination\">$label</a>")
}
else {
sb.append(node.text)
}
}
MarkdownTokenTypes.TEXT,
MarkdownTokenTypes.WHITE_SPACE,
MarkdownTokenTypes.COLON,
MarkdownTokenTypes.SINGLE_QUOTE,
MarkdownTokenTypes.DOUBLE_QUOTE,
MarkdownTokenTypes.LPAREN,
MarkdownTokenTypes.RPAREN,
MarkdownTokenTypes.LBRACKET,
MarkdownTokenTypes.RBRACKET,
MarkdownTokenTypes.EXCLAMATION_MARK -> {
sb.append(nodeText)
}
MarkdownTokenTypes.CODE_LINE -> {
sb.append(nodeText.removePrefix(KDocTag.indentationWhiteSpaces).htmlEscape())
}
MarkdownTokenTypes.CODE_FENCE_CONTENT -> {
sb.append(nodeText.htmlEscape())
}
MarkdownTokenTypes.EOL -> {
val parentType = node.parent?.type
if (parentType == MarkdownElementTypes.CODE_BLOCK || parentType == MarkdownElementTypes.CODE_FENCE) {
sb.append("\n")
}
else {
sb.append(" ")
}
}
MarkdownTokenTypes.GT -> sb.append("&gt;")
MarkdownTokenTypes.LT -> sb.append("&lt;")
MarkdownElementTypes.LINK_TEXT -> {
val childrenWithoutBrackets = node.children.drop(1).dropLast(1)
for (child in childrenWithoutBrackets) {
sb.append(child.toHtml())
}
}
MarkdownTokenTypes.EMPH -> {
val parentNodeType = node.parent?.type
if (parentNodeType != MarkdownElementTypes.EMPH && parentNodeType != MarkdownElementTypes.STRONG) {
sb.append(node.text)
}
}
else -> {
processChildren()
}
}
}
return sb.toString().trimEnd()
}
private fun StringBuilder.trimEnd() {
while (length > 0 && this[length - 1] == ' ') {
deleteCharAt(length - 1)
}
}
private fun String.htmlEscape(): String = replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
}
@@ -1,397 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.crossLanguage
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.QuickFixFactory
import com.intellij.lang.jvm.*
import com.intellij.lang.jvm.actions.*
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.appendModifier
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateCallableFromUsageFix
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.approximateFlexibleTypes
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.load.java.components.TypeUsage
import org.jetbrains.kotlin.load.java.lazy.JavaResolverComponents
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
import org.jetbrains.kotlin.load.java.lazy.child
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeAttributes
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeParameterImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.supertypes
class KotlinElementActionsFactory : JvmElementActionsFactory() {
companion object {
val javaPsiModifiersMapping = mapOf(
JvmModifier.PRIVATE to KtTokens.PRIVATE_KEYWORD,
JvmModifier.PUBLIC to KtTokens.PUBLIC_KEYWORD,
JvmModifier.PROTECTED to KtTokens.PUBLIC_KEYWORD,
JvmModifier.ABSTRACT to KtTokens.ABSTRACT_KEYWORD
)
}
private class FakeExpressionFromParameter(private val psiParam: PsiParameter) : PsiReferenceExpressionImpl() {
override fun getText(): String = psiParam.name!!
override fun getProject(): Project = psiParam.project
override fun getParent(): PsiElement = psiParam.parent
override fun getType(): PsiType? = psiParam.type
override fun isValid(): Boolean = true
override fun getContainingFile(): PsiFile = psiParam.containingFile
override fun getReferenceName(): String? = psiParam.name
override fun resolve(): PsiElement? = psiParam
}
private class ModifierBuilder(
private val targetContainer: KtElement,
private val allowJvmStatic: Boolean = true
) {
private val psiFactory = KtPsiFactory(targetContainer.project)
val modifierList = psiFactory.createEmptyModifierList()
private fun JvmModifier.transformAndAppend(): Boolean {
javaPsiModifiersMapping[this]?.let {
modifierList.appendModifier(it)
return true
}
when (this) {
JvmModifier.STATIC -> {
if (allowJvmStatic && targetContainer is KtClassOrObject) {
addAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME)
}
}
JvmModifier.ABSTRACT -> modifierList.appendModifier(KtTokens.ABSTRACT_KEYWORD)
JvmModifier.FINAL -> modifierList.appendModifier(KtTokens.FINAL_KEYWORD)
else -> return false
}
return true
}
var isValid = true
private set
fun addJvmModifier(modifier: JvmModifier) {
isValid = isValid && modifier.transformAndAppend()
}
fun addJvmModifiers(modifiers: Iterable<JvmModifier>) {
modifiers.forEach { addJvmModifier(it) }
}
fun addAnnotation(fqName: FqName) {
if (!isValid) return
modifierList.add(psiFactory.createAnnotationEntry("@${fqName.asString()}"))
}
}
class CreatePropertyFix(
private val targetClass: JvmClass,
contextElement: KtElement,
propertyInfo: PropertyInfo
) : CreateCallableFromUsageFix<KtElement>(contextElement, listOf(propertyInfo)) {
override fun getFamilyName() = "Add property"
override fun getText(): String {
val info = callableInfos.first() as PropertyInfo
return buildString {
append("Add '")
if (info.isLateinitPreferred) {
append("lateinit ")
}
append(if (info.writable) "var" else "val")
append("' property '${info.name}' to '${targetClass.name}'")
}
}
}
private fun JvmClass.toKtClassOrFile(): KtElement? {
val psi = sourceElement
return when (psi) {
is KtClassOrObject -> psi
is KtLightClassForSourceDeclaration -> psi.kotlinOrigin
is KtLightClassForFacade -> psi.files.firstOrNull()
else -> null
}
}
private inline fun <reified T : KtElement> JvmElement.toKtElement() = sourceElement?.unwrapped as? T
private fun fakeParametersExpressions(parameters: List<JvmParameter>, project: Project): Array<PsiExpression>? =
when {
parameters.isEmpty() -> emptyArray()
else -> JavaPsiFacade
.getElementFactory(project)
.createParameterList(
parameters.map { it.name }.toTypedArray(),
parameters.map { it.type as? PsiType ?: return null }.toTypedArray()
)
.parameters
.map(::FakeExpressionFromParameter)
.toTypedArray()
}
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
val results = ArrayList<PsiTypeParameter>()
accept(
object : PsiTypeVisitor<Unit>() {
override fun visitArrayType(arrayType: PsiArrayType) {
arrayType.componentType.accept(this)
}
override fun visitClassType(classType: PsiClassType) {
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
classType.parameters.forEach { it.accept(this) }
}
override fun visitWildcardType(wildcardType: PsiWildcardType) {
wildcardType.bound?.accept(this)
}
}
)
return results
}
private fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType? {
val typeParameters = collectTypeParameters()
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
val dummyClassDescriptor = ClassDescriptorImpl(
dummyPackageDescriptor,
Name.identifier("Dummy"),
Modality.FINAL,
ClassKind.CLASS,
emptyList(),
SourceElement.NO_SOURCE,
false,
LockBasedStorageManager.NO_LOCKS
)
val typeParameterResolver = object : TypeParameterResolver {
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
val index = typeParameters.indexOf(psiTypeParameter)
if (index < 0) return null
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
}
}
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
}
private fun ExpectedTypes.toKotlinTypeInfo(resolutionFacade: ResolutionFacade): TypeInfo {
val candidateTypes = flatMapTo(LinkedHashSet<KotlinType>()) {
val ktType = (it.theType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: return@flatMapTo emptyList()
when (it.theKind) {
ExpectedType.Kind.EXACT, ExpectedType.Kind.SUBTYPE -> listOf(ktType)
ExpectedType.Kind.SUPERTYPE -> listOf(ktType) + ktType.supertypes()
}
}
if (candidateTypes.isEmpty()) {
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
return TypeInfo(nullableAnyType, Variance.INVARIANT)
}
return TypeInfo.ByExplicitCandidateTypes(candidateTypes.toList())
}
override fun createChangeModifierActions(target: JvmModifiersOwner, request: MemberRequest.Modifier): List<IntentionAction> {
val kModifierOwner = target.toKtElement<KtModifierListOwner>() ?: return emptyList()
val modifier = request.modifier
val shouldPresent = request.shouldPresent
val (kToken, shouldPresentMapped) = if (JvmModifier.FINAL == modifier)
KtTokens.OPEN_KEYWORD to !shouldPresent
else
javaPsiModifiersMapping[modifier] to shouldPresent
if (kToken == null) return emptyList()
val action = if (shouldPresentMapped)
AddModifierFix.createIfApplicable(kModifierOwner, kToken)
else
RemoveModifierFix(kModifierOwner, kToken, false)
return listOfNotNull(action)
}
override fun createAddConstructorActions(targetClass: JvmClass, request: MemberRequest.Constructor): List<IntentionAction> {
val targetKtClass = targetClass.toKtClassOrFile() as? KtClass ?: return emptyList()
if (request.typeParameters.isNotEmpty()) return emptyList()
val modifierBuilder = ModifierBuilder(targetKtClass).apply { addJvmModifiers(request.modifiers) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetKtClass.getResolutionFacade()
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
val parameterInfos = request.parameters.mapIndexed { index, param ->
val ktType = (param.type as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
val name = param.name ?: "arg${index + 1}"
ParameterInfo(TypeInfo(ktType, Variance.IN_VARIANCE), listOf(name))
}
val needPrimary = !targetKtClass.hasExplicitPrimaryConstructor()
val constructorInfo = ConstructorInfo(
parameterInfos,
targetKtClass,
isPrimary = needPrimary,
modifierList = modifierBuilder.modifierList,
withBody = true
)
val targetClassName = targetClass.name
val addConstructorAction = object : CreateCallableFromUsageFix<KtElement>(targetKtClass, listOf(constructorInfo)) {
override fun getFamilyName() = "Add method"
override fun getText() = "Add ${if (needPrimary) "primary" else "secondary"} constructor to '$targetClassName'"
}
val changePrimaryConstructorAction = run {
val primaryConstructor = targetKtClass.primaryConstructor ?: return@run null
val lightMethod = primaryConstructor.toLightMethods().firstOrNull() ?: return@run null
val project = targetKtClass.project
val fakeParametersExpressions = fakeParametersExpressions(request.parameters, project) ?: return@run null
QuickFixFactory.getInstance()
.createChangeMethodSignatureFromUsageFix(
lightMethod,
fakeParametersExpressions,
PsiSubstitutor.EMPTY,
targetKtClass,
false,
2
).takeIf { it.isAvailable(project, null, targetKtClass.containingFile) }
}
return listOfNotNull(changePrimaryConstructorAction, addConstructorAction)
}
override fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifier(request.visibilityModifier) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetContainer.getResolutionFacade()
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
val ktType = (request.propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
val propertyInfo = PropertyInfo(
request.propertyName,
TypeInfo.Empty,
TypeInfo(ktType, Variance.INVARIANT),
request.setterRequired,
listOf(targetContainer),
modifierList = modifierBuilder.modifierList,
withInitializer = true
)
val propertyInfos = if (request.setterRequired) {
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
}
else {
listOf(propertyInfo)
}
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
}
override fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
val modifierBuilder = ModifierBuilder(targetContainer, allowJvmStatic = false).apply {
addJvmModifiers(request.modifiers)
addAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME)
}
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetContainer.getResolutionFacade()
val typeInfo = request.fieldType.toKotlinTypeInfo(resolutionFacade)
val writable = JvmModifier.FINAL !in request.modifiers
val propertyInfo = PropertyInfo(
request.fieldName,
TypeInfo.Empty,
typeInfo,
writable,
listOf(targetContainer),
isForCompanion = JvmModifier.STATIC in request.modifiers,
modifierList = modifierBuilder.modifierList,
withInitializer = true
)
val propertyInfos = if (writable) {
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
}
else {
listOf(propertyInfo)
}
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
}
override fun createAddMethodActions(targetClass: JvmClass, request: CreateMethodRequest): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifiers(request.modifiers) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = KotlinCacheService.getInstance(targetContainer.project)
.getResolutionFacadeByFile(targetContainer.containingFile, JvmPlatform) ?: return emptyList()
val returnTypeInfo = request.returnType.toKotlinTypeInfo(resolutionFacade)
val parameterInfos = request.parameters.map { (suggestedNames, expectedTypes) ->
ParameterInfo(expectedTypes.toKotlinTypeInfo(resolutionFacade), suggestedNames.names.toList())
}
val methodName = request.methodName
val functionInfo = FunctionInfo(
methodName,
TypeInfo.Empty,
returnTypeInfo,
listOf(targetContainer),
parameterInfos,
isForCompanion = JvmModifier.STATIC in request.modifiers,
modifierList = modifierBuilder.modifierList,
preferEmptyBody = true
)
val targetClassName = targetClass.name
val action = object : CreateCallableFromUsageFix<KtElement>(targetContainer, listOf(functionInfo)) {
override fun getFamilyName() = "Add method"
override fun getText() = "Add method '$methodName' to '$targetClassName'"
}
return listOf(action)
}
}
@@ -1,124 +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.idea.refactoring.changeSignature.ui
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClassOwner
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.changeSignature.CallerChooserBase
import com.intellij.refactoring.changeSignature.MethodNodeBase
import com.intellij.ui.ColoredTreeCellRenderer
import com.intellij.ui.JBColor
import com.intellij.ui.SimpleTextAttributes
import com.intellij.ui.treeStructure.Tree
import com.intellij.util.Consumer
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMethodDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.hierarchy.calls.CalleeReferenceProcessor
import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCallHierarchyNodeDescriptor
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import java.util.*
class KotlinCallerChooser(
declaration: PsiElement,
project: Project,
title: String,
previousTree: Tree?,
callback: Consumer<Set<PsiElement>>
): CallerChooserBase<PsiElement>(declaration, project, title, previousTree, "dummy." + KotlinFileType.EXTENSION, callback) {
override fun createTreeNode(method: PsiElement?, called: com.intellij.util.containers.HashSet<PsiElement>, cancelCallback: Runnable): KotlinMethodNode {
return KotlinMethodNode(method, called, myProject, cancelCallback)
}
override fun findDeepestSuperMethods(method: PsiElement) =
method.toLightMethods().singleOrNull()?.findDeepestSuperMethods()
override fun getEmptyCallerText() =
"Caller text \nwith highlighted callee call would be shown here"
override fun getEmptyCalleeText() =
"Callee text would be shown here"
}
class KotlinMethodNode(
method: PsiElement?,
called: HashSet<PsiElement>,
project: Project,
cancelCallback: Runnable
): MethodNodeBase<PsiElement>(method?.namedUnwrappedElement ?: method, called, project, cancelCallback) {
override fun createNode(caller: PsiElement, called: HashSet<PsiElement>) =
KotlinMethodNode(caller, called, myProject, myCancelCallback)
override fun customizeRendererText(renderer: ColoredTreeCellRenderer) {
val descriptor = when (myMethod) {
is KtFunction -> myMethod.unsafeResolveToDescriptor() as FunctionDescriptor
is KtClass -> (myMethod.unsafeResolveToDescriptor() as ClassDescriptor).unsubstitutedPrimaryConstructor ?: return
is PsiMethod -> myMethod.getJavaMethodDescriptor() ?: return
else -> throw AssertionError("Invalid declaration: ${myMethod.getElementTextWithContext()}")
}
val containerName = generateSequence<DeclarationDescriptor>(descriptor) { it.containingDeclaration }
.firstOrNull { it is ClassDescriptor }
?.name
val renderedFunction = KotlinCallHierarchyNodeDescriptor.renderNamedFunction(descriptor)
val renderedFunctionWithContainer =
containerName?.let {
"${if (it.isSpecial) "[Anonymous]" else it.asString()}.$renderedFunction"
} ?: renderedFunction
val attributes = if (isEnabled)
SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, UIUtil.getTreeForeground())
else
SimpleTextAttributes.EXCLUDED_ATTRIBUTES
renderer.append(renderedFunctionWithContainer, attributes)
val packageName = (myMethod.containingFile as? PsiClassOwner)?.packageName ?: ""
renderer.append(" ($packageName)", SimpleTextAttributes(SimpleTextAttributes.STYLE_ITALIC, JBColor.GRAY))
}
override fun computeCallers(): List<PsiElement> {
if (myMethod == null) return emptyList()
val callers = LinkedHashSet<PsiElement>()
val processor = object: CalleeReferenceProcessor(false) {
override fun onAccept(ref: PsiReference, element: PsiElement) {
if ((element is KtFunction || element is KtClass || element is PsiMethod) && element !in myCalled) {
callers.add(element)
}
}
}
val query = myMethod.getRepresentativeLightMethod()?.let { MethodReferencesSearch.search(it, it.useScope, true) }
?: ReferencesSearch.search(myMethod, myMethod.useScope)
query.forEach { processor.process(it) }
return callers.toList()
}
}
@@ -1,184 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.copy
import com.intellij.ide.util.DirectoryChooser
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.JavaProjectRootsUtil
import com.intellij.openapi.ui.DialogWrapper
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiManager
import com.intellij.refactoring.HelpID
import com.intellij.refactoring.MoveDestination
import com.intellij.refactoring.PackageWrapper
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesDialog
import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo
import com.intellij.ui.EditorTextField
import com.intellij.ui.RecentsManager
import com.intellij.ui.ReferenceEditorComboWithBrowseButton
import com.intellij.usageView.UsageViewUtil
import com.intellij.util.IncorrectOperationException
import com.intellij.util.ui.FormBuilder
import com.intellij.util.ui.UIUtil
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.refactoring.Pass
import org.jetbrains.kotlin.idea.refactoring.hasIdentifiersOnly
import org.jetbrains.kotlin.idea.refactoring.ui.KotlinDestinationFolderComboBox
import org.jetbrains.kotlin.idea.util.sourceRoot
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import java.awt.BorderLayout
import java.awt.Font
import javax.swing.JComponent
import javax.swing.JLabel
import javax.swing.JPanel
// Based on com.intellij.refactoring.copy.CopyClassDialog
class CopyKotlinDeclarationDialog(
declaration: KtNamedDeclaration,
private val defaultTargetDirectory: PsiDirectory?,
private val project: Project
) : DialogWrapper(project, true) {
private val informationLabel = JLabel()
private val classNameField = EditorTextField("")
private val packageLabel = JLabel()
private lateinit var packageNameField: ReferenceEditorComboWithBrowseButton
private val openInEditorCheckBox = CopyFilesOrDirectoriesDialog.createOpenInEditorCB()
private val destinationComboBox = object : KotlinDestinationFolderComboBox() {
override fun getTargetPackage() = packageNameField.text.trim()
override fun reportBaseInTestSelectionInSource() = true
}
private val originalFile = declaration.containingFile
var targetDirectory: MoveDestination? = null
private set
val targetSourceRoot: VirtualFile?
get() = ((destinationComboBox.comboBox.selectedItem as? DirectoryChooser.ItemWrapper)?.directory ?: originalFile).sourceRoot
init {
informationLabel.text = RefactoringBundle.message("copy.class.copy.0.1", UsageViewUtil.getType(declaration), UsageViewUtil.getLongName(declaration))
informationLabel.font = informationLabel.font.deriveFont(Font.BOLD)
init()
destinationComboBox.setData(
project,
defaultTargetDirectory,
Pass { setErrorText(it, destinationComboBox) },
packageNameField.childComponent
)
classNameField.text = UsageViewUtil.getShortName(declaration)
classNameField.selectAll()
}
override fun getPreferredFocusedComponent() = classNameField
override fun createCenterPanel() = JPanel(BorderLayout())
override fun createNorthPanel(): JComponent? {
val qualifiedName = qualifiedName
packageNameField = PackageNameReferenceEditorCombo(qualifiedName, project, RECENTS_KEY, RefactoringBundle.message("choose.destination.package"))
packageNameField.setTextFieldPreferredWidth(Math.max(qualifiedName.length + 5, 40))
packageLabel.text = RefactoringBundle.message("destination.package")
packageLabel.labelFor = packageNameField
val label = JLabel(RefactoringBundle.message("target.destination.folder"))
val isMultipleSourceRoots = JavaProjectRootsUtil.getSuitableDestinationSourceRoots(project).size > 1
destinationComboBox.isVisible = isMultipleSourceRoots
label.isVisible = isMultipleSourceRoots
label.labelFor = destinationComboBox
val panel = JPanel(BorderLayout())
panel.add(openInEditorCheckBox, BorderLayout.EAST)
return FormBuilder.createFormBuilder()
.addComponent(informationLabel)
.addLabeledComponent(RefactoringBundle.message("copy.files.new.name.label"), classNameField, UIUtil.LARGE_VGAP)
.addLabeledComponent(packageLabel, packageNameField)
.addLabeledComponent(label, destinationComboBox)
.addComponent(panel)
.panel
}
private val qualifiedName: String
get() = defaultTargetDirectory?.getPackage()?.qualifiedName ?: ""
val newName: String?
get() = classNameField.text
val openInEditor: Boolean
get() = openInEditorCheckBox.isSelected
private fun checkForErrors(): String? {
val packageName = packageNameField.text
val newName = newName
val manager = PsiManager.getInstance(project)
if (packageName.isNotEmpty() && !FqNameUnsafe(packageName).hasIdentifiersOnly()) {
return RefactoringBundle.message("invalid.target.package.name.specified")
}
if (newName.isNullOrEmpty()) {
return RefactoringBundle.message("no.class.name.specified")
}
try {
targetDirectory = destinationComboBox.selectDirectory(PackageWrapper(manager, packageName), false)
}
catch (e: IncorrectOperationException) {
return e.message
}
targetDirectory?.getTargetIfExists(defaultTargetDirectory)?.let {
val targetFileName = newName + "." + originalFile.virtualFile.extension
if (it.findFile(targetFileName) == originalFile) {
return "Can't copy class to the containing file"
}
}
return null
}
override fun doOKAction() {
val packageName = packageNameField.text
val errorString = checkForErrors()
if (errorString != null) {
if (errorString.isNotEmpty()) {
Messages.showMessageDialog(project, errorString, RefactoringBundle.message("error.title"), Messages.getErrorIcon())
}
classNameField.requestFocusInWindow()
return
}
RecentsManager.getInstance(project).registerRecentEntry(RECENTS_KEY, packageName)
CopyFilesOrDirectoriesDialog.saveOpenInEditorState(openInEditorCheckBox.isSelected)
super.doOKAction()
}
override fun getHelpId() = HelpID.COPY_CLASS
companion object {
@NonNls private val RECENTS_KEY = "CopyKotlinDeclarationDialog.RECENTS_KEY"
}
}
@@ -1,35 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.move.moveClassesOrPackages
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiPackage
import com.intellij.refactoring.MoveDestination
import com.intellij.refactoring.move.MoveCallback
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesToNewDirectoryDialog
class KotlinAwareMoveClassesOrPackagesToNewDirectoryDialog(
directory: PsiDirectory,
elementsToMove: Array<out PsiElement>,
moveCallback: MoveCallback?
) : MoveClassesOrPackagesToNewDirectoryDialog(directory, elementsToMove, moveCallback) {
override fun createDestination(aPackage: PsiPackage, directory: PsiDirectory): MoveDestination {
val delegate = super.createDestination(aPackage, directory)
return KotlinAwareDelegatingMoveDestination(delegate, aPackage, directory)
}
}
@@ -1,182 +0,0 @@
/*
* Copyright 2010-2016 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.refactoring.move.moveDeclarations
import com.intellij.psi.PsiElement
import com.intellij.refactoring.move.moveInner.MoveInnerClassUsagesHandler
import com.intellij.refactoring.util.MoveRenameUsageInfo
import com.intellij.usageView.UsageInfo
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.shorten.isToBeShortened
import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
sealed class MoveDeclarationsDelegate {
abstract fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo
open fun findInternalUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo> = emptyList()
open fun collectConflicts(
descriptor: MoveDeclarationsDescriptor,
internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String>
) {
}
open fun preprocessDeclaration(descriptor: MoveDeclarationsDescriptor, originalDeclaration: KtNamedDeclaration) {
}
open fun preprocessUsages(descriptor: MoveDeclarationsDescriptor, usages: List<UsageInfo>) {
}
object TopLevel : MoveDeclarationsDelegate() {
override fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo {
val sourcePackage = ContainerInfo.Package(originalDeclaration.containingKtFile.packageFqName)
val targetPackage = moveTarget.targetContainerFqName?.let { ContainerInfo.Package(it) } ?: ContainerInfo.UnknownPackage
return ContainerChangeInfo(sourcePackage, targetPackage)
}
}
class NestedClass(
val newClassName: String? = null,
val outerInstanceParameterName: String? = null
) : MoveDeclarationsDelegate() {
override fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo {
val originalInfo = ContainerInfo.Class(originalDeclaration.containingClassOrObject!!.fqName!!)
val movingToClass = (moveTarget as? KotlinMoveTargetForExistingElement)?.targetElement is KtClassOrObject
val targetContainerFqName = moveTarget.targetContainerFqName
val newInfo = when {
targetContainerFqName == null -> ContainerInfo.UnknownPackage
movingToClass -> ContainerInfo.Class(targetContainerFqName)
else -> ContainerInfo.Package(targetContainerFqName)
}
return ContainerChangeInfo(originalInfo, newInfo)
}
override fun findInternalUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo> {
val classToMove = descriptor.moveSource.elementsToMove.singleOrNull() as? KtClass ?: return emptyList()
return collectOuterInstanceReferences(classToMove)
}
private fun isValidTargetForImplicitCompanionAsDispatchReceiver(
moveDescriptor: MoveDeclarationsDescriptor,
companionDescriptor: ClassDescriptor
): Boolean {
val moveTarget = moveDescriptor.moveTarget
return when (moveTarget) {
is KotlinMoveTargetForCompanion -> true
is KotlinMoveTargetForExistingElement -> {
val targetClass = moveTarget.targetElement as? KtClassOrObject ?: return false
val targetClassDescriptor = targetClass.unsafeResolveToDescriptor() as ClassDescriptor
val companionClassDescriptor = companionDescriptor.containingDeclaration as? ClassDescriptor ?: return false
targetClassDescriptor.isSubclassOf(companionClassDescriptor)
}
else -> false
}
}
override fun collectConflicts(
descriptor: MoveDeclarationsDescriptor,
internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String>
) {
val usageIterator = internalUsages.iterator()
while (usageIterator.hasNext()) {
val usage = usageIterator.next()
val element = usage.element ?: continue
val isConflict = when (usage) {
is ImplicitCompanionAsDispatchReceiverUsageInfo -> {
if (!isValidTargetForImplicitCompanionAsDispatchReceiver(descriptor, usage.companionDescriptor)) {
conflicts.putValue(element, "Implicit companion object will be inaccessible: ${element.text}")
}
true
}
is OuterInstanceReferenceUsageInfo -> usage.reportConflictIfAny(conflicts)
else -> false
}
if (isConflict) {
usageIterator.remove()
}
}
}
override fun preprocessDeclaration(descriptor: MoveDeclarationsDescriptor, originalDeclaration: KtNamedDeclaration) {
with(originalDeclaration) {
newClassName?.let { setName(it) }
if (this is KtClass) {
if ((descriptor.moveTarget as? KotlinMoveTargetForExistingElement)?.targetElement !is KtClassOrObject) {
if (hasModifier(KtTokens.INNER_KEYWORD)) removeModifier(KtTokens.INNER_KEYWORD)
if (hasModifier(KtTokens.PROTECTED_KEYWORD)) removeModifier(KtTokens.PROTECTED_KEYWORD)
}
if (outerInstanceParameterName != null) {
val type = (containingClassOrObject!!.unsafeResolveToDescriptor() as ClassDescriptor).defaultType
val parameter = KtPsiFactory(project)
.createParameter("private val $outerInstanceParameterName: ${IdeDescriptorRenderers.SOURCE_CODE.renderType(type)}")
createPrimaryConstructorParameterListIfAbsent().addParameter(parameter).isToBeShortened = true
}
}
}
}
override fun preprocessUsages(descriptor: MoveDeclarationsDescriptor, usages: List<UsageInfo>) {
if (outerInstanceParameterName == null) return
val psiFactory = KtPsiFactory(descriptor.project)
val newOuterInstanceRef = psiFactory.createExpression(outerInstanceParameterName)
val classToMove = descriptor.moveSource.elementsToMove.singleOrNull() as? KtClass
for (usage in usages) {
if (usage is MoveRenameUsageInfo) {
val referencedNestedClass = usage.referencedElement?.unwrapped as? KtClassOrObject
if (referencedNestedClass == classToMove) {
val outerClass = referencedNestedClass?.containingClassOrObject
val lightOuterClass = outerClass?.toLightClass()
if (lightOuterClass != null) {
MoveInnerClassUsagesHandler.EP_NAME
.forLanguage(usage.element!!.language)
?.correctInnerClassUsage(usage, lightOuterClass)
}
}
}
when (usage) {
is OuterInstanceReferenceUsageInfo.ExplicitThis -> {
usage.expression?.replace(newOuterInstanceRef)
}
is OuterInstanceReferenceUsageInfo.ImplicitReceiver -> {
usage.callElement?.let { it.replace(psiFactory.createExpressionByPattern("$0.$1", outerInstanceParameterName, it)) }
}
}
}
}
}
}
@@ -1,150 +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.idea.refactoring.move.moveFilesOrDirectories
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesHelper
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
import com.intellij.usageView.UsageInfo
import com.intellij.util.Function
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.refactoring.invokeOnceOnCommandFinish
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinDirectoryMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.analyzeConflictsInFile
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import java.util.*
class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
private data class FileUsagesWrapper(
val psiFile: KtFile,
val usages: List<UsageInfo>,
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
) : UsageInfo(psiFile)
private class MoveContext(
val newParent: PsiDirectory,
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
)
private val fileHandler = MoveKotlinFileHandler()
private var fileToMoveContext: MutableMap<PsiFile, MoveContext>? = null
private fun getOrCreateMoveContextMap(): MutableMap<PsiFile, MoveContext> {
return fileToMoveContext ?: HashMap<PsiFile, MoveContext>().apply {
fileToMoveContext = this
invokeOnceOnCommandFinish { fileToMoveContext = null }
}
}
override fun findUsages(
filesToMove: MutableCollection<PsiFile>,
directoriesToMove: Array<out PsiDirectory>,
result: MutableCollection<UsageInfo>,
searchInComments: Boolean,
searchInNonJavaFiles: Boolean,
project: Project) {
filesToMove
.filterIsInstance<KtFile>()
.mapTo(result) { FileUsagesWrapper(it, fileHandler.findUsages(it, null, false), null) }
}
override fun preprocessUsages(
project: Project,
files: MutableSet<PsiFile>,
infos: Array<UsageInfo>,
directory: PsiDirectory?,
conflicts: MultiMap<PsiElement, String>
) {
val psiPackage = directory?.getPackage() ?: return
val moveTarget = KotlinDirectoryMoveTarget(FqName(psiPackage.qualifiedName), directory)
for ((index, usageInfo) in infos.withIndex()) {
if (usageInfo !is FileUsagesWrapper) continue
project.runSynchronouslyWithProgress("Analyzing conflicts in ${usageInfo.psiFile.name}", false) {
runReadAction {
analyzeConflictsInFile(usageInfo.psiFile, usageInfo.usages, moveTarget, files, conflicts) {
infos[index] = usageInfo.copy(usages = it)
}
}
}
}
}
override fun beforeMove(psiFile: PsiFile) {
}
// Actual move logic is implemented in postProcessUsages since usages are not available here
override fun move(
file: PsiFile,
moveDestination: PsiDirectory,
oldToNewElementsMapping: MutableMap<PsiElement, PsiElement>,
movedFiles: MutableList<PsiFile>,
listener: RefactoringElementListener?
): Boolean {
if (file !is KtFile) return false
val moveDeclarationsProcessor = fileHandler.initMoveProcessor(file, moveDestination, false)
val moveContextMap = getOrCreateMoveContextMap()
moveContextMap[file] = MoveContext(moveDestination, moveDeclarationsProcessor)
if (moveDeclarationsProcessor != null) {
moveDestination.getPackage()?.let { newPackage ->
file.packageDirective?.fqName = FqName(newPackage.qualifiedName).quoteIfNeeded()
}
}
return true
}
override fun afterMove(newElement: PsiElement) {
}
override fun postProcessUsages(usages: Array<out UsageInfo>, newDirMapper: Function<PsiDirectory, PsiDirectory>) {
val fileToMoveContext = fileToMoveContext ?: return
try {
val usagesToProcess = ArrayList<FileUsagesWrapper>()
usages
.filterIsInstance<FileUsagesWrapper>()
.forEach body@ {
val file = it.psiFile
val moveContext = fileToMoveContext[file] ?: return@body
MoveFilesOrDirectoriesUtil.doMoveFile(file, moveContext.newParent)
val moveDeclarationsProcessor = moveContext.moveDeclarationsProcessor ?: return@body
val movedFile = moveContext.newParent.findFile(file.name) ?: return@body
usagesToProcess += FileUsagesWrapper(movedFile as KtFile, it.usages, moveDeclarationsProcessor)
}
usagesToProcess.forEach { fileHandler.retargetUsages(it.usages, it.moveDeclarationsProcessor!!) }
}
finally {
this.fileToMoveContext = null
}
}
}
@@ -1,144 +0,0 @@
/*
* Copyright 2010-2016 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.refactoring.rename
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.refactoring.rename.RenamePsiElementProcessor
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.refactoring.withExpectedActuals
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.utils.SmartList
import java.util.*
class RenameKotlinClassifierProcessor : RenameKotlinPsiProcessor() {
override fun canProcessElement(element: PsiElement): Boolean {
return element is KtClassOrObject || element is KtLightClass || element is KtConstructor<*> || element is KtTypeAlias
}
override fun isToSearchInComments(psiElement: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS
override fun setToSearchInComments(element: PsiElement, enabled: Boolean) {
JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_CLASS = enabled
}
override fun isToSearchForTextOccurrences(element: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS
override fun setToSearchForTextOccurrences(element: PsiElement, enabled: Boolean) {
JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_CLASS = enabled
}
override fun substituteElementToRename(element: PsiElement, editor: Editor?) = getClassOrObject(element)
override fun prepareRenaming(element: PsiElement, newName: String, allRenames: MutableMap<PsiElement, String>) {
super.prepareRenaming(element, newName, allRenames)
val classOrObject = getClassOrObject(element) as? KtClassOrObject ?: return
classOrObject.withExpectedActuals().forEach {
val file = it.containingKtFile
val virtualFile = file.virtualFile
if (virtualFile != null) {
val nameWithoutExtensions = virtualFile.nameWithoutExtension
if (nameWithoutExtensions == it.name) {
val newFileName = newName + "." + virtualFile.extension
allRenames.put(file, newFileName)
RenamePsiElementProcessor.forElement(file).prepareRenaming(file, newFileName, allRenames)
}
}
}
}
override fun findReferences(element: PsiElement): Collection<PsiReference> {
if (element is KtObjectDeclaration && element.isCompanion()) {
return super.findReferences(element).filter { !it.isCompanionObjectClassReference() }
}
return super.findReferences(element)
}
private fun PsiReference.isCompanionObjectClassReference(): Boolean {
if (this !is KtSimpleNameReference) {
return false
}
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
return bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, element] != null
}
override fun findCollisions(
element: PsiElement,
newName: String?,
allRenames: MutableMap<out PsiElement, String>,
result: MutableList<UsageInfo>
) {
if (newName == null) return
val declaration = element.namedUnwrappedElement as? KtNamedDeclaration ?: return
val descriptor = declaration.unsafeResolveToDescriptor() as ClassifierDescriptor
val collisions = SmartList<UsageInfo>()
checkRedeclarations(descriptor, newName, collisions)
checkOriginalUsagesRetargeting(declaration, newName, result, collisions)
checkNewNameUsagesRetargeting(declaration, newName, collisions)
result += collisions
}
private fun getClassOrObject(element: PsiElement?): PsiElement? = when (element) {
is KtLightClass ->
when (element) {
is KtLightClassForSourceDeclaration -> element.kotlinOrigin
is KtLightClassForFacade -> element
else -> throw AssertionError("Should not be suggested to rename element of type " + element::class.java + " " + element)
}
is KtConstructor<*> ->
element.getContainingClassOrObject()
is KtClassOrObject, is KtTypeAlias -> element
else -> null
}
override fun renameElement(element: PsiElement, newName: String?, usages: Array<out UsageInfo>, listener: RefactoringElementListener?) {
val simpleUsages = ArrayList<UsageInfo>(usages.size)
val ambiguousImportUsages = com.intellij.util.SmartList<UsageInfo>()
for (usage in usages) {
if (usage.isAmbiguousImportUsage()) {
ambiguousImportUsages += usage
}
else {
simpleUsages += usage
}
}
element.ambiguousImportUsages = ambiguousImportUsages
super.renameElement(element, newName, simpleUsages.toTypedArray(), listener)
usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() }
}
}
@@ -1,80 +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.idea.refactoring.rename
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiReference
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.refactoring.rename.RenamePsiFileProcessor
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import org.jetbrains.kotlin.statistics.KotlinStatisticsTrigger
class RenameKotlinFileProcessor : RenamePsiFileProcessor() {
class FileRenamingPsiClassWrapper(
private val psiClass: KtLightClass,
private val file: KtFile
) : KtLightClass by psiClass {
override fun isValid() = file.isValid
}
override fun canProcessElement(element: PsiElement) =
element is KtFile && ProjectRootsUtil.isInProjectSource(element, includeScriptsOutsideSourceRoots = true)
override fun prepareRenaming(element: PsiElement?,
newName: String,
allRenames: MutableMap<PsiElement, String>,
scope: SearchScope) {
val jetFile = element as? KtFile ?: return
if (FileTypeManager.getInstance().getFileTypeByFileName(newName) != KotlinFileType.INSTANCE) {
return
}
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return
val fileInfo = JvmFileClassUtil.getFileClassInfoNoResolve(jetFile)
if (!fileInfo.withJvmName) {
val facadeFqName = fileInfo.facadeClassFqName
val project = jetFile.project
val facadeClass = JavaPsiFacade.getInstance(project)
.findClass(facadeFqName.asString(), GlobalSearchScope.moduleScope(module)) as? KtLightClass
if (facadeClass != null) {
allRenames[FileRenamingPsiClassWrapper(facadeClass, jetFile)] = PackagePartClassUtils.getFilePartShortName(newName)
}
}
}
override fun findReferences(element: PsiElement): MutableCollection<PsiReference> {
return super.findReferences(element).also {
KotlinStatisticsTrigger.trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
override fun findReferences(element: PsiElement, searchInCommentsAndStrings: Boolean): MutableCollection<PsiReference> {
return super.findReferences(element, searchInCommentsAndStrings).also {
KotlinStatisticsTrigger.trigger(KotlinIdeRefactoringTrigger::class.java, this::class.java.name)
}
}
}
@@ -1,248 +0,0 @@
/*
* Copyright 2010-2016 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.refactoring.rename
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Pass
import com.intellij.psi.*
import com.intellij.psi.search.SearchScope
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.refactoring.rename.RenameDialog
import com.intellij.refactoring.rename.RenameJavaMethodProcessor
import com.intellij.refactoring.rename.RenameProcessor
import com.intellij.refactoring.rename.RenameUtil
import com.intellij.refactoring.util.RefactoringUtil
import com.intellij.usageView.UsageInfo
import com.intellij.util.SmartList
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.refactoring.Pass
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethodsWithPopup
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.search.declarationsSearch.findDeepestSuperMethodsKotlinAware
import org.jetbrains.kotlin.idea.search.declarationsSearch.findDeepestSuperMethodsNoWrapping
import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingMethod
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.liftToExpected
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import java.lang.IllegalStateException
import java.util.*
class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
private val javaMethodProcessorInstance = RenameJavaMethodProcessor()
override fun canProcessElement(element: PsiElement): Boolean {
return element is KtNamedFunction || (element is KtLightMethod && element.kotlinOrigin is KtNamedFunction) || element is FunctionWithSupersWrapper
}
override fun isToSearchInComments(psiElement: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD
override fun setToSearchInComments(element: PsiElement, enabled: Boolean) {
JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD = enabled
}
override fun isToSearchForTextOccurrences(element: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD
override fun setToSearchForTextOccurrences(element: PsiElement, enabled: Boolean) {
JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD = enabled
}
private fun getJvmName(element: PsiElement): String? {
val descriptor = (element.unwrapped as? KtFunction)?.unsafeResolveToDescriptor() as? FunctionDescriptor ?: return null
return DescriptorUtils.getJvmName(descriptor)
}
override fun findReferences(element: PsiElement): Collection<PsiReference> {
val allReferences = super.findReferences(element)
return when {
getJvmName(element) == null -> allReferences
element is KtElement -> allReferences.filter { it is KtReference }
element is KtLightElement<*, *> -> allReferences.filterNot { it is KtReference }
else -> emptyList()
}
}
override fun findCollisions(
element: PsiElement,
newName: String?,
allRenames: Map<out PsiElement, String>,
result: MutableList<UsageInfo>
) {
if (newName == null) return
val declaration = element.unwrapped as? KtNamedFunction ?: return
val descriptor = declaration.unsafeResolveToDescriptor()
checkConflictsAndReplaceUsageInfos(element, allRenames, result)
result += SmartList<UsageInfo>().also { collisions ->
checkRedeclarations(descriptor, newName, collisions)
checkOriginalUsagesRetargeting(declaration, newName, result, collisions)
checkNewNameUsagesRetargeting(declaration, newName, collisions)
}
}
class FunctionWithSupersWrapper(
val originalDeclaration: KtNamedFunction,
val supers: List<PsiElement>
) : KtLightElement<KtNamedFunction, KtNamedFunction>, PsiNamedElement by originalDeclaration {
override val kotlinOrigin: KtNamedFunction?
get() = originalDeclaration
override val clsDelegate: KtNamedFunction
get() = originalDeclaration
}
private fun substituteForExpectOrActual(element: PsiElement?) = (element?.namedUnwrappedElement as? KtNamedDeclaration)?.liftToExpected()
override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
substituteForExpectOrActual(element)?.let { return it }
val wrappedMethod = wrapPsiMethod(element) ?: return element
val deepestSuperMethods = findDeepestSuperMethodsKotlinAware(wrappedMethod)
val substitutedJavaElement = when {
deepestSuperMethods.isEmpty() -> return element
wrappedMethod.isConstructor || deepestSuperMethods.size == 1 || element !is KtNamedFunction -> {
javaMethodProcessorInstance.substituteElementToRename(wrappedMethod, editor)
}
else -> {
val chosenElements = checkSuperMethods(element, null, "rename")
if (chosenElements.size > 1) FunctionWithSupersWrapper(element, chosenElements) else wrappedMethod
}
}
if (substitutedJavaElement is KtLightMethod && element is KtDeclaration) {
return substitutedJavaElement.kotlinOrigin as? KtNamedFunction
}
return substitutedJavaElement
}
override fun substituteElementToRename(element: PsiElement, editor: Editor, renameCallback: Pass<PsiElement>) {
fun preprocessAndPass(substitutedJavaElement: PsiElement) {
val elementToProcess = if (substitutedJavaElement is KtLightMethod && element is KtDeclaration) {
substitutedJavaElement.kotlinOrigin as? KtNamedFunction
}
else {
substitutedJavaElement
}
renameCallback.pass(elementToProcess)
}
substituteForExpectOrActual(element)?.let { return preprocessAndPass(it) }
val wrappedMethod = wrapPsiMethod(element)
val deepestSuperMethods = if (wrappedMethod != null) {
findDeepestSuperMethodsKotlinAware(wrappedMethod)
} else {
findDeepestSuperMethodsNoWrapping(element)
}
when {
deepestSuperMethods.isEmpty() -> preprocessAndPass(element)
wrappedMethod != null && (wrappedMethod.isConstructor || element !is KtNamedFunction) -> {
javaMethodProcessorInstance.substituteElementToRename(wrappedMethod, editor, Pass(::preprocessAndPass))
}
else -> {
val declaration = element.unwrapped as? KtNamedFunction ?: return
checkSuperMethodsWithPopup(declaration, deepestSuperMethods.toList(), "Rename", editor) {
preprocessAndPass(if (it.size > 1) FunctionWithSupersWrapper(declaration, it) else wrappedMethod ?: element)
}
}
}
}
override fun createRenameDialog(project: Project, element: PsiElement, nameSuggestionContext: PsiElement?, editor: Editor?): RenameDialog {
val elementForDialog = (element as? FunctionWithSupersWrapper)?.originalDeclaration ?: element
return object : RenameDialog(project, elementForDialog, nameSuggestionContext, editor) {
override fun createRenameProcessor(newName: String) = RenameProcessor(getProject(), element, newName, isSearchInComments, isSearchInNonJavaFiles)
}
}
override fun prepareRenaming(element: PsiElement, newName: String?, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
super.prepareRenaming(element, newName, allRenames, scope)
if (newName == null) return
if (element is KtLightMethod && getJvmName(element) == null) {
(element.kotlinOrigin as? KtNamedFunction)?.let { allRenames[it] = newName }
}
if (element is FunctionWithSupersWrapper) {
allRenames.remove(element)
}
for (declaration in ((element as? FunctionWithSupersWrapper)?.supers ?: listOf(element))) {
val psiMethod = wrapPsiMethod(declaration) ?: continue
allRenames[declaration] = newName
if (psiMethod.containingClass != null) {
psiMethod.forEachOverridingMethod { it ->
val overrider = (it as? PsiMirrorElement)?.prototype as? PsiMethod ?: it
if (overrider is SyntheticElement) return@forEachOverridingMethod true
val overriderName = overrider.name
val baseName = psiMethod.name
val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName)
if (newOverriderName != null) {
RenameProcessor.assertNonCompileElement(overrider)
allRenames.put(overrider, newOverriderName)
}
return@forEachOverridingMethod true
}
javaMethodProcessorInstance.prepareRenaming(psiMethod, newName, allRenames, scope)
}
}
}
override fun renameElement(element: PsiElement, newName: String?, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
val simpleUsages = ArrayList<UsageInfo>(usages.size)
val ambiguousImportUsages = SmartList<UsageInfo>()
for (usage in usages) {
if (usage is LostDefaultValuesInOverridingFunctionUsageInfo) {
usage.apply()
continue
}
if (usage.isAmbiguousImportUsage()) {
ambiguousImportUsages += usage
}
else {
simpleUsages += usage
}
}
element.ambiguousImportUsages = ambiguousImportUsages
RenameUtil.doRenameGenericNamedElement(element, newName, simpleUsages.toTypedArray(), listener)
usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() }
(element.unwrapped as? KtNamedDeclaration)?.let(::dropOverrideKeywordIfNecessary)
}
private fun wrapPsiMethod(element: PsiElement?): PsiMethod? = when (element) {
is PsiMethod -> element
is KtNamedFunction, is KtSecondaryConstructor -> runReadAction {
LightClassUtil.getLightClassMethod(element as KtFunction)
}
else -> throw IllegalStateException("Can't be for element $element there because of canProcessElement()")
}
}
@@ -1,62 +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.idea.refactoring.rename
import com.intellij.psi.PsiElement
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.utils.SmartList
class RenameKotlinParameterProcessor : RenameKotlinPsiProcessor() {
override fun canProcessElement(element: PsiElement) = element is KtParameter && element.ownerFunction is KtFunction
override fun isToSearchInComments(psiElement: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_VARIABLE
override fun setToSearchInComments(element: PsiElement, enabled: Boolean) {
JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_VARIABLE = enabled
}
override fun findCollisions(
element: PsiElement,
newName: String?,
allRenames: MutableMap<out PsiElement, String>,
result: MutableList<UsageInfo>
) {
if (newName == null) return
val declaration = element.namedUnwrappedElement as? KtNamedDeclaration ?: return
val descriptor = declaration.unsafeResolveToDescriptor() as VariableDescriptor
val collisions = SmartList<UsageInfo>()
checkRedeclarations(descriptor, newName, collisions)
checkOriginalUsagesRetargeting(declaration, newName, result, collisions)
checkNewNameUsagesRetargeting(declaration, newName, collisions)
result += collisions
}
override fun renameElement(element: PsiElement, newName: String?, usages: Array<out UsageInfo>, listener: RefactoringElementListener?) {
super.renameElement(element, newName, usages, listener)
usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() }
}
}
@@ -1,479 +0,0 @@
/*
* Copyright 2010-2016 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.refactoring.rename
import com.intellij.navigation.NavigationItem
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.Pass
import com.intellij.psi.*
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.DirectClassInheritorsSearch
import com.intellij.psi.search.searches.OverridingMethodsSearch
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.refactoring.rename.RenameProcessor
import com.intellij.refactoring.util.MoveRenameUsageInfo
import com.intellij.refactoring.util.RefactoringUtil
import com.intellij.usageView.UsageInfo
import com.intellij.usageView.UsageViewUtil
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations
import org.jetbrains.kotlin.idea.core.isEnumCompanionPropertyWithEntryConflict
import org.jetbrains.kotlin.idea.core.unquote
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethodsWithPopup
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.findPropertyByName
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.util.findCallableMemberBySignature
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.SmartList
class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
override fun canProcessElement(element: PsiElement): Boolean {
val namedUnwrappedElement = element.namedUnwrappedElement
return namedUnwrappedElement is KtProperty || (namedUnwrappedElement is KtParameter && namedUnwrappedElement.hasValOrVar())
}
override fun isToSearchInComments(psiElement: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_FIELD
override fun setToSearchInComments(element: PsiElement, enabled: Boolean) {
JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_FIELD = enabled
}
override fun isToSearchForTextOccurrences(element: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_FIELD
override fun setToSearchForTextOccurrences(element: PsiElement, enabled: Boolean) {
JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_FIELD = enabled
}
private fun getJvmNames(element: PsiElement): Pair<String?, String?> {
val descriptor = (element.unwrapped as? KtDeclaration)?.unsafeResolveToDescriptor() as? PropertyDescriptor ?: return null to null
val getterName = descriptor.getter?.let { DescriptorUtils.getJvmName(it) }
val setterName = descriptor.setter?.let { DescriptorUtils.getJvmName(it) }
return getterName to setterName
}
override fun findReferences(element: PsiElement): Collection<PsiReference> {
val allReferences = super.findReferences(element).filterNot { it is KtDestructuringDeclarationReference }
val (getterJvmName, setterJvmName) = getJvmNames(element)
return when {
getterJvmName == null && setterJvmName == null -> allReferences
element is KtElement -> allReferences.filter {
it is KtReference
|| (getterJvmName == null && (it.resolve() as? PsiNamedElement)?.name != setterJvmName)
|| (setterJvmName == null && (it.resolve() as? PsiNamedElement)?.name != getterJvmName)
}
element is KtLightDeclaration<*, *> -> {
val name = element.name
if (name == getterJvmName || name == setterJvmName) allReferences.filterNot { it is KtReference } else allReferences
}
else -> emptyList()
}
}
private fun checkAccidentalOverrides(
declaration: KtNamedDeclaration,
newName: String,
descriptor: VariableDescriptor,
result: MutableList<UsageInfo>
) {
fun reportAccidentalOverride(candidate: PsiNamedElement) {
val what = UsageViewUtil.getType(declaration).capitalize()
val withWhat = candidate.renderDescription()
val where = candidate.representativeContainer()?.renderDescription() ?: return
val message = "$what after rename will clash with existing $withWhat in $where"
result += BasicUnresolvableCollisionUsageInfo(candidate, candidate, message)
}
if (descriptor !is PropertyDescriptor) return
val initialClass = declaration.containingClassOrObject ?: return
val initialClassDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return
val prototype = object : PropertyDescriptor by descriptor {
override fun getName() = Name.guessByFirstCharacter(newName)
}
DFS.dfs(
listOf(initialClassDescriptor),
DFS.Neighbors<ClassDescriptor> { DescriptorUtils.getSuperclassDescriptors(it) },
object : DFS.AbstractNodeHandler<ClassDescriptor, Unit>() {
override fun beforeChildren(current: ClassDescriptor): Boolean {
if (current == initialClassDescriptor) return true
(current.findCallableMemberBySignature(prototype))?.let { candidateDescriptor ->
val candidate = candidateDescriptor.source.getPsi() as? PsiNamedElement ?: return false
reportAccidentalOverride(candidate)
return false
}
return true
}
override fun result() {
}
}
)
if (!declaration.hasModifier(KtTokens.PRIVATE_KEYWORD)) {
val initialPsiClass = initialClass.toLightClass() ?: return
val prototypes = declaration.toLightMethods().mapNotNull {
it as KtLightMethod
val methodName = accessorNameByPropertyName(newName, it) ?: return@mapNotNull null
object : KtLightMethod by it {
override fun getName() = methodName
}
}
DFS.dfs(
listOf(initialPsiClass),
DFS.Neighbors<PsiClass> { DirectClassInheritorsSearch.search(it) },
object : DFS.AbstractNodeHandler<PsiClass, Unit>() {
override fun beforeChildren(current: PsiClass): Boolean {
if (current == initialPsiClass) return true
if (current is KtLightClass) {
val property = current.kotlinOrigin?.findPropertyByName(newName) ?: return true
reportAccidentalOverride(property)
return false
}
for (psiMethod in prototypes) {
current.findMethodBySignature(psiMethod, false)?.let {
val candidate = it.unwrapped as? PsiNamedElement ?: return true
reportAccidentalOverride(candidate)
return false
}
}
return true
}
override fun result() {
}
}
)
}
}
override fun findCollisions(
element: PsiElement,
newName: String?,
allRenames: MutableMap<out PsiElement, String>,
result: MutableList<UsageInfo>
) {
if (newName == null) return
val declaration = element.namedUnwrappedElement as? KtNamedDeclaration ?: return
val descriptor = declaration.unsafeResolveToDescriptor() as VariableDescriptor
val collisions = SmartList<UsageInfo>()
checkRedeclarations(descriptor, newName, collisions)
checkAccidentalOverrides(declaration, newName, descriptor, collisions)
checkOriginalUsagesRetargeting(declaration, newName, result, collisions)
checkNewNameUsagesRetargeting(declaration, newName, collisions)
result += collisions
}
private fun chooseCallableToRename(callableDeclaration: KtCallableDeclaration): KtCallableDeclaration? {
val deepestSuperDeclaration = findDeepestOverriddenDeclaration(callableDeclaration)
if (deepestSuperDeclaration == null || deepestSuperDeclaration == callableDeclaration) {
return callableDeclaration
}
if (ApplicationManager.getApplication()!!.isUnitTestMode) return deepestSuperDeclaration
val containsText: String? =
deepestSuperDeclaration.fqName?.parent()?.asString() ?:
(deepestSuperDeclaration.parent as? KtClassOrObject)?.name
val result = Messages.showYesNoCancelDialog(
deepestSuperDeclaration.project,
if (containsText != null) "Do you want to rename base property from \n$containsText" else "Do you want to rename base property",
"Rename warning",
Messages.getQuestionIcon())
return when (result) {
Messages.YES -> deepestSuperDeclaration
Messages.NO -> callableDeclaration
else -> /* Cancel rename */ null
}
}
override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
val namedUnwrappedElement = element?.namedUnwrappedElement ?: return null
val callableDeclaration = namedUnwrappedElement as? KtCallableDeclaration
?: throw IllegalStateException("Can't be for element $element there because of canProcessElement()")
val declarationToRename = chooseCallableToRename(callableDeclaration) ?: return null
val (getterJvmName, setterJvmName) = getJvmNames(namedUnwrappedElement)
if (element is KtLightMethod) {
val name = element.name
if (element.name != getterJvmName && element.name != setterJvmName) return declarationToRename
return declarationToRename.toLightMethods().firstOrNull { it.name == name }
}
return declarationToRename
}
override fun substituteElementToRename(element: PsiElement, editor: Editor, renameCallback: Pass<PsiElement>) {
val namedUnwrappedElement = element.namedUnwrappedElement ?: return
val callableDeclaration = namedUnwrappedElement as? KtCallableDeclaration
?: throw IllegalStateException("Can't be for element $element there because of canProcessElement()")
fun preprocessAndPass(substitutedJavaElement: PsiElement) {
val (getterJvmName, setterJvmName) = getJvmNames(namedUnwrappedElement)
val elementToProcess = if (element is KtLightMethod) {
val name = element.name
if (element.name != getterJvmName && element.name != setterJvmName) {
substitutedJavaElement
}
else {
substitutedJavaElement.toLightMethods().firstOrNull { it.name == name }
}
}
else substitutedJavaElement
renameCallback.pass(elementToProcess)
}
val deepestSuperDeclaration = findDeepestOverriddenDeclaration(callableDeclaration)
if (deepestSuperDeclaration == null || deepestSuperDeclaration == callableDeclaration) {
return preprocessAndPass(callableDeclaration)
}
val superPsiMethods = listOfNotNull(deepestSuperDeclaration.getRepresentativeLightMethod())
checkSuperMethodsWithPopup(callableDeclaration, superPsiMethods, "Rename", editor) {
preprocessAndPass(if (it.size > 1) deepestSuperDeclaration else callableDeclaration)
}
}
class PropertyMethodWrapper(private val propertyMethod: PsiMethod) : PsiNamedElement by propertyMethod, NavigationItem by propertyMethod {
override fun getName() = propertyMethod.name
override fun setName(name: String) = this
override fun copy() = this
}
override fun prepareRenaming(element: PsiElement, newName: String?, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
super.prepareRenaming(element, newName, allRenames, scope)
val namedUnwrappedElement = element.namedUnwrappedElement
val propertyMethods = when(namedUnwrappedElement) {
is KtProperty -> runReadAction { LightClassUtil.getLightClassPropertyMethods(namedUnwrappedElement) }
is KtParameter -> runReadAction { LightClassUtil.getLightClassPropertyMethods(namedUnwrappedElement) }
else -> throw IllegalStateException("Can't be for element $element there because of canProcessElement()")
}
val newPropertyName = if (newName != null && element is KtLightMethod) propertyNameByAccessor(newName, element) else newName
val (getterJvmName, setterJvmName) = getJvmNames(namedUnwrappedElement)
val getter = propertyMethods.getter as? KtLightMethod
val setter = propertyMethods.setter as? KtLightMethod
if (newPropertyName != null
&& getter != null && setter != null
&& (element == getter || element == setter)
&& propertyNameByAccessor(getter.name, getter) == propertyNameByAccessor(setter.name, setter)) {
val accessorToRename = if (element == getter) setter else getter
val newAccessorName = if (element == getter) JvmAbi.setterName(newPropertyName) else JvmAbi.getterName(newPropertyName)
if (ApplicationManager.getApplication().isUnitTestMode
|| Messages.showYesNoDialog("Do you want to rename ${accessorToRename.name}() as well?",
"Rename",
Messages.getQuestionIcon()) == Messages.YES) {
allRenames[accessorToRename] = newAccessorName
}
}
for (propertyMethod in propertyMethods) {
if (element is KtDeclaration && newPropertyName != null) {
val wrapper = PropertyMethodWrapper(propertyMethod)
when {
JvmAbi.isGetterName(propertyMethod.name) && getterJvmName == null ->
allRenames[wrapper] = JvmAbi.getterName(newPropertyName)
JvmAbi.isSetterName(propertyMethod.name) && setterJvmName == null ->
allRenames[wrapper] = JvmAbi.setterName(newPropertyName)
}
}
addRenameElements(propertyMethod, (element as PsiNamedElement).name, newPropertyName, allRenames, scope)
}
}
private enum class UsageKind {
SIMPLE_PROPERTY_USAGE,
GETTER_USAGE,
SETTER_USAGE
}
override tailrec fun renameElement(element: PsiElement, newName: String, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
val newNameUnquoted = newName.unquote()
if (element is KtLightMethod) {
if (element.modifierList.findAnnotation(DescriptorUtils.JVM_NAME.asString()) != null) {
return super.renameElement(element, newName, usages, listener)
}
val origin = element.kotlinOrigin
val newPropertyName = propertyNameByAccessor(newNameUnquoted, element)
// Kotlin references to Kotlin property should not use accessor name
if (newPropertyName != null && (origin is KtProperty || origin is KtParameter)) {
val (ktUsages, otherUsages) = usages.partition { it.reference is KtSimpleNameReference }
super.renameElement(element, newName, otherUsages.toTypedArray(), listener)
renameElement(origin, newPropertyName.quoteIfNeeded(), ktUsages.toTypedArray(), listener)
return
}
}
if (element !is KtProperty && element !is KtParameter) {
super.renameElement(element, newName, usages, listener)
return
}
val name = (element as KtNamedDeclaration).name!!
val oldGetterName = JvmAbi.getterName(name)
val oldSetterName = JvmAbi.setterName(name)
if (isEnumCompanionPropertyWithEntryConflict(element, newNameUnquoted)) {
for ((i, usage) in usages.withIndex()) {
if (usage !is MoveRenameUsageInfo) continue
val ref = usage.reference ?: continue
// TODO: Enum value can't be accessed from Java in case of conflict with companion member
if (ref is KtReference) {
val newRef = (ref.bindToElement(element) as? KtSimpleNameExpression)?.mainReference ?: continue
usages[i] = MoveRenameUsageInfo(newRef, usage.referencedElement)
}
}
}
val adjustedUsages = if (element is KtParameter) usages.filterNot {
val refTarget = it.reference?.resolve()
refTarget is KtLightMethod && DataClassDescriptorResolver.isComponentLike(Name.guessByFirstCharacter(refTarget.name))
} else usages.toList()
val refKindUsages = adjustedUsages.groupBy { usage: UsageInfo ->
val refElement = usage.reference?.resolve()
if (refElement is PsiMethod) {
when (refElement.name) {
oldGetterName -> UsageKind.GETTER_USAGE
oldSetterName -> UsageKind.SETTER_USAGE
else -> UsageKind.SIMPLE_PROPERTY_USAGE
}
}
else {
UsageKind.SIMPLE_PROPERTY_USAGE
}
}
super.renameElement(element, JvmAbi.setterName(newNameUnquoted).quoteIfNeeded(),
refKindUsages[UsageKind.SETTER_USAGE]?.toTypedArray() ?: arrayOf<UsageInfo>(),
null)
super.renameElement(element, JvmAbi.getterName(newNameUnquoted).quoteIfNeeded(),
refKindUsages[UsageKind.GETTER_USAGE]?.toTypedArray() ?: arrayOf<UsageInfo>(),
null)
super.renameElement(element, newName,
refKindUsages[UsageKind.SIMPLE_PROPERTY_USAGE]?.toTypedArray() ?: arrayOf<UsageInfo>(),
null)
usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() }
dropOverrideKeywordIfNecessary(element)
listener?.elementRenamed(element)
}
private fun addRenameElements(psiMethod: PsiMethod?,
oldName: String?,
newName: String?,
allRenames: MutableMap<PsiElement, String>,
scope: SearchScope) {
if (psiMethod == null) return
OverridingMethodsSearch.search(psiMethod, scope, true).forEach { overrider ->
val overriderElement = overrider.namedUnwrappedElement
if (overriderElement != null && overriderElement !is SyntheticElement) {
RenameProcessor.assertNonCompileElement(overriderElement)
val overriderName = overriderElement.name
if (overriderElement is PsiMethod) {
if (newName != null && Name.isValidIdentifier(newName)) {
val isGetter = overriderElement.parameterList.parametersCount == 0
allRenames[overriderElement] = if (isGetter) JvmAbi.getterName(newName) else JvmAbi.setterName(newName)
}
}
else {
val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, oldName, newName)
if (newOverriderName != null) {
allRenames[overriderElement] = newOverriderName
}
}
}
}
}
private fun findDeepestOverriddenDeclaration(declaration: KtCallableDeclaration): KtCallableDeclaration? {
if (declaration.modifierList?.hasModifier(KtTokens.OVERRIDE_KEYWORD) == true) {
val bindingContext = declaration.analyze()
var descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]
if (descriptor is ValueParameterDescriptor) {
descriptor = bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor]
?: return declaration
}
if (descriptor != null) {
assert(descriptor is PropertyDescriptor) { "Property descriptor is expected" }
val supers = (descriptor as PropertyDescriptor).getDeepestSuperDeclarations()
// Take one of supers for now - API doesn't support substitute to several elements (IDEA-48796)
val deepest = supers.first()
if (deepest != descriptor) {
val superPsiElement = DescriptorToSourceUtils.descriptorToDeclaration(deepest)
return superPsiElement as? KtCallableDeclaration
}
}
}
return null
}
}
@@ -1,135 +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.idea.refactoring.rename
import com.intellij.openapi.util.Key
import com.intellij.psi.*
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.PsiUtilCore
import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.refactoring.rename.RenamePsiElementProcessor
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.or
import org.jetbrains.kotlin.idea.search.projectScope
import org.jetbrains.kotlin.idea.util.actualsForExpected
import org.jetbrains.kotlin.idea.util.liftToExpected
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.statistics.KotlinIdeRefactoringTrigger
import org.jetbrains.kotlin.statistics.KotlinStatisticsTrigger
abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
override fun canProcessElement(element: PsiElement): Boolean = element is KtNamedDeclaration
override fun findReferences(element: PsiElement): Collection<PsiReference> {
KotlinStatisticsTrigger.trigger(KotlinIdeRefactoringTrigger::class.java, this.javaClass.simpleName)
val searchParameters = KotlinReferencesSearchParameters(
element,
element.project.projectScope() or element.useScope,
kotlinOptions = KotlinReferencesSearchOptions(searchForComponentConventions = false)
)
val references = ReferencesSearch.search(searchParameters).toMutableList()
if (element is KtNamedFunction
|| (element is KtProperty && !element.isLocal)
|| (element is KtParameter && element.hasValOrVar())) {
element.toLightMethods().flatMapTo(references) { MethodReferencesSearch.search(it) }
}
return references
}
override fun getElementToSearchInStringsAndComments(element: PsiElement?): PsiElement? {
val unwrapped = element?.unwrapped ?: return null
if ((unwrapped is KtDeclaration) && KtPsiUtil.isLocal(unwrapped as KtDeclaration)) return null
return element
}
override fun getQualifiedNameAfterRename(element: PsiElement, newName: String?, nonJava: Boolean): String? {
if (!nonJava) return newName
val qualifiedName = when (element) {
is KtNamedDeclaration -> element.fqName?.asString() ?: element.name
is PsiClass -> element.qualifiedName ?: element.name
else -> return null
}
return PsiUtilCore.getQualifiedNameAfterRename(qualifiedName, newName)
}
override fun prepareRenaming(element: PsiElement, newName: String?, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
if (newName == null) return
val safeNewName = newName.quoteIfNeeded()
if (!newName.isIdentifier()) {
allRenames[element] = safeNewName
}
val declaration = element.namedUnwrappedElement as? KtNamedDeclaration
if (declaration != null) {
declaration.liftToExpected()?.let { expectDeclaration ->
allRenames[expectDeclaration] = safeNewName
expectDeclaration.actualsForExpected().forEach { allRenames[it] = safeNewName }
}
}
}
protected var PsiElement.ambiguousImportUsages: List<UsageInfo>? by UserDataProperty(Key.create("AMBIGUOUS_IMPORT_USAGES"))
protected fun UsageInfo.isAmbiguousImportUsage(): Boolean {
val ref = reference as? PsiPolyVariantReference ?: return false
val refElement = ref.element
return refElement.parents.any { (it is KtImportDirective && !it.isAllUnder) || (it is PsiImportStaticStatement && !it.isOnDemand) }
&& ref.multiResolve(false).mapNotNullTo(HashSet()) { it.element?.unwrapped }.size > 1
}
override fun getPostRenameCallback(element: PsiElement, newName: String?, elementListener: RefactoringElementListener?): Runnable? {
if (newName == null) return null
return Runnable {
element.ambiguousImportUsages?.forEach {
val ref = it.reference as? PsiPolyVariantReference ?: return@forEach
if (ref.multiResolve(false).isEmpty()) {
ref.handleElementRename(newName)
}
else {
ref.element?.getStrictParentOfType<KtImportDirective>()?.let { importDirective ->
val fqName = importDirective.importedFqName!!
val newFqName = fqName.parent().child(Name.identifier(newName))
val importList = importDirective.parent as KtImportList
if (importList.imports.none { it.importedFqName == newFqName }) {
val newImportDirective = KtPsiFactory(element).createImportDirective(ImportPath(newFqName, false))
importDirective.parent.addAfter(newImportDirective, importDirective)
}
}
}
}
element.ambiguousImportUsages = null
}
}
}
@@ -1,38 +0,0 @@
/*
* Copyright 2010-2016 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.refactoring.rename
import com.intellij.psi.PsiElement
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.psi.KtTypeParameter
class RenameKotlinTypeParameterProcessor : RenameKotlinPsiProcessor() {
override fun canProcessElement(element: PsiElement) = element is KtTypeParameter
override fun findCollisions(
element: PsiElement,
newName: String?,
allRenames: MutableMap<out PsiElement, String>,
result: MutableList<UsageInfo>
) {
if (newName == null) return
val declaration = element as? KtTypeParameter ?: return
val descriptor = declaration.unsafeResolveToDescriptor()
checkRedeclarations(descriptor, newName, result)
}
}
@@ -1,496 +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.idea.refactoring.safeDelete
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.Condition
import com.intellij.openapi.util.Conditions
import com.intellij.openapi.util.Key
import com.intellij.psi.*
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor
import com.intellij.refactoring.safeDelete.NonCodeUsageSearchInfo
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteOverrideAnnotation
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteOverridingMethodUsageInfo
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceJavaDeleteUsageInfo
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDeleteUsageInfo
import com.intellij.usageView.UsageInfo
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.core.deleteElementAndCleanParent
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
import org.jetbrains.kotlin.idea.refactoring.formatClass
import org.jetbrains.kotlin.idea.refactoring.formatFunction
import org.jetbrains.kotlin.idea.refactoring.withExpectedActuals
import org.jetbrains.kotlin.idea.refactoring.isTrueJavaMethod
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.projectScope
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
import org.jetbrains.kotlin.idea.util.liftToExpected
import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.utils.SmartSet
import org.jetbrains.kotlin.utils.ifEmpty
import java.util.*
class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
companion object {
@set:TestOnly
internal var Project.ALLOW_LIFTING_ACTUAL_PARAMETER_TO_EXPECTED
by NotNullableUserDataProperty(Key.create("ALLOW_LIFTING_ACTUAL_PARAMETER_TO_EXPECTED"), true)
private var KtDeclaration.dropActualModifier: Boolean? by UserDataProperty(Key.create("DROP_ACTUAL_MODIFIER"))
}
override fun handlesElement(element: PsiElement): Boolean = element.canDeleteElement()
override fun findUsages(
element: PsiElement, allElementsToDelete: Array<out PsiElement>, usages: MutableList<UsageInfo>
): NonCodeUsageSearchInfo {
val deleteSet = SmartSet.create<PsiElement>()
deleteSet.addAll(allElementsToDelete)
fun getIgnoranceCondition() = Condition<PsiElement> {
if (it is KtFile) return@Condition false
deleteSet.any { element -> JavaSafeDeleteProcessor.isInside(it, element.unwrapped) }
}
fun getSearchInfo(element: PsiElement) = NonCodeUsageSearchInfo(getIgnoranceCondition(), element)
fun searchKotlinDeclarationReferences(declaration: KtDeclaration): Sequence<PsiReference> {
val elementsToSearch = if (declaration is KtParameter) declaration.withExpectedActuals() else listOf(declaration)
return elementsToSearch.asSequence().flatMap {
val searchParameters = KotlinReferencesSearchParameters(
it,
if (it.hasActualModifier()) it.project.projectScope() else it.useScope,
kotlinOptions = KotlinReferencesSearchOptions(acceptCallableOverrides = true)
)
ReferencesSearch.search(searchParameters)
.asSequence()
.filterNot { reference -> getIgnoranceCondition().value(reference.element) }
}
}
fun findKotlinParameterUsages(parameter: KtParameter) {
val ownerFunction = parameter.ownerFunction as? KtFunction ?: return
val index = parameter.parameterIndex()
for (reference in searchKotlinDeclarationReferences(ownerFunction)) {
val callee = reference.element as? KtExpression ?: continue
val resolvedCall = callee.resolveToCall(BodyResolveMode.FULL) ?: continue
val parameterDescriptor = resolvedCall.candidateDescriptor.valueParameters.getOrNull(index) ?: continue
val resolvedArgument = resolvedCall.valueArguments[parameterDescriptor] ?: continue
val arguments = resolvedArgument.arguments.filterIsInstance<KtValueArgument>()
if (arguments.isEmpty()) continue
usages.add(SafeDeleteValueArgumentListUsageInfo(parameter, *arguments.toTypedArray()))
}
}
fun findKotlinDeclarationUsages(declaration: KtDeclaration): NonCodeUsageSearchInfo {
searchKotlinDeclarationReferences(declaration).mapNotNullTo(usages) { reference ->
val refElement = reference.element ?: return@mapNotNullTo null
refElement.getNonStrictParentOfType<KtImportDirective>()?.let { importDirective ->
SafeDeleteImportDirectiveUsageInfo(importDirective, element)
} ?: SafeDeleteReferenceSimpleDeleteUsageInfo(refElement, declaration, false)
}
if (declaration is KtParameter) {
findKotlinParameterUsages(declaration)
}
return getSearchInfo(declaration)
}
fun asLightElements(ktElements: Array<out PsiElement>) =
ktElements.flatMap { (it as? KtElement)?.toLightElements() ?: listOf(it) }.toTypedArray()
fun findUsagesByJavaProcessor(element: PsiElement, forceReferencedElementUnwrapping: Boolean): NonCodeUsageSearchInfo? {
val javaUsages = ArrayList<UsageInfo>()
val elementToPassToJava = when (element) {
is KtLightFieldImpl<*> -> object : KtLightField by element {
// Suppress walking through initializer compiled PSI (it doesn't contain any reference expressions anyway)
override fun getInitializer() = null
}
else -> element
}
val searchInfo = super.findUsages(elementToPassToJava, asLightElements(allElementsToDelete), javaUsages)
javaUsages.filterIsInstance<SafeDeleteOverridingMethodUsageInfo>().mapNotNullTo(deleteSet) { it.element }
val ignoranceCondition = getIgnoranceCondition()
javaUsages.mapNotNullTo(usages) { usageInfo ->
when (usageInfo) {
is SafeDeleteOverridingMethodUsageInfo ->
usageInfo.smartPointer.element?.let { usageElement ->
KotlinSafeDeleteOverridingUsageInfo(usageElement, usageInfo.referencedElement)
}
is SafeDeleteOverrideAnnotation ->
usageInfo.smartPointer.element?.let { usageElement ->
when {
usageElement.isTrueJavaMethod() -> usageInfo
usageElement.toLightMethods().all { method -> method.findSuperMethods().isEmpty() } -> {
KotlinSafeDeleteOverrideAnnotation(usageElement, usageInfo.referencedElement) as UsageInfo
}
else -> null
}
}
is SafeDeleteReferenceJavaDeleteUsageInfo ->
usageInfo.element?.let { usageElement ->
when {
usageElement.getNonStrictParentOfType<KtValueArgumentName>() != null -> null
ignoranceCondition.value(usageElement) -> null
else -> {
usageElement.getNonStrictParentOfType<KtImportDirective>()?.let { importDirective ->
SafeDeleteImportDirectiveUsageInfo(importDirective, element)
} ?: usageElement.getParentOfTypeAndBranch<KtSuperTypeEntry> { typeReference }?.let {
if (element is PsiClass && element.isInterface) SafeDeleteSuperTypeUsageInfo(it, element) else usageInfo
} ?: if (forceReferencedElementUnwrapping) {
SafeDeleteReferenceJavaDeleteUsageInfo(usageElement, element.unwrapped, usageInfo.isSafeDelete)
} else usageInfo
}
}
}
else -> usageInfo
}
}
return searchInfo
}
fun findUsagesByJavaProcessor(elements: Sequence<PsiElement>, insideDeleted: Condition<PsiElement>): Condition<PsiElement> =
elements
.mapNotNull { element -> findUsagesByJavaProcessor(element, true)?.insideDeletedCondition }
.fold(insideDeleted) { condition1, condition2 -> Conditions.or(condition1, condition2) }
fun findUsagesByJavaProcessor(ktDeclaration: KtDeclaration): NonCodeUsageSearchInfo {
val lightElements = ktDeclaration.toLightElements()
if (lightElements.isEmpty()) {
return findKotlinDeclarationUsages(ktDeclaration)
}
return NonCodeUsageSearchInfo(
findUsagesByJavaProcessor(
lightElements.asSequence(),
getIgnoranceCondition()
),
ktDeclaration
)
}
fun findTypeParameterUsages(parameter: KtTypeParameter) {
val owner = parameter.getNonStrictParentOfType<KtTypeParameterListOwner>() ?: return
val parameterList = owner.typeParameters
val parameterIndex = parameterList.indexOf(parameter)
for (reference in ReferencesSearch.search(owner)) {
if (reference !is KtReference) continue
val referencedElement = reference.element
val argList = referencedElement.getNonStrictParentOfType<KtUserType>()?.typeArgumentList
?: referencedElement.getNonStrictParentOfType<KtCallExpression>()?.typeArgumentList
if (argList != null) {
val projections = argList.arguments
if (parameterIndex < projections.size) {
usages.add(SafeDeleteTypeArgumentListUsageInfo(projections[parameterIndex], parameter))
}
}
}
}
fun findDelegationCallUsages(element: PsiElement) {
val constructors = when (element) {
is PsiClass -> element.constructors
is PsiMethod -> arrayOf(element)
else -> return
}
for (constructor in constructors) {
constructor.processDelegationCallConstructorUsages(constructor.useScope) {
if (!getIgnoranceCondition().value(it)) {
usages.add(SafeDeleteReferenceSimpleDeleteUsageInfo(it, element, false))
}
true
}
}
}
return when (element) {
is KtClassOrObject -> {
element.toLightClass()?.let { klass ->
findDelegationCallUsages(klass)
findUsagesByJavaProcessor(klass, false)
} ?: findKotlinDeclarationUsages(element)
}
is KtSecondaryConstructor -> {
if (element.hasActualModifier()) {
findKotlinDeclarationUsages(element)
} else {
element.getRepresentativeLightMethod()?.let { method ->
findDelegationCallUsages(method)
findUsagesByJavaProcessor(method, false)
} ?: findKotlinDeclarationUsages(element)
}
}
is KtNamedFunction -> {
if (element.isLocal || element.hasActualModifier()) {
findKotlinDeclarationUsages(element)
}
else {
val lightMethods = element.toLightMethods()
if (lightMethods.isNotEmpty()) {
lightMethods.map { method -> findUsagesByJavaProcessor(method, false) }.firstOrNull()
}
else {
findKotlinDeclarationUsages(element)
}
}
}
is PsiMethod -> {
findUsagesByJavaProcessor(element, false)
}
is PsiClass -> {
findUsagesByJavaProcessor(element, false)
}
is KtProperty -> {
if (element.isLocal || element.hasActualModifier()) {
findKotlinDeclarationUsages(element)
}
else {
findUsagesByJavaProcessor(element)
}
}
is KtTypeParameter -> {
findTypeParameterUsages(element)
findUsagesByJavaProcessor(element)
}
is KtParameter ->
findUsagesByJavaProcessor(element)
is KtTypeAlias -> {
findKotlinDeclarationUsages(element)
}
else -> null
} ?: getSearchInfo(element)
}
override fun findConflicts(element: PsiElement, allElementsToDelete: Array<out PsiElement>): MutableCollection<String>? {
if (element is KtNamedFunction || element is KtProperty) {
val jetClass = element.getNonStrictParentOfType<KtClass>()
if (jetClass == null || jetClass.getBody() != element.parent) return null
val modifierList = jetClass.modifierList
if (modifierList != null && modifierList.hasModifier(KtTokens.ABSTRACT_KEYWORD)) return null
val bindingContext = (element as KtElement).analyze()
val declarationDescriptor =
bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? CallableMemberDescriptor ?: return null
return declarationDescriptor.overriddenDescriptors
.asSequence()
.filter { overridenDescriptor -> overridenDescriptor.modality == Modality.ABSTRACT }
.mapTo(ArrayList()) { overridenDescriptor ->
KotlinBundle.message(
"x.implements.y",
formatFunction(declarationDescriptor, true),
formatClass(declarationDescriptor.containingDeclaration, true),
formatFunction(overridenDescriptor, true),
formatClass(overridenDescriptor.containingDeclaration, true)
)
}
}
return super.findConflicts(element, allElementsToDelete)
}
/*
* Mostly copied from JavaSafeDeleteProcessor.preprocessUsages
* Revision: d4fc033
* (replaced original dialog)
*/
override fun preprocessUsages(project: Project, usages: Array<out UsageInfo>): Array<UsageInfo>? {
val result = ArrayList<UsageInfo>()
val overridingMethodUsages = ArrayList<UsageInfo>()
for (usage in usages) {
if (usage is KotlinSafeDeleteOverridingUsageInfo) {
overridingMethodUsages.add(usage)
} else {
result.add(usage)
}
}
if (!overridingMethodUsages.isEmpty()) {
if (ApplicationManager.getApplication()!!.isUnitTestMode) {
result.addAll(overridingMethodUsages)
} else {
val dialog = KotlinOverridingDialog(project, overridingMethodUsages)
dialog.show()
if (!dialog.isOK) return null
result.addAll(dialog.selected)
}
}
return result.toTypedArray()
}
private fun KtDeclaration.removeOrClean() {
when (this) {
is KtParameter -> {
(parent as? KtParameterList)?.removeParameter(this)
}
is KtCallableDeclaration, is KtClassOrObject, is KtTypeAlias -> {
delete()
}
else -> {
removeModifier(KtTokens.IMPL_KEYWORD)
removeModifier(KtTokens.ACTUAL_KEYWORD)
}
}
}
override fun prepareForDeletion(element: PsiElement) {
if (element is KtDeclaration) {
element.runOnExpectAndAllActuals(checkExpect = false) { it.removeOrClean() }
}
when (element) {
is PsiMethod -> element.cleanUpOverrides()
is KtNamedFunction ->
if (!element.isLocal) {
element.getRepresentativeLightMethod()?.cleanUpOverrides()
}
is KtProperty ->
if (!element.isLocal) {
element.toLightMethods().forEach(PsiMethod::cleanUpOverrides)
}
is KtTypeParameter ->
element.deleteElementAndCleanParent()
is KtParameter -> {
element.ownerFunction?.let {
if (it.dropActualModifier == true) {
it.removeModifier(KtTokens.IMPL_KEYWORD)
it.removeModifier(KtTokens.ACTUAL_KEYWORD)
it.dropActualModifier = null
}
}
(element.parent as KtParameterList).removeParameter(element)
}
}
}
private fun shouldAllowPropagationToExpected(parameter: KtParameter): Boolean {
if (ApplicationManager.getApplication().isUnitTestMode) return parameter.project.ALLOW_LIFTING_ACTUAL_PARAMETER_TO_EXPECTED
return Messages.showYesNoDialog(
"Do you want to delete this parameter in expected declaration and all related actual ones?",
RefactoringBundle.message("safe.delete.title"),
Messages.getQuestionIcon()
) == Messages.YES
}
private fun shouldAllowPropagationToExpected(): Boolean {
if (ApplicationManager.getApplication().isUnitTestMode) return true
return Messages.showYesNoDialog(
"Do you want to delete expected declaration together with all related actual ones?",
RefactoringBundle.message("safe.delete.title"),
Messages.getQuestionIcon()
) == Messages.YES
}
override fun getElementsToSearch(
element: PsiElement, module: Module?, allElementsToDelete: Collection<PsiElement>
): Collection<PsiElement>? {
when (element) {
is KtParameter -> {
val expectParameter = element.liftToExpected()
if (expectParameter != null && expectParameter != element) {
if (shouldAllowPropagationToExpected(element)) {
return listOf(expectParameter)
} else {
element.ownerFunction?.dropActualModifier = true
return listOf(element)
}
}
return element.toPsiParameters().flatMap { psiParameter ->
checkParametersInMethodHierarchy(psiParameter) ?: emptyList()
}.ifEmpty { listOf(element) }
}
is KtDeclaration -> {
if (element.hasActualModifier() || element.isExpectDeclaration()) {
if (!shouldAllowPropagationToExpected()) {
return null
}
}
}
is PsiParameter ->
return checkParametersInMethodHierarchy(element)
}
if (ApplicationManager.getApplication()!!.isUnitTestMode) return Collections.singletonList(element)
return when (element) {
is KtNamedFunction, is KtProperty -> checkSuperMethods(element as KtDeclaration, allElementsToDelete, "delete (with usage search)")
else -> super.getElementsToSearch(element, module, allElementsToDelete)
}
}
}
-23
View File
@@ -1,23 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintShortAlarmInspection
import android.app.AlarmManager
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class TestAlarm {
fun test(alarmManager: AlarmManager) {
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 5000, 60000, null); // OK
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 6000, 70000, null); // OK
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, <warning descr="Value will be forced up to 5000 as of Android 5.1; don't rely on this to be exact">50</warning>, <warning descr="Value will be forced up to 60000 as of Android 5.1; don't rely on this to be exact">10</warning>, null); // ERROR
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 5000, // ERROR
<warning descr="Value will be forced up to 60000 as of Android 5.1; don't rely on this to be exact">OtherClass.MY_INTERVAL</warning>, null); // ERROR
val interval = 10;
val interval2 = 2L * interval;
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 5000, <warning descr="Value will be forced up to 60000 as of Android 5.1; don't rely on this to be exact">interval2</warning>, null); // ERROR
}
private object OtherClass {
val MY_INTERVAL = 1000L;
}
}
-486
View File
@@ -1,486 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
// INSPECTION_CLASS2: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInlinedApiInspection
// INSPECTION_CLASS3: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverrideInspection
import android.animation.RectEvaluator
import android.annotation.SuppressLint
import android.annotation.TargetApi
import org.w3c.dom.DOMError
import org.w3c.dom.DOMErrorHandler
import org.w3c.dom.DOMLocator
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import android.app.Activity
import android.app.ApplicationErrorReport
import android.graphics.drawable.VectorDrawable
import android.graphics.Path
import android.graphics.PorterDuff
import android.graphics.Rect
import android.os.Build
import android.widget.*
import dalvik.bytecode.OpcodeInfo
import android.os.Build.VERSION
import <warning descr="Field requires API level 4 (current min is 1): `android.os.Build.VERSION#SDK_INT`">android.os.Build.VERSION.SDK_INT</warning>
import android.os.Build.VERSION_CODES
import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH
import android.os.Build.VERSION_CODES.JELLY_BEAN
import android.os.Bundle
import android.os.Parcelable
import android.system.ErrnoException
import android.widget.TextView
@Suppress("SENSELESS_COMPARISON", "UNUSED_EXPRESSION", "UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION", "USELESS_CAST")
class ApiCallTest: Activity() {
fun method(chronometer: Chronometer, locator: DOMLocator) {
chronometer.<error descr="Call requires API level 16 (current min is 1): android.view.View#setBackground">setBackground</error>(null)
// Ok
Bundle().getInt("")
View.<warning descr="Field requires API level 16 (current min is 1): `android.view.View#SYSTEM_UI_FLAG_FULLSCREEN`">SYSTEM_UI_FLAG_FULLSCREEN</warning>
// Virtual call
<error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() // API 11
<error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">actionBar</error> // API 11
// Class references (no call or field access)
val error: DOMError? = null // API 8
val clz = <error descr="Class requires API level 8 (current min is 1): org.w3c.dom.DOMErrorHandler">DOMErrorHandler::class</error> // API 8
// Method call
chronometer.<error descr="Call requires API level 3 (current min is 1): android.widget.Chronometer#getOnChronometerTickListener">onChronometerTickListener</error> // API 3
// Inherited method call (from TextView
chronometer.<error descr="Call requires API level 11 (current min is 1): android.widget.TextView#setTextIsSelectable">setTextIsSelectable</error>(true) // API 11
<error descr="Class requires API level 14 (current min is 1): android.widget.GridLayout">GridLayout::class</error>
// Field access
val field = OpcodeInfo.<warning descr="Field requires API level 11 (current min is 1): `dalvik.bytecode.OpcodeInfo#MAXIMUM_VALUE`">MAXIMUM_VALUE</warning> // API 11
val fillParent = LayoutParams.FILL_PARENT // API 1
// This is a final int, which means it gets inlined
val matchParent = LayoutParams.MATCH_PARENT // API 8
// Field access: non final
val batteryInfo = report!!.<error descr="Field requires API level 14 (current min is 1): `android.app.ApplicationErrorReport#batteryInfo`">batteryInfo</error>
// Enum access
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
val mode = PorterDuff.Mode.<error descr="Field requires API level 11 (current min is 1): `android.graphics.PorterDuff.Mode#OVERLAY`">OVERLAY</error> // API 11
}
}
fun test(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
RectEvaluator(rect); // OK
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (rect != null) {
RectEvaluator(rect); // OK
}
}
}
fun test2(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
RectEvaluator(rect); // OK
}
}
fun test3(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
<error descr="Call requires API level 18 (current min is 1): android.animation.RectEvaluator#RectEvaluator">RectEvaluator</error>(); // ERROR
}
}
fun test4(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
System.out.println("Something");
RectEvaluator(rect); // OK
} else {
<error descr="Call requires API level 21 (current min is 1): android.animation.RectEvaluator#RectEvaluator">RectEvaluator</error>(rect); // ERROR
}
}
fun test5(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
<error descr="Call requires API level 21 (current min is 1): android.animation.RectEvaluator#RectEvaluator">RectEvaluator</error>(rect); // ERROR
} else {
<error descr="Call requires API level 21 (current min is 1): android.animation.RectEvaluator#RectEvaluator">RectEvaluator</error>(rect); // ERROR
}
}
fun test(priority: Boolean, layout: ViewGroup) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (SDK_INT >= ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
} else {
GridLayout(null).getOrientation(); // Not flagged
}
if (Build.VERSION.SDK_INT >= 14) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
// Nested conditionals
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (priority) {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
// Nested conditionals 2
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (priority) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null).getOrientation(); // Not flagged
}
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
}
fun test2(priority: Boolean) {
if (android.os.Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (android.os.Build.VERSION.SDK_INT >= 16) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (android.os.Build.VERSION.SDK_INT >= 13) {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (SDK_INT >= JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
} else {
GridLayout(null).getOrientation(); // Not flagged
}
if (Build.VERSION.SDK_INT >= 16) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
}
fun test(textView: TextView) {
if (textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
//ERROR
}
if (textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
//ERROR
}
if (SDK_INT >= JELLY_BEAN && textView.isSuggestionsEnabled()) {
//NO ERROR
}
if (SDK_INT >= JELLY_BEAN && textView.isSuggestionsEnabled) {
//NO ERROR
}
if (SDK_INT >= JELLY_BEAN && (textView.text != "" || textView.isSuggestionsEnabled)) {
//NO ERROR
}
if (SDK_INT < JELLY_BEAN && (textView.text != "" || textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>)) {
//ERROR
}
if (SDK_INT < JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
//ERROR
}
if (SDK_INT < JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
//ERROR
}
if (SDK_INT < JELLY_BEAN || textView.isSuggestionsEnabled) {
//NO ERROR
}
if (SDK_INT > JELLY_BEAN || textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
//ERROR
}
// getActionBar() API 11
if (SDK_INT <= 10 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT < 10 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
//ERROR
}
if (SDK_INT < 11 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT != 11 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT != 12 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
//ERROR
}
if (SDK_INT <= 11 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT < 12 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT <= 12 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT < 9 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
//ERROR
}
if (SDK_INT <= 9 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
//ERROR
}
}
fun testReturn() {
if (SDK_INT < 11) {
return
}
// No Error
val actionBar = getActionBar()
}
fun testThrow() {
if (SDK_INT < 11) {
throw IllegalStateException()
}
// No Error
val actionBar = getActionBar()
}
fun testError() {
if (SDK_INT < 11) {
error("Api")
}
// No Error
val actionBar = getActionBar()
}
fun testWithoutAnnotation(textView: TextView) {
if (textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
}
if (textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
}
}
@TargetApi(JELLY_BEAN)
fun testWithTargetApiAnnotation(textView: TextView) {
if (textView.isSuggestionsEnabled()) {
//NO ERROR, annotation
}
if (textView.isSuggestionsEnabled) {
//NO ERROR, annotation
}
}
@SuppressLint("NewApi")
fun testWithSuppressLintAnnotation(textView: TextView) {
if (textView.isSuggestionsEnabled()) {
//NO ERROR, annotation
}
if (textView.isSuggestionsEnabled) {
//NO ERROR, annotation
}
}
fun testCatch() {
try {
} catch (e: <error descr="Class requires API level 21 (current min is 1): android.system.ErrnoException">ErrnoException</error>) {
}
}
fun testOverload() {
// this overloaded addOval available only on API Level 21
Path().<error descr="Call requires API level 21 (current min is 1): android.graphics.Path#addOval">addOval</error>(0f, 0f, 0f, 0f, Path.Direction.CW)
}
// KT-14737 False error with short-circuit evaluation
fun testShortCircuitEvaluation() {
<error descr="Call requires API level 21 (current min is 1): android.content.Context#getDrawable">getDrawable</error>(0) // error here as expected
if(Build.VERSION.SDK_INT >= 23
&& null == getDrawable(0)) // error here should not occur
{
getDrawable(0) // no error here as expected
}
}
// KT-1482 Kotlin Lint: "Calling new methods on older versions" does not report call on receiver in extension function
private fun Bundle.caseE1a() { <error descr="Call requires API level 18 (current min is 1): android.os.Bundle#getBinder">getBinder</error>("") }
private fun Bundle.caseE1c() { this.<error descr="Call requires API level 18 (current min is 1): android.os.Bundle#getBinder">getBinder</error>("") }
private fun caseE1b(bundle: Bundle) { bundle.<error descr="Call requires API level 18 (current min is 1): android.os.Bundle#getBinder">getBinder</error>("") }
// KT-12023 Kotlin Lint: Cast doesn't trigger minSdk error
fun testCast(layout: ViewGroup) {
if (layout is LinearLayout) {} // OK API 1
layout as? LinearLayout // OK API 1
layout as LinearLayout // OK API 1
if (layout !is <error descr="Class requires API level 14 (current min is 1): android.widget.GridLayout">GridLayout</error>) {}
layout as? <error descr="Class requires API level 14 (current min is 1): android.widget.GridLayout">GridLayout</error>
layout as <error descr="Class requires API level 14 (current min is 1): android.widget.GridLayout">GridLayout</error>
val grid = layout as? <error descr="Class requires API level 14 (current min is 1): android.widget.GridLayout">GridLayout</error>
val linear = layout as LinearLayout // OK API 1
}
abstract class ErrorVectorDravable : <error descr="Call requires API level 21 (current min is 1): android.graphics.drawable.VectorDrawable#VectorDrawable"><error descr="Class requires API level 21 (current min is 1): android.graphics.drawable.VectorDrawable">VectorDrawable</error></error>(), Parcelable
@TargetApi(21)
class MyVectorDravable : VectorDrawable()
fun testTypes() {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(this)
val c = <error descr="Class requires API level 21 (current min is 1): android.graphics.drawable.VectorDrawable">VectorDrawable::class</error>.java
}
fun testCallWithApiAnnotation(textView: TextView) {
<error descr="Call requires API level 21 (current min is 1): ApiCallTest.MyVectorDravable#MyVectorDravable">MyVectorDravable</error>()
<error descr="Call requires API level 16 (current min is 1): ApiCallTest#testWithTargetApiAnnotation">testWithTargetApiAnnotation</error>(textView)
}
companion object : Activity() {
fun test() {
<error descr="Call requires API level 21 (current min is 1): android.content.Context#getDrawable">getDrawable</error>(0)
}
}
// Return type
internal // API 14
val gridLayout: GridLayout?
get() = null
private val report: ApplicationErrorReport?
get() = null
}
object O: Activity() {
fun test() {
<error descr="Call requires API level 21 (current min is 1): android.content.Context#getDrawable">getDrawable</error>(0)
}
}
fun testJava8() {
// Error, Api 24, Java8
mutableListOf(1, 2, 3).<error descr="Call requires API level 24 (current min is 1): java.util.Collection#removeIf">removeIf</error> {
true
}
// Ok, Kotlin
mutableListOf(1, 2, 3).removeAll {
true
}
// Error, Api 24, Java8
mapOf(1 to 2).<error descr="Call requires API level 24 (current min is 1): java.util.Map#forEach">forEach</error> { key, value -> key + value }
// Ok, Kotlin
mapOf(1 to 2).forEach { (key, value) -> key + value }
}
interface WithDefault {
// Should be ok
fun methodWithBody() {
return
}
}
-97
View File
@@ -1,97 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintMissingSuperCallInspection
package android.support.annotation
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.FUNCTION)
annotation class CallSuper
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class CallSuperTest {
private class Child : Parent() {
override fun <error descr="Overriding method should call `super.test1`">test1</error>() {
// ERROR
}
override fun <error descr="Overriding method should call `super.test2`">test2</error>() {
// ERROR
}
override fun <error descr="Overriding method should call `super.test3`">test3</error>() {
// ERROR
}
override fun <error descr="Overriding method should call `super.test4`">test4</error>(arg: Int) {
// ERROR
}
override fun test4(arg: String) {
// OK
}
override fun <error descr="Overriding method should call `super.test5`">test5</error>(arg1: Int, arg2: Boolean, arg3: Map<List<String>, *>, // ERROR
arg4: Array<IntArray>, vararg arg5: Int) {
}
override fun <error descr="Overriding method should call `super.test5`">test5</error>() {
// ERROR
super.test6() // (wrong super)
}
override fun test6() {
// OK
val x = 5
super.test6()
System.out.println(x)
}
}
private open class Parent : ParentParent() {
@CallSuper
protected open fun test1() {
}
override fun test3() {
super.test3()
}
@CallSuper
protected open fun test4(arg: Int) {
}
protected open fun test4(arg: String) {
}
@CallSuper
protected open fun test5() {
}
@CallSuper
protected open fun test5(arg1: Int, arg2: Boolean, arg3: Map<List<String>, *>,
arg4: Array<IntArray>, vararg arg5: Int) {
}
}
private open class ParentParent : ParentParentParent() {
@CallSuper
protected open fun test2() {
}
@CallSuper
protected open fun test3() {
}
@CallSuper
protected open fun test6() {
}
@CallSuper
protected fun test7() {
}
}
private open class ParentParentParent
}
-36
View File
@@ -1,36 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRecycleInspection
@file:Suppress("UNUSED_VARIABLE")
import android.app.Activity
import android.os.Bundle
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val cursor = contentResolver.<warning descr="This `Cursor` should be freed up after use with `#close()`">query</warning>(null, null, null, null, null)
// WARNING
contentResolver.<warning descr="This `Cursor` should be freed up after use with `#close()`">query</warning>(null, null, null, null, null)
// OK, closed in chained call
contentResolver.query(null, null, null, null, null).close()
// KT-14677: Kotlin Lint: "Missing recycle() calls" report cursor with `use()` call
val cursorUsed = contentResolver.query(null, null, null, null, null)
cursorUsed.use { }
// OK, used in chained call
contentResolver.query(null, null, null, null, null).use {
}
// KT-13372: Android Lint for Kotlin: false positive "Cursor should be freed" inside 'if' expression
if (true) {
val c = contentResolver.query(null, null, null, null, null)
c.close()
}
}
}
-41
View File
@@ -1,41 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintCommitTransactionInspection
@file:Suppress("UNUSED_VARIABLE")
import android.app.Activity
import android.app.FragmentTransaction
import android.app.FragmentManager
import android.os.Bundle
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//OK
val transaction = fragmentManager.beginTransaction()
val transaction2: FragmentTransaction
transaction2 = fragmentManager.beginTransaction()
transaction.commit()
transaction2.commit()
//WARNING
val transaction3 = fragmentManager.<warning descr="This transaction should be completed with a `commit()` call">beginTransaction</warning>()
//OK
fragmentManager.beginTransaction().commit()
fragmentManager.beginTransaction().add(null, "A").commit()
//OK KT-14470
Runnable {
val a = fragmentManager.beginTransaction()
a.commit()
}
}
// KT-14780: Kotlin Lint: "Missing commit() calls" false positive when the result of `commit()` is assigned or used as receiver
fun testResultOfCommit(fm: FragmentManager) {
val r1 = fm.beginTransaction().hide(fm.findFragmentByTag("aTag")).commit()
val r2 = fm.beginTransaction().hide(fm.findFragmentByTag("aTag")).commit().toString()
}
}
-193
View File
@@ -1,193 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintDrawAllocationInspection
// INSPECTION_CLASS2: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUseSparseArraysInspection
// INSPECTION_CLASS3: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUseValueOfInspection
import android.annotation.SuppressLint
import java.util.HashMap
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.SparseArray
import android.widget.Button
@SuppressWarnings("unused")
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class JavaPerformanceTest(context: Context, attrs: AttributeSet, defStyle: Int) : Button(context, attrs, defStyle) {
private var cachedRect: Rect? = null
private var shader: LinearGradient? = null
private var lastHeight: Int = 0
private var lastWidth: Int = 0
override fun onDraw(canvas: android.graphics.Canvas) {
super.onDraw(canvas)
// Various allocations:
java.lang.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">String("foo")</warning>
val s = java.lang.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">String("bar")</warning>
// This one should not be reported:
@SuppressLint("DrawAllocation")
val i = 5
// Cached object initialized lazily: should not complain about these
if (cachedRect == null) {
cachedRect = Rect(0, 0, 100, 100)
}
if (cachedRect == null || cachedRect!!.width() != 50) {
cachedRect = Rect(0, 0, 50, 100)
}
val b = java.lang.Boolean.valueOf(true)!! // auto-boxing
dummy(1, 2)
// Non-allocations
super.animate()
dummy2(1, 2)
// This will involve allocations, but we don't track
// inter-procedural stuff here
someOtherMethod()
}
internal fun dummy(foo: Int?, bar: Int) {
dummy2(foo!!, bar)
}
internal fun dummy2(foo: Int, bar: Int) {
}
internal fun someOtherMethod() {
// Allocations are okay here
java.lang.String("foo")
val s = java.lang.String("bar")
val b = java.lang.Boolean.valueOf(true)!! // auto-boxing
// Sparse array candidates
val myMap = <warning descr="Use `new SparseArray<String>(...)` instead for better performance">HashMap<Int, String>()</warning>
// Should use SparseBooleanArray
val myBoolMap = <warning descr="Use `new SparseBooleanArray(...)` instead for better performance">HashMap<Int, Boolean>()</warning>
// Should use SparseIntArray
val myIntMap = java.util.<warning descr="Use new `SparseIntArray(...)` instead for better performance">HashMap<Int, Int>()</warning>
// This one should not be reported:
@SuppressLint("UseSparseArrays")
val myOtherMap = HashMap<Int, Any>()
}
protected fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int,
x: Boolean) {
// wrong signature
java.lang.String("not an error")
}
protected fun onMeasure(widthMeasureSpec: Int) {
// wrong signature
java.lang.String("not an error")
}
protected fun onLayout(changed: Boolean, left: Int, top: Int, right: Int,
bottom: Int, wrong: Int) {
// wrong signature
java.lang.String("not an error")
}
protected fun onLayout(changed: Boolean, left: Int, top: Int, right: Int) {
// wrong signature
java.lang.String("not an error")
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int,
bottom: Int) {
java.lang.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">String("flag me")</warning>
}
@SuppressWarnings("null") // not real code
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
java.lang.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">String("flag me")</warning>
// Forbidden factory methods:
Bitmap.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">createBitmap(100, 100, null)</warning>
android.graphics.Bitmap.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">createScaledBitmap(null, 100, 100, false)</warning>
BitmapFactory.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">decodeFile(null)</warning>
val canvas: Canvas? = null
canvas!!.<warning descr="Avoid object allocations during draw operations: Use `Canvas.getClipBounds(Rect)` instead of `Canvas.getClipBounds()` which allocates a temporary `Rect`">getClipBounds()</warning> // allocates on your behalf
canvas.<warning descr="Avoid object allocations during draw operations: Use `Canvas.getClipBounds(Rect)` instead of `Canvas.getClipBounds()` which allocates a temporary `Rect`">clipBounds</warning> // allocates on your behalf
canvas.getClipBounds(null) // NOT an error
val layoutWidth = width
val layoutHeight = height
if (mAllowCrop && (mOverlay == null || mOverlay!!.width != layoutWidth ||
mOverlay!!.height != layoutHeight)) {
mOverlay = Bitmap.createBitmap(layoutWidth, layoutHeight, Bitmap.Config.ARGB_8888)
mOverlayCanvas = Canvas(mOverlay!!)
}
if (widthMeasureSpec == 42) {
throw IllegalStateException("Test") // NOT an allocation
}
// More lazy init tests
var initialized = false
if (!initialized) {
java.lang.String("foo")
initialized = true
}
// NOT lazy initialization
if (!initialized || mOverlay == null) {
java.lang.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">String("foo")</warning>
}
}
internal fun factories() {
val i1 = 42
val l1 = 42L
val b1 = true
val c1 = 'c'
val f1 = 1.0f
val d1 = 1.0
// The following should not generate errors:
val i3 = Integer.valueOf(42)
}
private val mAllowCrop: Boolean = false
private var mOverlayCanvas: Canvas? = null
private var mOverlay: Bitmap? = null
override fun layout(l: Int, t: Int, r: Int, b: Int) {
// Using "this." to reference fields
if (this.shader == null)
this.shader = LinearGradient(0f, 0f, width.toFloat(), 0f, intArrayOf(0), null,
Shader.TileMode.REPEAT)
val width = width
val height = height
if (shader == null || lastWidth != width || lastHeight != height) {
lastWidth = width
lastHeight = height
shader = LinearGradient(0f, 0f, width.toFloat(), 0f, intArrayOf(0), null, Shader.TileMode.REPEAT)
}
}
fun inefficientSparseArray() {
<warning descr="Use `new SparseIntArray(...)` instead for better performance">SparseArray<Int>()</warning> // Use SparseIntArray instead
SparseArray<Long>() // Use SparseLongArray instead
<warning descr="Use `new SparseBooleanArray(...)` instead for better performance">SparseArray<Boolean>()</warning> // Use SparseBooleanArray instead
SparseArray<Any>() // OK
}
fun longSparseArray() {
// but only minSdkVersion >= 17 or if has v4 support lib
val myStringMap = HashMap<Long, String>()
}
fun byteSparseArray() {
// bytes easily apply to ints
val myByteMap = <warning descr="Use `new SparseArray<String>(...)` instead for better performance">HashMap<Byte, String>()</warning>
}
}
-66
View File
@@ -1,66 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintJavascriptInterfaceInspection
import android.annotation.SuppressLint
import android.webkit.JavascriptInterface
import android.webkit.WebView
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "UNUSED_VALUE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class JavaScriptTestK {
fun test(webview: WebView) {
webview.addJavascriptInterface(AnnotatedObject(), "myobj")
webview.addJavascriptInterface(InheritsFromAnnotated(), "myobj")
webview.addJavascriptInterface(NonAnnotatedObject(), "myobj")
webview.addJavascriptInterface(null, "nothing")
webview.addJavascriptInterface(object : Any() { @JavascriptInterface fun method() {} }, "nothing")
webview.addJavascriptInterface(JavascriptFace(), "nothing")
var o: Any = NonAnnotatedObject()
webview.addJavascriptInterface(o, "myobj")
o = InheritsFromAnnotated()
webview.addJavascriptInterface(o, "myobj")
}
fun test(webview: WebView, object1: AnnotatedObject, object2: NonAnnotatedObject) {
webview.addJavascriptInterface(object1, "myobj")
webview.addJavascriptInterface(object2, "myobj")
}
@SuppressLint("JavascriptInterface")
fun testSuppressed(webview: WebView) {
webview.addJavascriptInterface(NonAnnotatedObject(), "myobj")
}
fun testLaterReassignment(webview: WebView) {
var o: Any = NonAnnotatedObject()
val t = o
webview.addJavascriptInterface(t, "myobj")
o = AnnotatedObject()
}
class NonAnnotatedObject() {
fun test1() {}
fun test2() {}
}
open class AnnotatedObject {
@JavascriptInterface
open fun test1() {}
open fun test2() {}
@JavascriptInterface
fun test3() {}
}
class InheritsFromAnnotated : AnnotatedObject() {
override fun test1() {}
override fun test2() {}
}
}
class JavascriptFace {
fun method() {}
}
-50
View File
@@ -1,50 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInflateParamsInspection
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
abstract class LayoutInflationTest : BaseAdapter() {
lateinit var mInflater: LayoutInflater
override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
var view = <warning descr="[VARIABLE_WITH_REDUNDANT_INITIALIZER] Variable 'view' initializer is redundant">convertView</warning>
<warning descr="[UNUSED_VALUE] The value 'mInflater.inflate(R.layout.your_layout, null)' assigned to 'var view: View defined in LayoutInflationTest.getView' is never used">view =</warning> mInflater.inflate(R.layout.your_layout, null)
<warning descr="[UNUSED_VALUE] The value 'mInflater.inflate(R.layout.your_layout, null, true)' assigned to 'var view: View defined in LayoutInflationTest.getView' is never used">view =</warning> mInflater.inflate(R.layout.your_layout, null, true)
view = mInflater.inflate(R.layout.your_layout, parent)
view = WeirdInflater.inflate(view, null)
return view
}
object WeirdInflater {
fun inflate(view: View, parent: View?) = view
}
object R {
object layout {
val your_layout = 1
}
}
}
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
abstract class LayoutInflationTest2 : BaseAdapter() {
lateinit var mInflater: LayoutInflater
override fun getView(position: Int, convertView: View, parent: ViewGroup): View? {
return if (true) {
mInflater.inflate(R.layout.your_layout, parent)
} else {
null
}
}
object R {
object layout {
val your_layout = 1
}
}
}
-111
View File
@@ -1,111 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLogConditionalInspection
// INSPECTION_CLASS2: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLogTagMismatchInspection
// INSPECTION_CLASS3: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLongLogTagInspection
import android.annotation.SuppressLint
import android.util.Log
import android.util.Log.DEBUG
@SuppressWarnings("UnusedDeclaration")
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class LogTest {
fun checkConditional(m: String) {
Log.d(TAG1, "message") // ok: unconditional, but not performing computation
Log.d(TAG1, m) // ok: unconditional, but not performing computation
Log.d(TAG1, "a" + "b") // ok: unconditional, but not performing non-constant computation
Log.d(TAG1, Constants.MY_MESSAGE) // ok: unconditional, but constant string
Log.<warning descr="The log call Log.i(...) should be conditional: surround with `if (Log.isLoggable(...))` or `if (BuildConfig.DEBUG) { ... }`">i(TAG1, "message" + m)</warning> // error: unconditional w/ computation
Log.<warning descr="The log call Log.i(...) should be conditional: surround with `if (Log.isLoggable(...))` or `if (BuildConfig.DEBUG) { ... }`">i(TAG1, toString())</warning> // error: unconditional w/ computation
Log.e(TAG1, toString()) // ok: only flagging debug/info messages
Log.w(TAG1, toString()) // ok: only flagging debug/info messages
Log.wtf(TAG1, toString()) // ok: only flagging debug/info messages
if (Log.isLoggable(TAG1, 0)) {
Log.d(TAG1, toString()) // ok: conditional
}
}
fun checkWrongTag(tag: String) {
if (Log.isLoggable(<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `TAG1` versus `TAG2` (Conflicting tag)">TAG1</error>, Log.DEBUG)) {
Log.d(<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `TAG1` versus `TAG2`">TAG2</error>, "message") // warn: mismatched tags!
}
if (Log.isLoggable("<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `\"my_tag\"` versus `\"other_tag\"` (Conflicting tag)">my_tag</error>", Log.DEBUG)) {
Log.d("<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `\"my_tag\"` versus `\"other_tag\"`">other_tag</error>", "message") // warn: mismatched tags!
}
if (Log.isLoggable("my_tag", Log.DEBUG)) {
Log.d("my_tag", "message") // ok: strings equal
}
if (Log.isLoggable(tag, Log.DEBUG)) {
Log.d(tag, "message") // ok: same variable
}
}
fun checkLongTag(shouldLog: Boolean) {
if (shouldLog) {
// String literal tags
Log.d("short_tag", "message") // ok: short
Log.<error descr="The logging tag can be at most 23 characters, was 43 (really_really_really_really_really_long_tag)">d("really_really_really_really_really_long_tag", "message")</error> // error: too long
// Resolved field tags
Log.d(TAG1, "message") // ok: short
Log.d(TAG22, "message") // ok: short
Log.d(TAG23, "message") // ok: threshold
Log.<error descr="The logging tag can be at most 23 characters, was 24 (123456789012345678901234)">d(TAG24, "message")</error> // error: too long
Log.<error descr="The logging tag can be at most 23 characters, was 39 (MyReallyReallyReallyReallyReallyLongTag)">d(LONG_TAG, "message")</error> // error: way too long
// Locally defined variable tags
val LOCAL_TAG = "MyReallyReallyReallyReallyReallyLongTag"
Log.<error descr="The logging tag can be at most 23 characters, was 39 (MyReallyReallyReallyReallyReallyLongTag)">d(LOCAL_TAG, "message")</error> // error: too long
// Concatenated tags
Log.<error descr="The logging tag can be at most 23 characters, was 28 (1234567890123456789012MyTag1)">d(TAG22 + TAG1, "message")</error> // error: too long
Log.<error descr="The logging tag can be at most 23 characters, was 27 (1234567890123456789012MyTag)">d(TAG22 + "MyTag", "message")</error> // error: too long
}
}
fun checkWrongLevel(tag: String) {
if (Log.isLoggable(TAG1, Log.DEBUG)) {
Log.d(TAG1, "message") // ok: right level
}
if (Log.isLoggable(TAG1, Log.INFO)) {
Log.i(TAG1, "message") // ok: right level
}
if (Log.isLoggable(TAG1, <error descr="Mismatched logging levels: when checking `isLoggable` level `DEBUG`, the corresponding log call should be `Log.d`, not `Log.v` (Conflicting tag)">Log.DEBUG</error>)) {
Log.<error descr="Mismatched logging levels: when checking `isLoggable` level `DEBUG`, the corresponding log call should be `Log.d`, not `Log.v`">v</error>(TAG1, "message") // warn: wrong level
}
if (Log.isLoggable(TAG1, <error descr="Mismatched logging levels: when checking `isLoggable` level `DEBUG`, the corresponding log call should be `Log.d`, not `Log.v` (Conflicting tag)">DEBUG</error>)) {
// static import of level
Log.<error descr="Mismatched logging levels: when checking `isLoggable` level `DEBUG`, the corresponding log call should be `Log.d`, not `Log.v`">v</error>(TAG1, "message") // warn: wrong level
}
if (Log.isLoggable(TAG1, <error descr="Mismatched logging levels: when checking `isLoggable` level `VERBOSE`, the corresponding log call should be `Log.v`, not `Log.d` (Conflicting tag)">Log.VERBOSE</error>)) {
Log.<error descr="Mismatched logging levels: when checking `isLoggable` level `VERBOSE`, the corresponding log call should be `Log.v`, not `Log.d`">d</error>(TAG1, "message") // warn? verbose is a lower logging level, which includes debug
}
if (Log.isLoggable(TAG1, Constants.MY_LEVEL)) {
Log.d(TAG1, "message") // ok: unknown level alias
}
}
@SuppressLint("all")
fun suppressed1() {
Log.d(TAG1, "message") // ok: suppressed
}
@SuppressLint("LogConditional")
fun suppressed2() {
Log.d(TAG1, "message") // ok: suppressed
}
private object Constants {
val MY_MESSAGE = "My Message"
val MY_LEVEL = 5
}
companion object {
private val TAG1 = "MyTag1"
private val TAG2 = "MyTag2"
private val TAG22 = "1234567890123456789012"
private val TAG23 = "12345678901234567890123"
private val TAG24 = "123456789012345678901234"
private val LONG_TAG = "MyReallyReallyReallyReallyReallyLongTag"
}
}
-19
View File
@@ -1,19 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUnlocalizedSmsInspection
import android.content.Context
import android.telephony.SmsManager
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class NonInternationalizedSmsDetectorTest {
private fun sendLocalizedMessage(context: Context) {
// Don't warn here
val sms = SmsManager.getDefault()
sms.sendTextMessage("+1234567890", null, null, null, null)
}
private fun sendAlternativeCountryPrefix(context: Context) {
// Do warn here
val sms = SmsManager.getDefault()
sms.sendMultipartTextMessage("<warning descr="To make sure the SMS can be sent by all users, please start the SMS number with a + and a country code or restrict the code invocation to people in the country you are targeting.">001234567890</warning>", null, null, null, null)
}
}
-61
View File
@@ -1,61 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverrideAbstractInspection
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.os.Build
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class OverrideConcreteTest2 {
// OK: This one specifies both methods
private open class MyNotificationListenerService1 : NotificationListenerService() {
override fun onNotificationPosted(statusBarNotification: StatusBarNotification) {
}
override fun onNotificationRemoved(statusBarNotification: StatusBarNotification) {
}
}
// Error: Misses onNotificationPosted
private class <error descr="Must override `android.service.notification.NotificationListenerService.onNotificationPosted(android.service.notification.StatusBarNotification)`: Method was abstract until 21, and your `minSdkVersion` is 18">MyNotificationListenerService2</error> : NotificationListenerService() {
override fun onNotificationRemoved(statusBarNotification: StatusBarNotification) {
}
}
// Error: Misses onNotificationRemoved
private open class <error descr="Must override `android.service.notification.NotificationListenerService.onNotificationRemoved(android.service.notification.StatusBarNotification)`: Method was abstract until 21, and your `minSdkVersion` is 18">MyNotificationListenerService3</error> : NotificationListenerService() {
override fun onNotificationPosted(statusBarNotification: StatusBarNotification) {
}
}
// Error: Missing both; wrong signatures (first has wrong arg count, second has wrong type)
private class <error descr="Must override `android.service.notification.NotificationListenerService.onNotificationPosted(android.service.notification.StatusBarNotification)`: Method was abstract until 21, and your `minSdkVersion` is 18">MyNotificationListenerService4</error> : NotificationListenerService() {
fun onNotificationPosted(statusBarNotification: StatusBarNotification, flags: Int) {
}
fun onNotificationRemoved(statusBarNotification: Int) {
}
}
// OK: Inherits from a class which define both
private class MyNotificationListenerService5 : MyNotificationListenerService1()
// OK: Inherits from a class which defines only one, but the other one is defined here
private class MyNotificationListenerService6 : MyNotificationListenerService3() {
override fun onNotificationRemoved(statusBarNotification: StatusBarNotification) {
}
}
// Error: Inheriting from a class which only defines one
private class <error descr="Must override `android.service.notification.NotificationListenerService.onNotificationRemoved(android.service.notification.StatusBarNotification)`: Method was abstract until 21, and your `minSdkVersion` is 18">MyNotificationListenerService7</error> : MyNotificationListenerService3()
// OK: Has target api setting a local version that is high enough
@TargetApi(21)
private class MyNotificationListenerService8 : NotificationListenerService()
// OK: Suppressed
@SuppressLint("OverrideAbstract")
private class MyNotificationListenerService9 : MyNotificationListenerService1()
}
-104
View File
@@ -1,104 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
@file:Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
import android.os.Parcel
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
class <error descr="This class implements `Parcelable` but does not provide a `CREATOR` field">MyParcelable1</error> : Parcelable {
override fun describeContents() = 0
override fun writeToParcel(arg0: Parcel, arg1: Int) {}
}
internal class MyParcelable2 : Parcelable {
override fun describeContents() = 0
override fun writeToParcel(arg0: Parcel, arg1: Int) {}
companion object {
@JvmField
val CREATOR: Parcelable.Creator<String> = object : Parcelable.Creator<String> {
override fun newArray(size: Int) = null!!
override fun createFromParcel(source: Parcel?) = null!!
}
}
}
internal class MyParcelable3 : Parcelable {
override fun describeContents() = 0
override fun writeToParcel(arg0: Parcel, arg1: Int) {}
companion object {
@JvmField
val CREATOR = 0 // Wrong type
}
}
class RecyclerViewScrollPosition(val position: Int, val topOffset: Int): Parcelable {
override fun describeContents(): Int = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeInt(position)
dest.writeInt(topOffset)
}
companion object {
@JvmField
val CREATOR = object : Parcelable.Creator<RecyclerViewScrollPosition> {
override fun createFromParcel(parcel: Parcel): RecyclerViewScrollPosition {
val position = parcel.readInt()
val topOffset = parcel.readInt()
return RecyclerViewScrollPosition(position, topOffset)
}
override fun newArray(size: Int): Array<RecyclerViewScrollPosition?> = arrayOfNulls(size)
}
}
}
class RecyclerViewScrollPositionWithoutJvmF(val position: Int, val topOffset: Int): Parcelable {
override fun describeContents(): Int = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeInt(position)
dest.writeInt(topOffset)
}
companion object {
val CREATOR = object : Parcelable.Creator<RecyclerViewScrollPosition> {
override fun createFromParcel(parcel: Parcel): RecyclerViewScrollPosition {
val position = parcel.readInt()
val topOffset = parcel.readInt()
return RecyclerViewScrollPosition(position, topOffset)
}
override fun newArray(size: Int): Array<RecyclerViewScrollPosition?> = arrayOfNulls(size)
}
}
}
class RecyclerViewScrollPosition2(val position: Int, val topOffset: Int): Parcelable {
override fun describeContents(): Int = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeInt(position)
dest.writeInt(topOffset)
}
companion object CREATOR: Parcelable.Creator<RecyclerViewScrollPosition> {
override fun createFromParcel(parcel: Parcel): RecyclerViewScrollPosition {
val position = parcel.readInt()
val topOffset = parcel.readInt()
return RecyclerViewScrollPosition(position, topOffset)
}
override fun newArray(size: Int): Array<RecyclerViewScrollPosition?> = arrayOfNulls(size)
}
}
internal abstract class MyParcelable4 : Parcelable {
override fun describeContents() = 0
override fun writeToParcel(arg0: Parcel, arg1: Int) {}
}
@Parcelize
class ParcelizeUser(val firstName: String, val lastName: String) : Parcelable
-45
View File
@@ -1,45 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection
import java.io.File
import android.content.Intent
import android.net.Uri
/**
* Ignore comments - create("/sdcard/foo")
*/
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class SdCardTest {
internal var deviceDir = File("<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard/vr</warning>")
init {
if (PROFILE_STARTUP) {
android.os.Debug.startMethodTracing("<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead"><warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard/launcher</warning></warning>")
}
if (File("<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead"><warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard</warning></warning>").exists()) {
}
val FilePath = "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead"><warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard/</warning></warning>" + File("test")
System.setProperty("foo.bar", "file://sdcard")
val intent = Intent(Intent.ACTION_PICK)
intent.setDataAndType(Uri.parse("<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead"><warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">file://sdcard/foo.json</warning></warning>"), "application/bar-json")
intent.putExtra("path-filter", "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead"><warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard(/.+)*</warning></warning>")
intent.putExtra("start-dir", "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead"><warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard</warning></warning>")
val mypath = "<warning descr="Do not hardcode \"`/data/`\"; use `Context.getFilesDir().getPath()` instead"><warning descr="Do not hardcode \"`/data/`\"; use `Context.getFilesDir().getPath()` instead">/data/data/foo</warning></warning>"
val base = "<warning descr="Do not hardcode \"`/data/`\"; use `Context.getFilesDir().getPath()` instead"><warning descr="Do not hardcode \"`/data/`\"; use `Context.getFilesDir().getPath()` instead">/data/data/foo.bar/test-profiling</warning></warning>"
val s = "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead"><warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">file://sdcard/foo</warning></warning>"
val sdCardPath by lazy { "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard</warning>" }
fun localPropertyTest() {
val sdCardPathLocal by lazy { "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard</warning>" }
}
}
companion object {
private val PROFILE_STARTUP = true
private val SDCARD_TEST_HTML = "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard/test.html</warning>"
val SDCARD_ROOT = "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard</warning>"
val PACKAGES_PATH = "<warning descr="Do not hardcode \"/sdcard/\"; use `Environment.getExternalStorageDirectory().getPath()` instead">/sdcard/o/packages/</warning>"
}
}
-24
View File
@@ -1,24 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSetJavaScriptEnabledInspection
import android.annotation.SuppressLint
import android.app.Activity
import android.webkit.WebView
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
public class HelloWebApp : Activity() {
fun test(webView: WebView) {
webView.settings.<warning descr="Using `setJavaScriptEnabled` can introduce XSS vulnerabilities into you application, review carefully.">javaScriptEnabled</warning> = true // bad
webView.getSettings().<warning descr="Using `setJavaScriptEnabled` can introduce XSS vulnerabilities into you application, review carefully.">setJavaScriptEnabled(true)</warning> // bad
webView.getSettings().setJavaScriptEnabled(false) // good
webView.loadUrl("file:///android_asset/www/index.html")
}
@SuppressLint("SetJavaScriptEnabled")
fun suppressed(webView: WebView) {
webView.getSettings().javaScriptEnabled = true; // bad
webView.getSettings().setJavaScriptEnabled(true) // bad
webView.getSettings().setJavaScriptEnabled(false); // good
webView.loadUrl("file:///android_asset/www/index.html");
}
}
-127
View File
@@ -1,127 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintCommitPrefEditsInspection
import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.preference.PreferenceManager
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class SharedPrefsText(context: Context) : Activity() {
// OK 1
fun onCreate1(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
val editor = preferences.edit()
editor.putString("foo", "bar")
editor.putInt("bar", 42)
editor.commit()
}
// OK 2
fun onCreate2(savedInstanceState: Bundle, apply: Boolean) {
super.onCreate(savedInstanceState)
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
val editor = preferences.edit()
editor.putString("foo", "bar")
editor.putInt("bar", 42)
if (apply) {
editor.apply()
}
}
// OK using with lambda
fun withLambda() {
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
with(preferences.edit()) {
putString("foo", "bar")
putInt("bar", 42)
apply()
}
}
// OK using apply lambda
fun testApplyLambda() {
PreferenceManager.getDefaultSharedPreferences(this).edit().apply {
putString("foo", "bar")
putInt("bar", 42)
apply()
}
}
// OK using also lambda
fun testAlsoLambda() {
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
preferences.edit().also {
it.putString("foo", "bar")
it.putInt("bar", 42)
it.apply()
}
}
// Not a bug
fun test(foo: Foo) {
val bar1 = foo.edit()
val bar3 = edit()
apply()
}
internal fun apply() {
}
fun edit(): Bar {
return Bar()
}
class Foo {
internal fun edit(): Bar {
return Bar()
}
}
class Bar
// Bug
fun bug1(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
val editor = preferences.<warning descr="`SharedPreferences.edit()` without a corresponding `commit()` or `apply()` call">edit()</warning>
editor.putString("foo", "bar")
editor.putInt("bar", 42)
}
// Bug missing commit in apply lambda
fun applyLambdaMissingCommit() {
PreferenceManager.getDefaultSharedPreferences(this).<warning descr="`SharedPreferences.edit()` without a corresponding `commit()` or `apply()` call">edit()</warning>.apply {
putString("foo", "bar")
putInt("bar", 42)
}
}
// Bug missing commit in also lambda
fun alsoLambdaMissingCommit() {
PreferenceManager.getDefaultSharedPreferences(this).<warning descr="`SharedPreferences.edit()` without a corresponding `commit()` or `apply()` call">edit()</warning>.also {
it.putString("foo", "bar")
it.putInt("bar", 42)
}
}
// Bug missing commit in with lambda
fun withLambdaMissingCommit() {
with(PreferenceManager.getDefaultSharedPreferences(this).<warning descr="`SharedPreferences.edit()` without a corresponding `commit()` or `apply()` call">edit()</warning>) {
putString("foo", "bar")
putInt("bar", 42)
}
}
init {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val editor = preferences.<warning descr="`SharedPreferences.edit()` without a corresponding `commit()` or `apply()` call"><warning descr="`SharedPreferences.edit()` without a corresponding `commit()` or `apply()` call">edit()</warning></warning>
editor.putString("foo", "bar")
}
fun testResultOfCommit() {
val r1 = PreferenceManager.getDefaultSharedPreferences(this).edit().putString("wat", "wat").commit()
val r2 = PreferenceManager.getDefaultSharedPreferences(this).edit().putString("wat", "wat").commit().toString()
}
}
@@ -1,9 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSQLiteStringInspection
import android.database.sqlite.SQLiteDatabase
fun test(db: SQLiteDatabase) {
val <warning descr="[UNUSED_VARIABLE] Variable 'a' is never used">a</warning>: String = <error descr="[CONSTANT_EXPECTED_TYPE_MISMATCH] The integer literal does not conform to the expected type String">1</error>
db.<warning descr="Using column type STRING; did you mean to use TEXT? (STRING is a numeric type and its value can be adjusted; for example, strings that look like integers can drop leading zeroes. See issue explanation for details.)">execSQL("CREATE TABLE COMPANY(NAME STRING)")</warning>
}
-7
View File
@@ -1,7 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSQLiteStringInspection
import android.database.sqlite.SQLiteDatabase
fun test(db: SQLiteDatabase) {
db.<warning descr="Using column type STRING; did you mean to use TEXT? (STRING is a numeric type and its value can be adjusted; for example, strings that look like integers can drop leading zeroes. See issue explanation for details.)">execSQL("CREATE TABLE COMPANY(NAME STRING)")</warning>
}
-36
View File
@@ -1,36 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSupportAnnotationUsageInspection
// DEPENDENCY: IntRange.java -> android/support/annotation/IntRange.java
// DEPENDENCY: RequiresPermission.java -> android/support/annotation/RequiresPermission.java
import android.support.annotation.IntRange
import android.support.annotation.RequiresPermission
import android.Manifest
import android.view.View
const val constantVal = 0L
<error descr="Invalid range: the `from` attribute must be less than the `to` attribute">@IntRange(from = 10, to = 0)</error>
fun invalidRange1a(): Int = 5
@IntRange(from = constantVal, to = 10) // ok
fun invalidRange0b(): Int = 5
<error descr="Invalid range: the `from` attribute must be less than the `to` attribute">@IntRange(from = 10, to = constantVal)</error>
fun invalidRange1b(): Int = 5
// should be ok, KT-16600
@RequiresPermission(anyOf = arrayOf(Manifest.permission.ACCESS_CHECKIN_PROPERTIES,
Manifest.permission.ACCESS_FINE_LOCATION))
fun needsPermissions1() { }
// should be ok, KT-16600
@RequiresPermission(Manifest.permission.ACCESS_CHECKIN_PROPERTIES)
fun needsPermissions2() { }
// error
<error descr="Only specify one of `value`, `anyOf` or `allOf`">@RequiresPermission(
value = Manifest.permission.ACCESS_CHECKIN_PROPERTIES,
anyOf = arrayOf(Manifest.permission.ACCESS_CHECKIN_PROPERTIES, Manifest.permission.ACCESS_FINE_LOCATION))</error>
fun needsPermissions3() { }
-29
View File
@@ -1,29 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintServiceCastInspection
import android.content.ClipboardManager
import android.app.Activity
import android.app.WallpaperManager
import android.content.Context
import android.hardware.display.DisplayManager
import android.service.wallpaper.WallpaperService
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class SystemServiceTest : Activity() {
fun test1() {
val displayServiceOk = getSystemService(DISPLAY_SERVICE) as DisplayManager
val displayServiceWrong = <error descr="Suspicious cast to `DisplayManager` for a `DEVICE_POLICY_SERVICE`: expected `DevicePolicyManager`">getSystemService(DEVICE_POLICY_SERVICE) as DisplayManager</error>
val wallPaperOk = getSystemService(WALLPAPER_SERVICE) as WallpaperService
val wallPaperWrong = <error descr="Suspicious cast to `WallpaperManager` for a `WALLPAPER_SERVICE`: expected `WallpaperService`">getSystemService(WALLPAPER_SERVICE) as WallpaperManager</error>
}
fun test2(context: Context) {
val displayServiceOk = context.getSystemService(DISPLAY_SERVICE) as DisplayManager
val displayServiceWrong = <error descr="Suspicious cast to `DisplayManager` for a `DEVICE_POLICY_SERVICE`: expected `DevicePolicyManager`">context.getSystemService(DEVICE_POLICY_SERVICE) as DisplayManager</error>
}
fun clipboard(context: Context) {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipboard2 = context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
}
}
-75
View File
@@ -1,75 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintShowToastInspection
import android.app.Activity
import android.content.Context
import android.widget.Toast
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class ToastTest(context: Context) : Activity() {
private fun createToast(context: Context): Toast {
// Don't warn here
return Toast.makeText(context, "foo", Toast.LENGTH_LONG)
}
private fun insideRunnable(context: Context) {
Runnable {
Toast.makeText(context, "foo", Toast.LENGTH_LONG).show()
}
Runnable {
val toast = Toast.makeText(context, "foo", Toast.LENGTH_LONG)
if (5 > 3) {
toast.show()
}
}
Runnable {
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(context, "foo", Toast.LENGTH_LONG)
}
}
private fun showToast(context: Context) {
// Don't warn here
val toast = Toast.makeText(context, "foo", Toast.LENGTH_LONG)
System.out.println("Other intermediate code here")
val temp = 5 + 2
toast.show()
}
private fun showToast2(context: Context) {
// Don't warn here
val duration = Toast.LENGTH_LONG
Toast.makeText(context, "foo", Toast.LENGTH_LONG).show()
Toast.makeText(context, R.string.app_name, duration).show()
}
private fun broken(context: Context) {
// Errors
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(context, "foo", Toast.LENGTH_LONG)
val toast = Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(context, R.string.app_name, <warning descr="Expected duration `Toast.LENGTH_SHORT` or `Toast.LENGTH_LONG`, a custom duration value is not supported">5000</warning>)
toast.duration
}
init {
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(context, "foo", Toast.LENGTH_LONG)
}
@android.annotation.SuppressLint("ShowToast")
private fun checkSuppress1(context: Context) {
val toast = Toast.makeText(this, "MyToast", Toast.LENGTH_LONG)
}
private fun checkSuppress2(context: Context) {
@android.annotation.SuppressLint("ShowToast")
val toast1 = Toast.makeText(this, "MyToast", Toast.LENGTH_LONG)
@android.annotation.SuppressLint("ShowToast", "Lorem ipsum")
val toast2 = Toast.makeText(this, "MyToast", Toast.LENGTH_LONG)
}
class R {
object string {
val app_name = 1
}
}
}
-8
View File
@@ -1,8 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUseValueOfInspection
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class Simple {
fun test() {
<warning descr="Use `Integer.valueOf(5)` instead">Integer(5)</warning>
}
}
@@ -1,23 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintRecycleInspection
@file:Suppress("UNUSED_VARIABLE")
import android.app.Activity
import android.os.Bundle
import android.view.VelocityTracker
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
VelocityTracker.<warning descr="This `VelocityTracker` should be recycled after use with `#recycle()`">obtain</warning>()
VelocityTracker.obtain().recycle()
val v1 = VelocityTracker.<warning descr="This `VelocityTracker` should be recycled after use with `#recycle()`">obtain</warning>()
val v2 = VelocityTracker.obtain()
v2.recycle()
}
}
-32
View File
@@ -1,32 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintViewConstructorInspection
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.TextView
class View1(context: Context?) : View(context)
class View2(context: Context?, attrs: AttributeSet?) : View(context, attrs)
class View3(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : TextView(context, attrs, defStyleAttr)
// Error
class <warning descr="Custom view `View4` is missing constructor used by tools: `(Context)` or `(Context,AttributeSet)` or `(Context,AttributeSet,int)`">View4</warning>(<warning descr="[UNUSED_PARAMETER] Parameter 'int' is never used">int</warning>: Int, context: Context?) : View(context)
// Error
class <warning descr="Custom view `View5` is missing constructor used by tools: `(Context)` or `(Context,AttributeSet)` or `(Context,AttributeSet,int)`">View5</warning>(context: Context?, attrs: AttributeSet?, val name: String) : View(context, attrs)
class View6 : View {
constructor(context: Context) : super(context) {
}
}
class View7 : View {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
}
// Error
class <warning descr="Custom view `View8` is missing constructor used by tools: `(Context)` or `(Context,AttributeSet)` or `(Context,AttributeSet,int)`">View8</warning> : View {
constructor(context: Context, <warning descr="[UNUSED_PARAMETER] Parameter 'a' is never used">a</warning>: Int) : super(context)
}
-154
View File
@@ -1,154 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintViewHolderInspection
@file:Suppress("NAME_SHADOWING", "unused", "UNUSED_VALUE", "VARIABLE_WITH_REDUNDANT_INITIALIZER", "UNUSED_VARIABLE")
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.LinearLayout
import android.widget.TextView
import java.util.ArrayList
@SuppressWarnings("ConstantConditions", "UnusedDeclaration")
abstract class ViewHolderTest : BaseAdapter() {
override fun getCount() = 0
override fun getItem(position: Int) = null
override fun getItemId(position: Int) = 0L
class Adapter1 : ViewHolderTest() {
override fun getView(position: Int, convertView: View, parent: ViewGroup) = null
}
class Adapter2 : ViewHolderTest() {
lateinit var mInflater: LayoutInflater
override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
var convertView = convertView
// Should use View Holder pattern here
convertView = mInflater.<warning descr="Unconditional layout inflation from view adapter: Should use View Holder pattern (use recycled view passed into this method as the second parameter) for smoother scrolling">inflate(R.layout.your_layout, null)</warning>
val text: TextView = convertView.findViewById(R.id.text)
text.text = "Position " + position
return convertView
}
}
class Adapter3 : ViewHolderTest() {
lateinit var mInflater: LayoutInflater
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
// Already using View Holder pattern
if (convertView == null) {
convertView = mInflater.inflate(R.layout.your_layout, null)
}
val text: TextView = convertView!!.findViewById(R.id.text)
text.text = "Position " + position
return convertView
}
}
class Adapter4 : ViewHolderTest() {
lateinit var mInflater: LayoutInflater
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
// Already using View Holder pattern
//noinspection StatementWithEmptyBody
if (convertView != null) {
} else {
convertView = mInflater.inflate(R.layout.your_layout, null)
}
val text: TextView = convertView!!.findViewById(R.id.text)
text.text = "Position " + position
return convertView
}
}
class Adapter5 : ViewHolderTest() {
lateinit var mInflater: LayoutInflater
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
// Already using View Holder pattern
convertView = if (convertView == null) mInflater.inflate(R.layout.your_layout, null) else convertView
val text: TextView = convertView!!.findViewById(R.id.text)
text.text = "Position " + position
return convertView
}
}
class Adapter6 : ViewHolderTest() {
private val mContext: Context? = null
private var mLayoutInflator: LayoutInflater? = null
private lateinit var mLapTimes: ArrayList<Double>
override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
if (mLayoutInflator == null)
mLayoutInflator = mContext!!.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
var v: View? = convertView
if (v == null) v = mLayoutInflator!!.inflate(R.layout.your_layout, null)
val listItemHolder: LinearLayout = v!!.findViewById(R.id.laptimes_list_item_holder)
listItemHolder.removeAllViews()
for (i in 1..5) {
val lapItemView: View = mLayoutInflator!!.inflate(R.layout.laptime_item, null)
if (i == 0) {
val t: TextView = lapItemView.findViewById(R.id.laptime_text)
}
val t2: TextView = lapItemView.findViewById(R.id.laptime_text2)
if (i < mLapTimes.size - 1 && mLapTimes.size > 1) {
var laptime = mLapTimes[i] - mLapTimes[i + 1]
if (laptime < 0) laptime = mLapTimes[i]
}
listItemHolder.addView(lapItemView)
}
return v
}
}
class Adapter7 : ViewHolderTest() {
lateinit var inflater: LayoutInflater
override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
var rootView: View? = convertView
val itemViewType = getItemViewType(position)
when (itemViewType) {
0 -> {
if (rootView != null)
return rootView
rootView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false)
}
}
return rootView!!
}
}
class R {
object layout {
val your_layout = 1
val laptime_item = 2
}
object id {
val laptime_text = 1
val laptime_text2 = 2
val laptimes_list_item_holder = 3
val text = 4
}
}
}
-42
View File
@@ -1,42 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLocalSuppressInspection
import android.annotation.SuppressLint
import android.view.View
@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
class WrongAnnotation2 {
@SuppressLint("NewApi")
private val field1: Int = 0
@SuppressLint("NewApi")
private val field2 = 5
companion object {
@SuppressLint("NewApi") // Valid: class-file check on method
fun foobar(view: View, @SuppressLint("NewApi") foo: Int) {
// Invalid: class-file check
<error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method">@SuppressLint("NewApi")</error> // Invalid
val a: Boolean
@SuppressLint("SdCardPath", "NewApi") // TODO: Invalid, class-file based check on local variable
val b: Boolean
@android.annotation.SuppressLint("SdCardPath", "NewApi") // TDOD: Invalid (FQN)
val c: Boolean
@SuppressLint("SdCardPath") // Valid: AST-based check
val d: Boolean
}
init {
// Local variable outside method: invalid
<error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method">@SuppressLint("NewApi")</error>
val localvar = 5
}
private fun test() {
<error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method">@SuppressLint("NewApi")</error> // Invalid
val a = View.MEASURED_STATE_MASK
}
}
}
-8
View File
@@ -1,8 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSuspiciousImportInspection
//Warning
<warning descr="Don't include `android.R` here; use a fully qualified name for each usage instead">import android.R</warning>
fun a() {
R.id.button1
}
-23
View File
@@ -1,23 +0,0 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintWrongCallInspection
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import android.widget.FrameLayout
import android.widget.LinearLayout
abstract class WrongViewCall(context: Context, attrs: AttributeSet, defStyle: Int) : LinearLayout(context, attrs, defStyle) {
private val child: MyChild? = null
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
child?.<error descr="Suspicious method call; should probably call \"`draw`\" rather than \"`onDraw`\"">onDraw</error>(canvas)
}
private inner class MyChild(context: Context, attrs: AttributeSet, defStyle: Int) : FrameLayout(context, attrs, defStyle) {
public override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
}
}
}
@@ -1,14 +0,0 @@
// INTENTION_TEXT: Add Parcelable Implementation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
import android.os.Parcel
import android.os.Parcelable
class <caret>MissingCreator : Parcelable {
override fun writeToParcel(dest: Parcel?, flags: Int) {
TODO("not implemented")
}
override fun describeContents(): Int {
TODO("not implemented")
}
}
@@ -1,27 +0,0 @@
// INTENTION_TEXT: Add Parcelable Implementation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
import android.os.Parcel
import android.os.Parcelable
class MissingCreator() : Parcelable {
constructor(parcel: Parcel) : this() {
}
override fun writeToParcel(dest: Parcel?, flags: Int) {
TODO("not implemented")
}
override fun describeContents(): Int {
TODO("not implemented")
}
companion object CREATOR : Parcelable.Creator<MissingCreator> {
override fun createFromParcel(parcel: Parcel): MissingCreator {
return MissingCreator(parcel)
}
override fun newArray(size: Int): Array<MissingCreator?> {
return arrayOfNulls(size)
}
}
}
@@ -1,5 +0,0 @@
// INTENTION_TEXT: Add Parcelable Implementation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
import android.os.Parcelable
class <caret>NoImplementation : Parcelable
@@ -1,27 +0,0 @@
// INTENTION_TEXT: Add Parcelable Implementation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
import android.os.Parcel
import android.os.Parcelable
class NoImplementation() : Parcelable {
constructor(parcel: Parcel) : this() {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<NoImplementation> {
override fun createFromParcel(parcel: Parcel): NoImplementation {
return NoImplementation(parcel)
}
override fun newArray(size: Int): Array<NoImplementation?> {
return arrayOfNulls(size)
}
}
}
@@ -1,11 +0,0 @@
// INTENTION_TEXT: Add @RequiresApi(LOLLIPOP) Annotation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
// DEPENDENCY: RequiresApi.java -> android/support/annotation/RequiresApi.java
import android.graphics.drawable.VectorDrawable
class VectorDrawableProvider {
companion object {
val VECTOR_DRAWABLE = <caret>VectorDrawable()
}
}
@@ -1,14 +0,0 @@
// INTENTION_TEXT: Add @RequiresApi(LOLLIPOP) Annotation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
// DEPENDENCY: RequiresApi.java -> android/support/annotation/RequiresApi.java
import android.graphics.drawable.VectorDrawable
import android.os.Build
import android.support.annotation.RequiresApi
class VectorDrawableProvider {
companion object {
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
val VECTOR_DRAWABLE = VectorDrawable()
}
}
@@ -1,10 +0,0 @@
// INTENTION_TEXT: Add @RequiresApi(LOLLIPOP) Annotation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
// DEPENDENCY: RequiresApi.java -> android/support/annotation/RequiresApi.java
import android.graphics.drawable.VectorDrawable
fun withDefaultParameter(vector: VectorDrawable = <caret>VectorDrawable()) {
}
@@ -1,13 +0,0 @@
// INTENTION_TEXT: Add @RequiresApi(LOLLIPOP) Annotation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
// DEPENDENCY: RequiresApi.java -> android/support/annotation/RequiresApi.java
import android.graphics.drawable.VectorDrawable
import android.os.Build
import android.support.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun withDefaultParameter(vector: VectorDrawable = VectorDrawable()) {
}
@@ -1,9 +0,0 @@
// INTENTION_TEXT: Add @RequiresApi(LOLLIPOP) Annotation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
// DEPENDENCY: RequiresApi.java -> android/support/annotation/RequiresApi.java
import android.graphics.drawable.VectorDrawable
class MyVectorDrawable : <caret>VectorDrawable() {
}
@@ -1,12 +0,0 @@
// INTENTION_TEXT: Add @RequiresApi(LOLLIPOP) Annotation
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
// DEPENDENCY: RequiresApi.java -> android/support/annotation/RequiresApi.java
import android.graphics.drawable.VectorDrawable
import android.os.Build
import android.support.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class MyVectorDrawable : VectorDrawable() {
}

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