Code improvements

This commit is contained in:
Valentin Kipyatkov
2015-07-24 22:02:01 +03:00
parent a2b759ef78
commit 29379c061a
4 changed files with 93 additions and 159 deletions
@@ -36,58 +36,38 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.renderer.NameShortness
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import javax.swing.Icon
public class DescriptorClassMember(private val myPsiElement: PsiElement, public val descriptor: DeclarationDescriptor) : MemberChooserObjectBase(DescriptorClassMember.getText(descriptor), DescriptorClassMember.getIcon(myPsiElement, descriptor)), ClassMemberWithElement {
public class DescriptorClassMember(
private val psiElement: PsiElement,
public val descriptor: DeclarationDescriptor
) : MemberChooserObjectBase(DescriptorClassMember.getText(descriptor), DescriptorClassMember.getIcon(psiElement, descriptor)), ClassMemberWithElement {
override fun getParentNodeDelegate(): MemberChooserObject {
val parent = descriptor.containingDeclaration
var declaration: PsiElement?
if (myPsiElement is JetDeclaration) {
// kotlin
declaration = PsiTreeUtil.getStubOrPsiParentOfType(myPsiElement, javaClass<JetNamedDeclaration>())
if (declaration == null) {
declaration = PsiTreeUtil.getStubOrPsiParentOfType(myPsiElement, javaClass<JetFile>())
}
val parent = descriptor.containingDeclaration ?: error("No parent for $descriptor")
val declaration = if (psiElement is JetDeclaration) { // kotlin
PsiTreeUtil.getStubOrPsiParentOfType(psiElement, javaClass<JetNamedDeclaration>())
?: PsiTreeUtil.getStubOrPsiParentOfType(psiElement, javaClass<JetFile>())
}
else {
// java or bytecode
declaration = (myPsiElement as PsiMember).containingClass
else { // java or compiled
(psiElement as PsiMember).containingClass
} ?: error("No parent for $psiElement")
return when (declaration) {
is JetFile -> PsiElementMemberChooserObject(declaration, declaration.name)
else -> DescriptorClassMember(declaration, parent)
}
assert(parent != null) { "$NO_PARENT_FOR$descriptor" }
assert(declaration != null) { "$NO_PARENT_FOR$myPsiElement" }
if (declaration is JetFile) {
return PsiElementMemberChooserObject(declaration, declaration.name)
}
return DescriptorClassMember(declaration!!, parent!!)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
override fun equals(other: Any?) = this === other || other is DescriptorClassMember && descriptor == other.descriptor
val that = other as DescriptorClassMember
override fun hashCode() = descriptor.hashCode()
if (descriptor != that.descriptor) return false
return true
}
override fun hashCode(): Int {
return descriptor.hashCode()
}
override fun getElement(): PsiElement {
return myPsiElement
}
override fun getElement() = psiElement
companion object {
public val NO_PARENT_FOR: String = "No parent for "
private val MEMBER_RENDERER = DescriptorRenderer.withOptions {
withDefinedIn = false
modifiers = emptySet<DescriptorRendererModifier>()
@@ -96,30 +76,29 @@ public class DescriptorClassMember(private val myPsiElement: PsiElement, public
}
private fun getText(descriptor: DeclarationDescriptor): String {
if (descriptor is ClassDescriptor) {
return DescriptorUtils.getFqNameSafe(descriptor).render()
}
else {
return MEMBER_RENDERER.render(descriptor)
}
return if (descriptor is ClassDescriptor)
descriptor.fqNameSafe.render()
else
MEMBER_RENDERER.render(descriptor)
}
private fun getIcon(element: PsiElement, declarationDescriptor: DeclarationDescriptor): Icon {
private fun getIcon(element: PsiElement, descriptor: DeclarationDescriptor): Icon {
if (element.isValid) {
val isClass = element is PsiClass || element is JetClass
val flags = if (isClass) 0 else Iconable.ICON_FLAG_VISIBILITY
if (element is JetDeclaration) {
// kotlin declaration
// visibility and abstraction better detect by a descriptor
return JetDescriptorIconProvider.getIcon(declarationDescriptor, element, flags)
return JetDescriptorIconProvider.getIcon(descriptor, element, flags)
}
else {
// it is better to show java icons for java code
return element.getIcon(flags)
}
}
return JetDescriptorIconProvider.getIcon(declarationDescriptor, element, 0)
else {
return JetDescriptorIconProvider.getIcon(descriptor, element, 0)
}
}
}
}
@@ -20,34 +20,19 @@ import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMethodsHandler
import org.jetbrains.kotlin.resolve.OverrideResolver
public class ImplementMethodsHandler : OverrideImplementMethodsHandler(), IntentionAction {
override fun collectMethodsToGenerate(descriptor: ClassDescriptor): Set<CallableMemberDescriptor> {
return OverrideResolver.getMissingImplementations(descriptor)
}
override fun collectMethodsToGenerate(descriptor: ClassDescriptor) = OverrideResolver.getMissingImplementations(descriptor)
override fun getChooserTitle(): String {
return "Implement Members"
}
override fun getChooserTitle() = "Implement Members"
override fun getNoMethodsFoundHint(): String {
return "No methods to implement have been found"
}
override fun getNoMethodsFoundHint() = "No methods to implement have been found"
override fun getText(): String {
return JetBundle.message("implement.members")
}
override fun getText() = JetBundle.message("implement.members")
override fun getFamilyName() = JetBundle.message("implement.members")
override fun getFamilyName(): String {
return JetBundle.message("implement.members")
}
override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean {
return isValidFor(editor, file)
}
override fun isAvailable(project: Project, editor: Editor, file: PsiFile) = isValidFor(editor, file)
}
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.overrideImplement.DescriptorClassMember
import org.jetbrains.kotlin.idea.quickfix.moveCaretIntoGeneratedElement
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
@@ -43,30 +42,25 @@ import java.util.ArrayList
public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActionHandler {
public fun collectMethodsToGenerate(classOrObject: JetClassOrObject): Set<CallableMemberDescriptor> {
val descriptor = classOrObject.resolveToDescriptor()
if (descriptor is ClassDescriptor) {
return collectMethodsToGenerate(descriptor)
}
return emptySet()
val descriptor = classOrObject.resolveToDescriptor() as? ClassDescriptor ?: return emptySet()
return collectMethodsToGenerate(descriptor)
}
protected abstract fun collectMethodsToGenerate(descriptor: ClassDescriptor): Set<CallableMemberDescriptor>
private fun showOverrideImplementChooser(project: Project, members: Array<DescriptorClassMember>): MemberChooser<DescriptorClassMember>? {
val chooser = MemberChooser(members, true, true, project)
chooser.setTitle(getChooserTitle())
chooser.title = getChooserTitle()
chooser.show()
if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return null
if (chooser.exitCode != DialogWrapper.OK_EXIT_CODE) return null
return chooser
}
protected abstract fun getChooserTitle(): String
override fun isValidFor(editor: Editor, file: PsiFile): Boolean {
if (file !is JetFile) {
return false
}
val elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset())
if (file !is JetFile) return false
val elementAtCaret = file.findElementAt(editor.caretModel.offset)
val classOrObject = elementAtCaret?.getNonStrictParentOfType<JetClassOrObject>()
return classOrObject != null
}
@@ -74,7 +68,7 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
protected abstract fun getNoMethodsFoundHint(): String
public fun invoke(project: Project, editor: Editor, file: PsiFile, implementAll: Boolean) {
val elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset())
val elementAtCaret = file.findElementAt(editor.caretModel.offset)
val classOrObject = elementAtCaret?.getNonStrictParentOfType<JetClassOrObject>()!!
val missingImplementations = collectMethodsToGenerate(classOrObject)
@@ -82,22 +76,17 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
HintManager.getInstance().showErrorHint(editor, getNoMethodsFoundHint())
return
}
val members = membersFromDescriptors(file as JetFile, missingImplementations)
val selectedElements: List<DescriptorClassMember>?
if (implementAll) {
selectedElements = members
val selectedElements: List<DescriptorClassMember> = if (implementAll) {
members
}
else {
val chooser = showOverrideImplementChooser(project, members.toTypedArray())
if (chooser == null) {
return
}
selectedElements = chooser.getSelectedElements()
if (selectedElements == null || selectedElements.isEmpty()) return
val chooser = showOverrideImplementChooser(project, members.toTypedArray()) ?: return
chooser.selectedElements ?: return
}
if (selectedElements.isEmpty()) return
PsiDocumentManager.getInstance(project).commitAllDocuments()
@@ -119,18 +108,17 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES
}
private val LOG = Logger.getInstance(javaClass<OverrideImplementMethodsHandler>().getCanonicalName())
private val LOG = Logger.getInstance(javaClass<OverrideImplementMethodsHandler>().canonicalName)
public fun membersFromDescriptors(file: JetFile, missingImplementations: Iterable<CallableMemberDescriptor>): List<DescriptorClassMember> {
val members = ArrayList<DescriptorClassMember>()
for (memberDescriptor in missingImplementations) {
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.getProject(), memberDescriptor)
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, memberDescriptor)
if (declaration == null) {
LOG.error("Can not find declaration for descriptor " + memberDescriptor)
LOG.error("Can not find declaration for descriptor $memberDescriptor")
}
else {
val member = DescriptorClassMember(declaration, memberDescriptor)
members.add(member)
members.add(DescriptorClassMember(declaration, memberDescriptor))
}
}
return members
@@ -140,9 +128,7 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
runWriteAction {
val body = classOrObject.getOrCreateBody()
var afterAnchor = findInsertAfterAnchor(editor, body)
if (afterAnchor == null) return@runWriteAction
var afterAnchor = findInsertAfterAnchor(editor, body) ?: return@runWriteAction
var firstGenerated: PsiElement? = null
@@ -162,12 +148,12 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
if (firstGenerated == null) return@runWriteAction
val project = classOrObject.getProject()
val project = classOrObject.project
val pointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(firstGenerated)
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument())
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
val element = pointer.getElement()
val element = pointer.element
if (element != null) {
moveCaretIntoGeneratedElement(editor, element)
}
@@ -176,19 +162,18 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
}
private fun findInsertAfterAnchor(editor: Editor, body: JetClassBody): PsiElement? {
val afterAnchor = body.getLBrace()
if (afterAnchor == null) return null
val afterAnchor = body.lBrace ?: return null
val offset = editor.getCaretModel().getOffset()
val offsetCursorElement = PsiTreeUtil.findFirstParent(body.getContainingFile().findElementAt(offset)) {
it.getParent() == body
val offset = editor.caretModel.offset
val offsetCursorElement = PsiTreeUtil.findFirstParent(body.containingFile.findElementAt(offset)) {
it.parent == body
}
if (offsetCursorElement is PsiWhiteSpace) {
return removeAfterOffset(offset, offsetCursorElement)
}
if (offsetCursorElement != null && offsetCursorElement != body.getRBrace()) {
if (offsetCursorElement != null && offsetCursorElement != body.rBrace) {
return offsetCursorElement
}
@@ -196,23 +181,23 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
}
private fun removeAfterOffset(offset: Int, whiteSpace: PsiWhiteSpace): PsiElement {
val spaceNode = whiteSpace.getNode()
if (spaceNode.getTextRange().contains(offset)) {
var beforeWhiteSpaceText = spaceNode.getText().substring(0, offset - spaceNode.getStartOffset())
val spaceNode = whiteSpace.node
if (spaceNode.textRange.contains(offset)) {
var beforeWhiteSpaceText = spaceNode.text.substring(0, offset - spaceNode.startOffset)
if (!StringUtil.containsLineBreak(beforeWhiteSpaceText)) {
// Prevent insertion on same line
beforeWhiteSpaceText += "\n"
}
val factory = JetPsiFactory(whiteSpace.getProject())
val factory = JetPsiFactory(whiteSpace.project)
val insertAfter = whiteSpace.getPrevSibling()
val insertAfter = whiteSpace.prevSibling
whiteSpace.delete()
val beforeSpace = factory.createWhiteSpace(beforeWhiteSpaceText)
insertAfter.getParent().addAfter(beforeSpace, insertAfter)
insertAfter.parent.addAfter(beforeSpace, insertAfter)
return insertAfter.getNextSibling()
return insertAfter.nextSibling
}
return whiteSpace
@@ -234,38 +219,38 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
}
private fun overrideProperty(classOrObject: JetClassOrObject, descriptor: PropertyDescriptor): JetElement {
val newDescriptor = descriptor.copy(descriptor.getContainingDeclaration(), Modality.OPEN, descriptor.getVisibility(),
descriptor.getKind(), /* copyOverrides = */ true) as PropertyDescriptor
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true) as PropertyDescriptor
newDescriptor.addOverriddenDescriptor(descriptor)
val body = StringBuilder()
body.append("\nget()")
body.append(" = ")
body.append(generateUnsupportedOrSuperCall(classOrObject, descriptor))
if (descriptor.isVar()) {
if (descriptor.isVar) {
body.append("\nset(value) {}")
}
return JetPsiFactory(classOrObject.getProject()).createProperty(OVERRIDE_RENDERER.render(newDescriptor) + body)
return JetPsiFactory(classOrObject.project).createProperty(OVERRIDE_RENDERER.render(newDescriptor) + body)
}
private fun overrideFunction(classOrObject: JetClassOrObject, descriptor: FunctionDescriptor): JetNamedFunction {
val newDescriptor = descriptor.copy(descriptor.getContainingDeclaration(), Modality.OPEN, descriptor.getVisibility(),
descriptor.getKind(), /* copyOverrides = */ true)
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true)
newDescriptor.addOverriddenDescriptor(descriptor)
val returnType = descriptor.getReturnType()
val returnType = descriptor.returnType
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
val isAbstract = descriptor.getModality() == Modality.ABSTRACT
val isAbstract = descriptor.modality == Modality.ABSTRACT
val delegation = generateUnsupportedOrSuperCall(classOrObject, descriptor)
val body = "{" + (if (returnsNotUnit && !isAbstract) "return " else "") + delegation + "}"
return JetPsiFactory(classOrObject.getProject()).createFunction(OVERRIDE_RENDERER.render(newDescriptor) + body)
return JetPsiFactory(classOrObject.project).createFunction(OVERRIDE_RENDERER.render(newDescriptor) + body)
}
private fun generateUnsupportedOrSuperCall(classOrObject: JetClassOrObject, descriptor: CallableMemberDescriptor): String {
val isAbstract = descriptor.getModality() == Modality.ABSTRACT
val isAbstract = descriptor.modality == Modality.ABSTRACT
if (isAbstract) {
return "throw UnsupportedOperationException()"
}
@@ -273,14 +258,14 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
val builder = StringBuilder()
builder.append("super")
if (classOrObject.getDelegationSpecifiers().size() > 1) {
builder.append("<").append(descriptor.getContainingDeclaration().escapedName()).append(">")
builder.append("<").append(descriptor.containingDeclaration.escapedName()).append(">")
}
builder.append(".").append(descriptor.escapedName())
if (descriptor is FunctionDescriptor) {
val paramTexts = descriptor.getValueParameters().map {
val paramTexts = descriptor.valueParameters.map {
val renderedName = it.escapedName()
if (it.getVarargElementType() != null) "*$renderedName" else renderedName
if (it.varargElementType != null) "*$renderedName" else renderedName
}
paramTexts.joinTo(builder, prefix="(", postfix=")")
}
@@ -289,6 +274,6 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
}
}
private fun DeclarationDescriptor.escapedName() = getName().render()
private fun DeclarationDescriptor.escapedName() = name.render()
}
}
@@ -23,8 +23,6 @@ import org.jetbrains.kotlin.resolve.OverrideResolver
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized
import java.util.HashSet
import java.util.LinkedHashSet
public class OverrideMethodsHandler : OverrideImplementMethodsHandler() {
override fun collectMethodsToGenerate(descriptor: ClassDescriptor): Set<CallableMemberDescriptor> {
@@ -36,29 +34,20 @@ public class OverrideMethodsHandler : OverrideImplementMethodsHandler() {
}
}
}
val result = HashSet<CallableMemberDescriptor>()
for (superMethod in superMethods) {
if (superMethod.modality.isOverridable) {
if (!isOrOverridesSynthesized(superMethod)) {
result.add(superMethod)
}
}
}
return result
return superMethods
.filter { it.modality.isOverridable && !isOrOverridesSynthesized(it) }
.toSet()
}
private fun collectSuperMethods(classDescriptor: ClassDescriptor): MutableSet<CallableMemberDescriptor> {
val inheritedFunctions = LinkedHashSet<CallableMemberDescriptor>()
for (supertype in classDescriptor.typeConstructor.supertypes) {
for (descriptor in supertype.memberScope.getAllDescriptors()) {
if (descriptor is CallableMemberDescriptor) {
inheritedFunctions.add(descriptor)
}
}
}
val inheritedFunctionsSet = classDescriptor.typeConstructor.supertypes
.flatMap { it.memberScope.getAllDescriptors() }
.filterIsInstance<CallableMemberDescriptor>()
.toSet()
// Only those actually inherited
val filteredMembers = OverrideResolver.filterOutOverridden(inheritedFunctions)
val filteredMembers = OverrideResolver.filterOutOverridden(inheritedFunctionsSet)
// Group members with "the same" signature
val factoredMembers = LinkedHashMultimap.create<CallableMemberDescriptor, CallableMemberDescriptor>()
@@ -76,11 +65,7 @@ public class OverrideMethodsHandler : OverrideImplementMethodsHandler() {
return factoredMembers.keySet()
}
override fun getChooserTitle(): String {
return "Override Members"
}
override fun getChooserTitle() = "Override Members"
override fun getNoMethodsFoundHint(): String {
return "No methods to override have been found"
}
override fun getNoMethodsFoundHint() = "No methods to override have been found"
}