blob: 4897f97b68e71c9cd284e7b75bcf6c65c92281e3 [file]
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.gradle.config
import com.intellij.codeInsight.daemon.ImplicitUsageProvider
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifierList
import com.intellij.psi.util.PropertyUtilBase.*
import com.intellij.usages.impl.rules.UsageType
import com.intellij.util.Processor
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_TASKS_ACTION
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField
/**
* @author Vladislav.Soroka
*/
class GradleImplicitUsageProvider : ImplicitUsageProvider {
companion object {
val taskAnnotations = listOf("org.gradle.api.tasks.Input",
"org.gradle.api.tasks.InputFile",
"org.gradle.api.tasks.InputFiles",
"org.gradle.api.tasks.InputDirectory",
"org.gradle.api.tasks.OutputDirectory",
"org.gradle.api.tasks.OutputDirectories",
"org.gradle.api.tasks.OutputFile",
"org.gradle.api.tasks.LocalState",
"org.gradle.api.tasks.Destroys",
"org.gradle.api.tasks.Classpath",
"org.gradle.api.tasks.Console")
}
override fun isImplicitUsage(element: PsiElement): Boolean {
var modifierList: PsiModifierList? = null
if (element is GrField) {
modifierList = element.modifierList
}
else if (element is PsiMethod) {
if (element.modifierList.hasAnnotation(GRADLE_API_TASKS_ACTION)) return true
if (isSimplePropertyGetter(element)) {
modifierList = element.modifierList
}
else if (isSimplePropertySetter(element)) {
val getter = getPropertyName(element)?.let { findPropertyGetter(element.containingClass, it, false, false) }
modifierList = getter?.modifierList
}
}
if (modifierList?.let { taskAnnotations.find(modifierList::hasAnnotation) } != null) {
return true
}
return hasUsageOfType(element, null)
}
override fun isImplicitRead(element: PsiElement): Boolean {
return hasUsageOfType(element, UsageType.READ)
}
override fun isImplicitWrite(element: PsiElement): Boolean {
return hasUsageOfType(element, UsageType.WRITE)
}
private fun hasUsageOfType(element: PsiElement, usage: UsageType?): Boolean {
if (element !is PsiMember) return false
val found = Ref.create(false)
GradleUseScopeEnlarger.search(element, Processor {
if (!it.isReferenceTo(element))
return@Processor true
if (usage == null) {
found.set(true)
return@Processor false
}
val readWriteAccessDetector = ReadWriteAccessDetector.findDetector(element) ?: return@Processor true
when (readWriteAccessDetector.getReferenceAccess(it.element, it)) {
ReadWriteAccessDetector.Access.ReadWrite -> {
found.set(true)
return@Processor false
}
ReadWriteAccessDetector.Access.Read -> {
if (usage == UsageType.READ) {
found.set(true)
return@Processor false
}
}
ReadWriteAccessDetector.Access.Write -> {
if (usage == UsageType.WRITE) {
found.set(true)
return@Processor false
}
}
}
true
})
return found.get()
}
}