Refactored to ensure use of correct options

This commit is contained in:
Valentin Kipyatkov
2016-09-08 02:44:35 +03:00
parent 32e4a033db
commit 1d24fc3a7b
@@ -147,33 +147,34 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
val failedToImportDescriptors = LinkedHashSet<DeclarationDescriptor>() val failedToImportDescriptors = LinkedHashSet<DeclarationDescriptor>()
while (true) { while (true) {
// Visitor order is important here so that enclosing elements are not shortened before their children are, e.g. // Processors order is important here so that enclosing elements are not shortened before their children are, e.g.
// test.foo(this@A) -> foo(this) // test.foo(this@A) -> foo(this)
val visitors: List<ShorteningVisitor<*>> = listOf( val processors: List<ShorteningProcessor<*>> = listOf(
ShortenTypesVisitor(file, elementFilter, failedToImportDescriptors), ShortenTypesProcessor(file, elementFilter, failedToImportDescriptors),
ShortenThisExpressionsVisitor(file, elementFilter, failedToImportDescriptors), ShortenThisExpressionsProcessor(file, elementFilter, failedToImportDescriptors),
ShortenQualifiedExpressionsVisitor(file, elementFilter, failedToImportDescriptors), ShortenQualifiedExpressionsProcessor(file, elementFilter, failedToImportDescriptors),
RemoveExplicitCompanionObjectReferenceVisitor(file, elementFilter, failedToImportDescriptors) RemoveExplicitCompanionObjectReferenceProcessor(file, elementFilter, failedToImportDescriptors)
) )
// step 1: collect qualified elements to analyze (no resolve at this step) // step 1: collect qualified elements to analyze (no resolve at this step)
val visitors = processors.map { it.collectElementsVisitor }
for (visitor in visitors) { for (visitor in visitors) {
for (element in elementsToUse) { for (element in elementsToUse) {
visitor.options = options(element) visitor.options = options(element)
element.accept(visitor) element.accept(visitor)
} }
} }
val elementsToAnalyze = visitors.flatMap { it.getElementsToAnalyze() }
// step 2: analyze collected elements with resolve and decide which can be shortened now and which need descriptors to be imported before shortening // step 2: analyze collected elements with resolve and decide which can be shortened now and which need descriptors to be imported before shortening
val bindingContext = file.getResolutionFacade().analyze(elementsToAnalyze, BodyResolveMode.PARTIAL) val allElementsToAnalyze = visitors.flatMap { it.getElementsToAnalyze().map { it.element } }
visitors.forEach { it.analyzeCollectedElements(bindingContext) } val bindingContext = file.getResolutionFacade().analyze(allElementsToAnalyze, BodyResolveMode.PARTIAL)
processors.forEach { it.analyzeCollectedElements(bindingContext) }
// step 3: shorten elements that can be shortened right now // step 3: shorten elements that can be shortened right now
visitors.forEach { it.shortenElements(elementsToUse) } processors.forEach { it.shortenElements(elementSetToUpdate = elementsToUse) }
// step 4: try to import descriptors needed to shorten other elements // step 4: try to import descriptors needed to shorten other elements
val descriptorsToImport = visitors.flatMap { it.getDescriptorsToImport() }.toSet() val descriptorsToImport = processors.flatMap { it.getDescriptorsToImport() }.toSet()
var anyChange = false var anyChange = false
for (descriptor in descriptorsToImport) { for (descriptor in descriptorsToImport) {
assert(descriptor !in failedToImportDescriptors) assert(descriptor !in failedToImportDescriptors)
@@ -199,20 +200,15 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
} }
} }
private abstract class ShorteningVisitor<TElement : KtElement>(
protected val file: KtFile,
protected val elementFilter: (PsiElement) -> FilterResult,
protected val failedToImportDescriptors: Set<DeclarationDescriptor>
) : KtVisitorVoid() {
var options: Options = Options.DEFAULT
private data class ElementToAnalyze<TElement>(val element: TElement, val level: Int) private data class ElementToAnalyze<TElement>(val element: TElement, val level: Int)
private val elementsToAnalyze = ArrayList<ElementToAnalyze<TElement>>() private abstract class CollectElementsVisitor<TElement : KtElement>(
private val elementsToShorten = ArrayList<TElement>() protected val elementFilter: (PsiElement) -> FilterResult
private val descriptorsToImport = LinkedHashSet<DeclarationDescriptor>() ) : KtVisitorVoid() {
protected val resolutionFacade = file.getResolutionFacade() var options: Options = Options.DEFAULT
private val elementsToAnalyze = ArrayList<ElementToAnalyze<TElement>>()
private var level = 0 private var level = 0
@@ -232,10 +228,31 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
elementsToAnalyze.add(ElementToAnalyze(element, level)) elementsToAnalyze.add(ElementToAnalyze(element, level))
} }
override fun visitElement(element: PsiElement) {
if (elementFilter(element) != FilterResult.SKIP) {
element.acceptChildren(this)
}
}
fun getElementsToAnalyze(): List<ElementToAnalyze<TElement>> = elementsToAnalyze
}
private abstract class ShorteningProcessor<TElement : KtElement>(
protected val file: KtFile,
protected val failedToImportDescriptors: Set<DeclarationDescriptor>
) {
protected val resolutionFacade = file.getResolutionFacade()
private val elementsToShorten = ArrayList<TElement>()
private val descriptorsToImport = LinkedHashSet<DeclarationDescriptor>()
abstract val collectElementsVisitor: CollectElementsVisitor<TElement>
fun analyzeCollectedElements(bindingContext: BindingContext) { fun analyzeCollectedElements(bindingContext: BindingContext) {
val elements = collectElementsVisitor.getElementsToAnalyze()
var index = 0 var index = 0
while (index < elementsToAnalyze.size) { while (index < elements.size) {
val (element, level) = elementsToAnalyze[index++] val (element, level) = elements[index++]
val result = analyzeQualifiedElement(element, bindingContext) val result = analyzeQualifiedElement(element, bindingContext)
@@ -266,7 +283,7 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
if (toBeShortened) { if (toBeShortened) {
// we are going to shorten qualified element - we must skip all elements inside its qualifier // we are going to shorten qualified element - we must skip all elements inside its qualifier
while (index < elementsToAnalyze.size && elementsToAnalyze[index].level > level) { while (index < elements.size && elements[index].level > level) {
index++ index++
} }
} }
@@ -292,12 +309,6 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
protected abstract fun shortenElement(element: TElement): KtElement protected abstract fun shortenElement(element: TElement): KtElement
override fun visitElement(element: PsiElement) {
if (elementFilter(element) != FilterResult.SKIP) {
element.acceptChildren(this)
}
}
fun shortenElements(elementSetToUpdate: MutableSet<KtElement>) { fun shortenElements(elementSetToUpdate: MutableSet<KtElement>) {
for (element in elementsToShorten) { for (element in elementsToShorten) {
if (!element.isValid) continue if (!element.isValid) continue
@@ -315,15 +326,17 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
} }
} }
fun getElementsToAnalyze(): Collection<TElement> = elementsToAnalyze.map { it.element }
fun getDescriptorsToImport(): Set<DeclarationDescriptor> = descriptorsToImport fun getDescriptorsToImport(): Set<DeclarationDescriptor> = descriptorsToImport
} }
private class ShortenTypesVisitor( private class ShortenTypesProcessor(
file: KtFile, file: KtFile,
elementFilter: (PsiElement) -> FilterResult, elementFilter: (PsiElement) -> FilterResult,
failedToImportDescriptors: Set<DeclarationDescriptor> failedToImportDescriptors: Set<DeclarationDescriptor>
) : ShorteningVisitor<KtUserType>(file, elementFilter, failedToImportDescriptors) { ) : ShorteningProcessor<KtUserType>(file, failedToImportDescriptors) {
override val collectElementsVisitor: CollectElementsVisitor<KtUserType> =
object : CollectElementsVisitor<KtUserType>(elementFilter) {
override fun visitUserType(userType: KtUserType) { override fun visitUserType(userType: KtUserType) {
val filterResult = elementFilter(userType) val filterResult = elementFilter(userType)
if (filterResult == FilterResult.SKIP) return if (filterResult == FilterResult.SKIP) return
@@ -339,6 +352,7 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
userType.qualifier?.accept(this) userType.qualifier?.accept(this)
prevLevel() prevLevel()
} }
}
override fun analyzeQualifiedElement(element: KtUserType, bindingContext: BindingContext): AnalyzeQualifiedElementResult { override fun analyzeQualifiedElement(element: KtUserType, bindingContext: BindingContext): AnalyzeQualifiedElementResult {
if (element.qualifier == null) return Skip if (element.qualifier == null) return Skip
@@ -363,12 +377,13 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
} }
} }
private abstract class QualifiedExpressionShorteningVisitor( private abstract class QualifiedExpressionShorteningProcessor(
file: KtFile, file: KtFile,
elementFilter: (PsiElement) -> FilterResult, elementFilter: (PsiElement) -> FilterResult,
failedToImportDescriptors: Set<DeclarationDescriptor> failedToImportDescriptors: Set<DeclarationDescriptor>
) : ShorteningVisitor<KtDotQualifiedExpression>(file, elementFilter, failedToImportDescriptors) { ) : ShorteningProcessor<KtDotQualifiedExpression>(file, failedToImportDescriptors) {
protected open class MyVisitor(elementFilter: (PsiElement) -> FilterResult) : CollectElementsVisitor<KtDotQualifiedExpression>(elementFilter) {
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) { override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
val filterResult = elementFilter(expression) val filterResult = elementFilter(expression)
if (filterResult == FilterResult.SKIP) return if (filterResult == FilterResult.SKIP) return
@@ -386,16 +401,21 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
} }
} }
private class ShortenQualifiedExpressionsVisitor( override val collectElementsVisitor = MyVisitor(elementFilter)
}
private class ShortenQualifiedExpressionsProcessor(
file: KtFile, file: KtFile,
elementFilter: (PsiElement) -> FilterResult, elementFilter: (PsiElement) -> FilterResult,
failedToImportDescriptors: Set<DeclarationDescriptor> failedToImportDescriptors: Set<DeclarationDescriptor>
) : QualifiedExpressionShorteningVisitor(file, elementFilter, failedToImportDescriptors) { ) : QualifiedExpressionShorteningProcessor(file, elementFilter, failedToImportDescriptors) {
override val collectElementsVisitor = object : MyVisitor(elementFilter) {
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) { override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
if (expression.receiverExpression is KtThisExpression && !options.removeThis) return if (expression.receiverExpression is KtThisExpression && !options.removeThis) return
super.visitDotQualifiedExpression(expression) super.visitDotQualifiedExpression(expression)
} }
}
override fun analyzeQualifiedElement(element: KtDotQualifiedExpression, bindingContext: BindingContext): AnalyzeQualifiedElementResult { override fun analyzeQualifiedElement(element: KtDotQualifiedExpression, bindingContext: BindingContext): AnalyzeQualifiedElementResult {
val receiver = element.receiverExpression val receiver = element.receiverExpression
@@ -456,13 +476,23 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
} }
} }
private class ShortenThisExpressionsVisitor( private class ShortenThisExpressionsProcessor(
file: KtFile, file: KtFile,
elementFilter: (PsiElement) -> FilterResult, elementFilter: (PsiElement) -> FilterResult,
failedToImportDescriptors: Set<DeclarationDescriptor> failedToImportDescriptors: Set<DeclarationDescriptor>
) : ShorteningVisitor<KtThisExpression>(file, elementFilter, failedToImportDescriptors) { ) : ShorteningProcessor<KtThisExpression>(file, failedToImportDescriptors) {
private val simpleThis = KtPsiFactory(file).createExpression("this") as KtThisExpression private val simpleThis = KtPsiFactory(file).createExpression("this") as KtThisExpression
override val collectElementsVisitor: CollectElementsVisitor<KtThisExpression> =
object : CollectElementsVisitor<KtThisExpression>(elementFilter) {
override fun visitThisExpression(expression: KtThisExpression) {
if (options.removeThisLabels && elementFilter(expression) == FilterResult.PROCESS && expression.getTargetLabel() != null) {
addQualifiedElementToAnalyze(expression)
}
}
}
override fun analyzeQualifiedElement(element: KtThisExpression, bindingContext: BindingContext): AnalyzeQualifiedElementResult { override fun analyzeQualifiedElement(element: KtThisExpression, bindingContext: BindingContext): AnalyzeQualifiedElementResult {
val targetBefore = element.instanceReference.targets(bindingContext).singleOrNull() ?: return Skip val targetBefore = element.instanceReference.targets(bindingContext).singleOrNull() ?: return Skip
val scope = element.getResolutionScope(bindingContext, resolutionFacade) val scope = element.getResolutionScope(bindingContext, resolutionFacade)
@@ -471,22 +501,16 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
return if (targetBefore == targetAfter) ShortenNow else Skip return if (targetBefore == targetAfter) ShortenNow else Skip
} }
override fun visitThisExpression(expression: KtThisExpression) {
if (options.removeThisLabels && elementFilter(expression) == FilterResult.PROCESS && expression.getTargetLabel() != null) {
addQualifiedElementToAnalyze(expression)
}
}
override fun shortenElement(element: KtThisExpression): KtElement { override fun shortenElement(element: KtThisExpression): KtElement {
return element.replace(simpleThis) as KtElement return element.replace(simpleThis) as KtElement
} }
} }
private class RemoveExplicitCompanionObjectReferenceVisitor( private class RemoveExplicitCompanionObjectReferenceProcessor(
file: KtFile, file: KtFile,
elementFilter: (PsiElement) -> FilterResult, elementFilter: (PsiElement) -> FilterResult,
failedToImportDescriptors: Set<DeclarationDescriptor> failedToImportDescriptors: Set<DeclarationDescriptor>
) : QualifiedExpressionShorteningVisitor(file, elementFilter, failedToImportDescriptors) { ) : QualifiedExpressionShorteningProcessor(file, elementFilter, failedToImportDescriptors) {
private fun KtExpression.singleTarget(context: BindingContext): DeclarationDescriptor? { private fun KtExpression.singleTarget(context: BindingContext): DeclarationDescriptor? {
return (getCalleeExpressionIfAny() as? KtReferenceExpression)?.targets(context)?.singleOrNull() return (getCalleeExpressionIfAny() as? KtReferenceExpression)?.targets(context)?.singleOrNull()