*/
package com.intellij.codeInspection.dataFlow
-import com.intellij.ide.highlighter.JavaFileType
import com.intellij.lang.LighterAST
import com.intellij.lang.LighterASTNode
-import com.intellij.lang.TreeBackedLighterAST
-import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiMethod
-import com.intellij.psi.impl.source.JavaFileElementType
import com.intellij.psi.impl.source.JavaLightStubBuilder
import com.intellij.psi.impl.source.PsiFileImpl
import com.intellij.psi.impl.source.PsiMethodImpl
import com.intellij.psi.impl.source.tree.JavaElementType.*
import com.intellij.psi.impl.source.tree.LightTreeUtil
import com.intellij.psi.impl.source.tree.RecursiveLighterASTNodeWalkingVisitor
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.util.CachedValueProvider
-import com.intellij.psi.util.CachedValuesManager
-import com.intellij.util.indexing.*
-import com.intellij.util.io.DataExternalizer
-import com.intellij.util.io.IntInlineKeyDescriptor
+import com.intellij.util.gist.GistManager
import java.util.*
/**
* @author peter
*/
-private val INDEX_ID = ID.create<Int, MethodData>("java.inferred.contracts")
-
-class ContractInferenceIndex : FileBasedIndexExtension<Int, MethodData>(), PsiDependentIndex {
- override fun getName() = INDEX_ID
- override fun getVersion() = 0
- override fun dependsOnFileContent() = true
- override fun getKeyDescriptor() = IntInlineKeyDescriptor()
- override fun getValueExternalizer(): DataExternalizer<MethodData> = MethodDataExternalizer
-
- override fun getInputFilter() = FileBasedIndex.InputFilter {
- it.fileType == JavaFileType.INSTANCE && JavaFileElementType.isInSourceContent(it)
- }
-
- override fun getIndexer() = DataIndexer<Int, MethodData, FileContent> { fc ->
- val result = HashMap<Int, MethodData>()
-
- val tree = (fc as FileContentImpl).lighterASTForPsiDependentIndex
- object : RecursiveLighterASTNodeWalkingVisitor(tree) {
- var methodIndex = 0
+private val gist = GistManager.getInstance().newPsiFileGist("contractInference", 0, MethodDataExternalizer) { file ->
+ indexFile(file.node.lighterAST)
+}
- override fun visitNode(element: LighterASTNode) {
- if (element.tokenType === JavaElementType.METHOD) {
- calcData(tree, element)?.let { data -> result[methodIndex] = data }
- methodIndex++
- }
+private fun indexFile(tree: LighterAST): Map<Int, MethodData> {
+ val result = HashMap<Int, MethodData>()
- if (JavaLightStubBuilder.isCodeBlockWithoutStubs(element)) return
+ object : RecursiveLighterASTNodeWalkingVisitor(tree) {
+ var methodIndex = 0
- super.visitNode(element)
+ override fun visitNode(element: LighterASTNode) {
+ if (element.tokenType === METHOD) {
+ calcData(tree, element)?.let { data -> result[methodIndex] = data }
+ methodIndex++
}
- }.visitNode(tree.root)
- result
- }
+ if (JavaLightStubBuilder.isCodeBlockWithoutStubs(element)) return
+
+ super.visitNode(element)
+ }
+ }.visitNode(tree.root)
+ return result
}
private fun calcData(tree: LighterAST, method: LighterASTNode): MethodData? {
fun getIndexedData(method: PsiMethod): MethodData? {
if (method !is PsiMethodImpl || !InferenceFromSourceUtil.shouldInferFromSource(method)) return null
- val vFile = method.containingFile.virtualFile ?: return calcNonPhysicalMethodData(method)
- val ref = Ref<MethodData>()
- val scope = GlobalSearchScope.fileScope(method.project, vFile)
- FileBasedIndex.getInstance().processValues(INDEX_ID, methodIndex(method), vFile, { file, data -> ref.set(data); true }, scope)
- return ref.get()
+ return gist.getFileData(method.containingFile)?.get(methodIndex(method))
}
private fun methodIndex(method: PsiMethodImpl): Int {
val file = method.containingFile as PsiFileImpl
val stubTree = file.stubTree ?: file.calcStubTree()
return stubTree.plainList.filter { it.stubType == JavaElementType.METHOD }.map { it.psi }.indexOf(method)
-}
-
-private fun calcNonPhysicalMethodData(method: PsiMethodImpl): MethodData? {
- return CachedValuesManager.getCachedValue(method) {
- CachedValueProvider.Result(calcData(method.containingFile.node.lighterAST, TreeBackedLighterAST.wrap(method.node)), method)
- }
}
\ No newline at end of file
import com.intellij.util.io.DataExternalizer
import com.intellij.util.io.DataInputOutputUtil
-import com.intellij.util.io.IOUtil
import java.io.DataInput
import java.io.DataOutput
/**
* @author peter
*/
-internal object MethodDataExternalizer : DataExternalizer<MethodData> {
+internal object MethodDataExternalizer : DataExternalizer<Map<Int, MethodData>> {
- override fun save(out: DataOutput, data: MethodData) {
+ override fun save(out: DataOutput, value: Map<Int, MethodData>?) {
+ writeList(out, value!!.toList()) { DataInputOutputUtil.writeINT(out, it.first); writeMethod(out, it.second) }
+ }
+
+ override fun read(input: DataInput) = readList(input) { DataInputOutputUtil.readINT(input) to readMethod(input) }.toMap()
+
+ private fun writeMethod(out: DataOutput, data: MethodData) {
writeNullable(out, data.nullity) { writeNullity(out, it) }
writeNullable(out, data.purity) { writePurity(out, it) }
writeList(out, data.contracts) { writeContract(out, it) }
DataInputOutputUtil.writeINT(out, data.bodyEnd)
}
- override fun read(input: DataInput): MethodData {
+ private fun readMethod(input: DataInput): MethodData {
val nullity = readNullable(input) { readNullity(input) }
val purity = readNullable(input) { readPurity(input) }
val contracts = readList(input) { readContract(input) }