Merge remote-tracking branch 'origin/master'
@@ -17,13 +17,13 @@ package com.intellij.codeInsight.intention
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.lang.LanguageExtension
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.PsiTypeParameter
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.uast.UClass
|
||||
import org.jetbrains.uast.UDeclaration
|
||||
import org.jetbrains.uast.UParameter
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UastContext
|
||||
|
||||
/**
|
||||
* Extension Point provides language-abstracted code modifications for JVM-based languages.
|
||||
@@ -38,18 +38,22 @@ import org.jetbrains.uast.UParameter
|
||||
@ApiStatus.Experimental
|
||||
abstract class JvmCommonIntentionActionsFactory {
|
||||
|
||||
open fun createChangeModifierAction(declaration: UDeclaration,
|
||||
open fun createChangeModifierAction(declaration: @JvmCommon PsiModifierListOwner,
|
||||
@PsiModifier.ModifierConstant modifier: String,
|
||||
shouldPresent: Boolean): IntentionAction? = null
|
||||
shouldPresent: Boolean): IntentionAction? =
|
||||
//Fallback if Uast-version of method is overridden
|
||||
createChangeModifierAction(declaration.asUast<UDeclaration>(), modifier, shouldPresent)
|
||||
|
||||
open fun createAddCallableMemberActions(info: MethodInsertionInfo): List<IntentionAction> = emptyList()
|
||||
|
||||
open fun createAddBeanPropertyActions(uClass: UClass,
|
||||
open fun createAddBeanPropertyActions(psiClass: @JvmCommon PsiClass,
|
||||
propertyName: String,
|
||||
@PsiModifier.ModifierConstant visibilityModifier: String,
|
||||
propertyType: PsiType,
|
||||
setterRequired: Boolean,
|
||||
getterRequired: Boolean): List<IntentionAction> = emptyList()
|
||||
getterRequired: Boolean): List<IntentionAction> =
|
||||
//Fallback if Uast-version of method is overridden
|
||||
createAddBeanPropertyActions(psiClass.asUast<UClass>(), propertyName, visibilityModifier, propertyType, setterRequired, getterRequired)
|
||||
|
||||
companion object : LanguageExtension<JvmCommonIntentionActionsFactory>(
|
||||
"com.intellij.codeInsight.intention.jvmCommonIntentionActionsFactory") {
|
||||
@@ -58,49 +62,78 @@ abstract class JvmCommonIntentionActionsFactory {
|
||||
override fun forLanguage(l: Language): JvmCommonIntentionActionsFactory? = super.forLanguage(l)
|
||||
}
|
||||
|
||||
//A fallback to old api
|
||||
@Deprecated("use or/and override @JvmCommon-version of this method instead")
|
||||
open fun createChangeModifierAction(declaration: UDeclaration,
|
||||
@PsiModifier.ModifierConstant modifier: String,
|
||||
shouldPresent: Boolean): IntentionAction? = null
|
||||
|
||||
@Deprecated("use or/and override @JvmCommon-version of this method instead")
|
||||
open fun createAddBeanPropertyActions(uClass: UClass,
|
||||
propertyName: String,
|
||||
@PsiModifier.ModifierConstant visibilityModifier: String,
|
||||
propertyType: PsiType,
|
||||
setterRequired: Boolean,
|
||||
getterRequired: Boolean): List<IntentionAction> = emptyList()
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
sealed class MethodInsertionInfo(
|
||||
val containingClass: UClass,
|
||||
val targetClass: @JvmCommon PsiClass,
|
||||
@PsiModifier.ModifierConstant
|
||||
val modifiers: List<String> = emptyList(),
|
||||
val typeParams: List<PsiTypeParameter> = emptyList(),
|
||||
val parameters: List<UParameter> = emptyList()
|
||||
val parameters: List<@JvmCommon PsiParameter> = emptyList()
|
||||
) {
|
||||
|
||||
@Deprecated("use `targetClass`", ReplaceWith("targetClass"))
|
||||
val containingClass: UClass
|
||||
get() = targetClass.asUast<UClass>()
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun constructorInfo(containingClass: UClass, parameters: List<UParameter>) =
|
||||
Constructor(containingClass = containingClass, parameters = parameters)
|
||||
fun constructorInfo(targetClass: @JvmCommon PsiClass, parameters: List<@JvmCommon PsiParameter>) =
|
||||
Constructor(targetClass = targetClass, parameters = parameters)
|
||||
|
||||
@JvmStatic
|
||||
fun simpleMethodInfo(containingClass: UClass,
|
||||
fun simpleMethodInfo(containingClass: @JvmCommon PsiClass,
|
||||
methodName: String,
|
||||
@PsiModifier.ModifierConstant modifier: String,
|
||||
returnType: PsiType,
|
||||
parameters: List<UParameter>) =
|
||||
parameters: List<@JvmCommon PsiParameter>) =
|
||||
Method(name = methodName,
|
||||
modifiers = listOf(modifier),
|
||||
containingClass = containingClass,
|
||||
targetClass = containingClass,
|
||||
returnType = returnType,
|
||||
parameters = parameters)
|
||||
|
||||
}
|
||||
|
||||
class Method(
|
||||
containingClass: UClass,
|
||||
targetClass: @JvmCommon PsiClass,
|
||||
val name: String,
|
||||
modifiers: List<String> = emptyList(),
|
||||
typeParams: List<PsiTypeParameter> = emptyList(),
|
||||
typeParams: List<@JvmCommon PsiTypeParameter> = emptyList(),
|
||||
val returnType: PsiType,
|
||||
parameters: List<UParameter> = emptyList(),
|
||||
parameters: List<@JvmCommon PsiParameter> = emptyList(),
|
||||
val isAbstract: Boolean = false
|
||||
) : MethodInsertionInfo(containingClass, modifiers, typeParams, parameters)
|
||||
) : MethodInsertionInfo(targetClass, modifiers, typeParams, parameters)
|
||||
|
||||
class Constructor(
|
||||
containingClass: UClass,
|
||||
targetClass: @JvmCommon PsiClass,
|
||||
modifiers: List<String> = emptyList(),
|
||||
typeParams: List<PsiTypeParameter> = emptyList(),
|
||||
parameters: List<UParameter> = emptyList()
|
||||
) : MethodInsertionInfo(containingClass, modifiers, typeParams, parameters)
|
||||
typeParams: List<@JvmCommon PsiTypeParameter> = emptyList(),
|
||||
parameters: List<@JvmCommon PsiParameter> = emptyList()
|
||||
) : MethodInsertionInfo(targetClass, modifiers, typeParams, parameters)
|
||||
|
||||
}
|
||||
|
||||
@Deprecated("remove after kotlin plugin will be ported")
|
||||
private inline fun <reified T : UElement> PsiElement.asUast(): T = when (this) {
|
||||
is T -> this
|
||||
else -> this.let { ServiceManager.getService(project, UastContext::class.java).convertElement(this, null, T::class.java) as T? }
|
||||
?: throw UnsupportedOperationException("cant convert $this to ${T::class}")
|
||||
}
|
||||
@@ -17,8 +17,8 @@ package com.intellij.codeInspection.inheritance
|
||||
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle
|
||||
import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory
|
||||
import com.intellij.codeInspection.*
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
@@ -185,7 +185,8 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() {
|
||||
shouldPresent: Boolean,
|
||||
actionsList: SmartList<IntentionAction>) {
|
||||
if (declaration.modifierList?.hasModifierProperty(name) != shouldPresent) {
|
||||
(actionsFactory.createChangeModifierAction(declaration, name, shouldPresent))?.let {
|
||||
(actionsFactory.createChangeModifierAction(declaration as @com.intellij.psi.JvmCommon PsiModifierListOwner, name,
|
||||
shouldPresent))?.let {
|
||||
actionsList.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,22 +225,27 @@ public class ParametersFolder {
|
||||
if (isAccessedForWriting((PsiExpression)expression)) {
|
||||
return null;
|
||||
}
|
||||
for (PsiElement scopeElement : scopeElements) {
|
||||
if (PsiTreeUtil.isAncestor(expression, scopeElement, true)) {
|
||||
expression = null;
|
||||
break;
|
||||
}
|
||||
if (isAncestor(expression, scopeElements)) {
|
||||
break;
|
||||
}
|
||||
if (dependsOnLocals(expression, inputVariables)) {
|
||||
break;
|
||||
}
|
||||
final PsiElement parent = expression.getParent();
|
||||
if (parent instanceof PsiExpressionStatement) {
|
||||
break;
|
||||
}
|
||||
if (expression == null) break;
|
||||
|
||||
final PsiType expressionType = ((PsiExpression)expression).getType();
|
||||
if (expressionType != null && !PsiType.VOID.equals(expressionType) && !(expression.getParent() instanceof PsiExpressionStatement)) {
|
||||
if (dependsOnLocals(expression, inputVariables)) {
|
||||
break;
|
||||
}
|
||||
if (expressionType == null || PsiType.VOID.equals(expressionType)) {
|
||||
break;
|
||||
}
|
||||
if (isTooLongExpressionChain(expression)) {
|
||||
break;
|
||||
}
|
||||
if (!isMethodNameExpression(expression)) {
|
||||
expressions.add((PsiExpression)expression);
|
||||
}
|
||||
expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class);
|
||||
expression = parent instanceof PsiExpression ? parent : null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -275,6 +280,47 @@ public class ParametersFolder {
|
||||
return exprWithWriteAccessInside[0] != null;
|
||||
}
|
||||
|
||||
private static boolean isAncestor(PsiElement expression, PsiElement[] scopeElements) {
|
||||
for (PsiElement scopeElement : scopeElements) {
|
||||
if (PsiTreeUtil.isAncestor(expression, scopeElement, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isTooLongExpressionChain(PsiElement expression) {
|
||||
int count = 0;
|
||||
for (PsiElement element = getInnerExpression(expression); element != null; element = getInnerExpression(element)) {
|
||||
count++;
|
||||
if (count > 1) { // expression chains like 'var.foo().bar()' and 'var.foo[i].bar()' are too long
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static PsiElement getInnerExpression(PsiElement expression) {
|
||||
if (expression instanceof PsiMethodCallExpression) {
|
||||
return ((PsiMethodCallExpression)expression).getMethodExpression().getQualifierExpression();
|
||||
}
|
||||
if (expression instanceof PsiArrayAccessExpression) {
|
||||
while (expression instanceof PsiArrayAccessExpression) {
|
||||
expression = ((PsiArrayAccessExpression)expression).getArrayExpression();
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isMethodNameExpression(@NotNull PsiElement expression) {
|
||||
final PsiElement parent = expression.getParent();
|
||||
return expression instanceof PsiReferenceExpression &&
|
||||
parent instanceof PsiMethodCallExpression &&
|
||||
((PsiReferenceExpression)expression).getReferenceNameElement() ==
|
||||
((PsiMethodCallExpression)parent).getMethodExpression().getReferenceNameElement();
|
||||
}
|
||||
|
||||
private static boolean dependsOnLocals(final PsiElement expression, final List<? extends PsiVariable> inputVariables) {
|
||||
final boolean[] localVarsUsed = new boolean[]{false};
|
||||
expression.accept(new JavaRecursiveElementWalkingVisitor(){
|
||||
|
||||
@@ -22,15 +22,13 @@ import com.intellij.codeInspection.LocalQuickFixBase
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.SmartPointerManager
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import com.intellij.util.PsiNavigateUtil
|
||||
import org.jetbrains.uast.UClass
|
||||
import org.jetbrains.uast.UMethod
|
||||
import org.jetbrains.uast.toUElementOfType
|
||||
|
||||
class UastCreateMethodFix(containingClass: UClass, private val createMethodAction: IntentionAction)
|
||||
class CreateMethodFix(containingClass: @JvmCommon PsiClass, private val createMethodAction: IntentionAction)
|
||||
: LocalQuickFixBase(createMethodAction.text, createMethodAction.familyName) {
|
||||
|
||||
private val containingClass = SmartPointerManager.getInstance(containingClass.project).createSmartPsiElementPointer(containingClass)
|
||||
@@ -44,22 +42,27 @@ class UastCreateMethodFix(containingClass: UClass, private val createMethodActio
|
||||
reformatAndOpenCreatedMethod(newMethod)
|
||||
}
|
||||
|
||||
private fun reformatAndOpenCreatedMethod(method: UMethod) {
|
||||
private fun reformatAndOpenCreatedMethod(method: @JvmCommon PsiMethod) {
|
||||
CodeStyleManager.getInstance(containingClass.project).reformat(method)
|
||||
PsiNavigateUtil.navigate(method.uastBody?.psi?.lastChild ?: method)
|
||||
PsiNavigateUtil.navigate((method.body ?: uastBody(method))?.lastChild ?: method)
|
||||
}
|
||||
|
||||
private fun uastBody(method: PsiMethod): PsiElement? = when (method) {
|
||||
is UMethod -> method.uastBody?.psi
|
||||
else -> method.toUElementOfType<UMethod>()?.uastBody?.psi
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createVoidMethodIfFixPossible(uClass: UClass,
|
||||
fun createVoidMethodIfFixPossible(psiClass: @JvmCommon PsiClass,
|
||||
methodName: String,
|
||||
@PsiModifier.ModifierConstant modifier: String): UastCreateMethodFix? {
|
||||
if (!ModuleUtilCore.projectContainsFile(uClass.project, uClass.containingFile.virtualFile, false)) return null
|
||||
val actionsFactory = JvmCommonIntentionActionsFactory.forLanguage(uClass.language) ?: return null
|
||||
@PsiModifier.ModifierConstant modifier: String): CreateMethodFix? {
|
||||
if (!ModuleUtilCore.projectContainsFile(psiClass.project, psiClass.containingFile.virtualFile, false)) return null
|
||||
val actionsFactory = JvmCommonIntentionActionsFactory.forLanguage(psiClass.language) ?: return null
|
||||
val action = actionsFactory.createAddCallableMemberActions(
|
||||
MethodInsertionInfo.simpleMethodInfo(uClass, methodName, modifier, PsiType.VOID, emptyList())
|
||||
MethodInsertionInfo.simpleMethodInfo(psiClass, methodName, modifier, PsiType.VOID, emptyList())
|
||||
).firstOrNull() ?: return null
|
||||
return UastCreateMethodFix(uClass, action)
|
||||
return CreateMethodFix(psiClass, action)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,46 +22,47 @@ import com.intellij.codeInsight.intention.AbstractIntentionAction
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory
|
||||
import com.intellij.codeInsight.intention.MethodInsertionInfo
|
||||
import com.intellij.lang.java.JavaLanguage
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager
|
||||
import com.intellij.psi.impl.beanProperties.CreateJavaBeanPropertyFix
|
||||
import com.intellij.psi.util.PsiFormatUtil
|
||||
import com.intellij.psi.util.PsiFormatUtilBase
|
||||
import com.intellij.util.VisibilityUtil
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.uast.UClass
|
||||
import org.jetbrains.uast.UDeclaration
|
||||
import org.jetbrains.uast.UParameter
|
||||
|
||||
|
||||
class JavaCommonIntentionActionsFactory : JvmCommonIntentionActionsFactory() {
|
||||
|
||||
override fun createChangeModifierAction(declaration: UDeclaration, modifier: String, shouldPresent: Boolean): IntentionAction {
|
||||
override fun createChangeModifierAction(declaration: @JvmCommon PsiModifierListOwner,
|
||||
modifier: String,
|
||||
shouldPresent: Boolean): IntentionAction {
|
||||
return ModifierFix(declaration.modifierList, modifier, shouldPresent, false)
|
||||
}
|
||||
|
||||
override fun createAddCallableMemberActions(info: MethodInsertionInfo): List<IntentionAction> {
|
||||
return when (info) {
|
||||
is MethodInsertionInfo.Method -> with(info) {
|
||||
createAddMethodAction(containingClass, name, modifiers.joinToString(" "), returnType, parameters)
|
||||
createAddMethodAction(targetClass, name, modifiers.joinToString(" "), returnType, parameters)
|
||||
?.let { listOf(it) } ?: emptyList()
|
||||
}
|
||||
|
||||
is MethodInsertionInfo.Constructor ->
|
||||
listOf(AddConstructorFix(info.containingClass.psi, info.parameters.map { it.psi }))
|
||||
listOf(AddConstructorFix(info.targetClass.javaPsi(), info.parameters.map { it.javaPsi() }))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAddMethodAction(uClass: UClass,
|
||||
private fun createAddMethodAction(psiClass: @JvmCommon PsiClass,
|
||||
methodName: String,
|
||||
@PsiModifier.ModifierConstant @NotNull visibilityModifier: String,
|
||||
returnType: PsiType,
|
||||
parameters: List<UParameter>): IntentionAction? {
|
||||
val paramsString = parameters.mapIndexed { i, t -> "${t.type.presentableText} ${t.name ?: "arg$i"}" }.joinToString()
|
||||
parameters: List<@JvmCommon PsiParameter>): IntentionAction? {
|
||||
val paramsString = parameters.mapIndexed { i, t -> "${t.type.canonicalText} ${t.name ?: "arg$i"}" }.joinToString()
|
||||
val signatureString =
|
||||
"${VisibilityUtil.getVisibilityString(visibilityModifier)} ${returnType.presentableText} $methodName($paramsString){}"
|
||||
val targetClassPointer = SmartPointerManager.getInstance(uClass.project).createSmartPsiElementPointer(uClass.psi)
|
||||
"${VisibilityUtil.getVisibilityString(visibilityModifier)} ${returnType.canonicalText} $methodName($paramsString){}"
|
||||
val targetClassPointer = SmartPointerManager.getInstance(psiClass.project).createSmartPsiElementPointer(psiClass.javaPsi())
|
||||
return object : AbstractIntentionAction() {
|
||||
|
||||
private val text = targetClassPointer.element?.let { psiClass ->
|
||||
@@ -77,17 +78,30 @@ class JavaCommonIntentionActionsFactory : JvmCommonIntentionActionsFactory() {
|
||||
override fun getText(): String = text
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: PsiFile) {
|
||||
targetClassPointer.element?.let { targetClass ->
|
||||
targetClass.add(createMethod(targetClass))
|
||||
val targetClass = targetClassPointer.element ?: return
|
||||
runWriteAction {
|
||||
val addedMethod = targetClass.add(createMethod(targetClass))
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(addedMethod)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createMethod(targetClass: PsiClass): PsiMethod = PsiElementFactory.SERVICE.getInstance(targetClass.project)
|
||||
.createMethodFromText(signatureString, targetClass)
|
||||
private fun createMethod(targetClass: PsiClass): PsiMethod {
|
||||
val elementFactory = JVMElementFactories.getFactory(targetClass.language, targetClass.project) // it could be Groovy
|
||||
?: JavaPsiFacade.getElementFactory(targetClass.project)
|
||||
return elementFactory.createMethodFromText(signatureString, targetClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createAddBeanPropertyActions(uClass: UClass,
|
||||
private inline fun <reified T : PsiElement> T.javaPsi(): T {
|
||||
assert(language == JavaLanguage.INSTANCE)
|
||||
return when (this) {
|
||||
is org.jetbrains.uast.UElement -> psi as T
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
override fun createAddBeanPropertyActions(psiClass: @JvmCommon PsiClass,
|
||||
propertyName: String,
|
||||
@PsiModifier.ModifierConstant visibilityModifier: String,
|
||||
propertyType: PsiType,
|
||||
@@ -95,20 +109,20 @@ class JavaCommonIntentionActionsFactory : JvmCommonIntentionActionsFactory() {
|
||||
getterRequired: Boolean): List<IntentionAction> {
|
||||
if (getterRequired && setterRequired)
|
||||
return listOf<IntentionAction>(
|
||||
CreateJavaBeanPropertyFix(uClass.psi, propertyName, propertyType, getterRequired, setterRequired,
|
||||
CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired,
|
||||
true),
|
||||
CreateJavaBeanPropertyFix(uClass.psi, propertyName, propertyType, getterRequired, setterRequired,
|
||||
CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired,
|
||||
false))
|
||||
if (getterRequired || setterRequired)
|
||||
return listOf<IntentionAction>(
|
||||
CreateJavaBeanPropertyFix(uClass.psi, propertyName, propertyType, getterRequired, setterRequired,
|
||||
CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired,
|
||||
true),
|
||||
CreateJavaBeanPropertyFix(uClass.psi, propertyName, propertyType, getterRequired, setterRequired,
|
||||
CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired,
|
||||
false),
|
||||
CreateJavaBeanPropertyFix(uClass.psi, propertyName, propertyType, true, true, true))
|
||||
CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, true, true, true))
|
||||
|
||||
return listOf<IntentionAction>(
|
||||
CreateJavaBeanPropertyFix(uClass.psi, propertyName, propertyType, getterRequired, setterRequired, true))
|
||||
CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired, true))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,8 +25,6 @@ import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UClass;
|
||||
import org.jetbrains.uast.UastContextKt;
|
||||
|
||||
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
|
||||
import static com.intellij.util.ArrayUtil.toObjectArray;
|
||||
@@ -35,14 +33,14 @@ import static com.intellij.util.ArrayUtil.toObjectArray;
|
||||
public class CreateBeanPropertyFixes {
|
||||
|
||||
public static LocalQuickFix[] createFixes(String propertyName,
|
||||
@NotNull PsiClass psiClass,
|
||||
@NotNull @JvmCommon PsiClass psiClass,
|
||||
@Nullable PsiType type,
|
||||
final boolean createSetter) {
|
||||
return IntentionWrapper.wrapToQuickFixes(createActions(propertyName, psiClass, type, createSetter), psiClass.getContainingFile());
|
||||
}
|
||||
|
||||
public static IntentionAction[] createActions(String propertyName,
|
||||
@NotNull PsiClass psiClass,
|
||||
@NotNull @JvmCommon PsiClass psiClass,
|
||||
@Nullable PsiType type,
|
||||
final boolean createSetter) {
|
||||
if (psiClass instanceof PsiCompiledElement) return IntentionAction.EMPTY_ARRAY;
|
||||
@@ -55,9 +53,8 @@ public class CreateBeanPropertyFixes {
|
||||
}
|
||||
JvmCommonIntentionActionsFactory factory = JvmCommonIntentionActionsFactory.forLanguage(psiClass.getLanguage());
|
||||
if (factory == null) return IntentionAction.EMPTY_ARRAY;
|
||||
UClass uClass = UastContextKt.toUElement(psiClass, UClass.class);
|
||||
if (uClass == null) return IntentionAction.EMPTY_ARRAY;
|
||||
return toObjectArray(factory.createAddBeanPropertyActions(uClass, propertyName, PsiModifier.PUBLIC, type, createSetter, !createSetter),
|
||||
IntentionAction.class);
|
||||
return toObjectArray(
|
||||
factory.createAddBeanPropertyActions(psiClass, propertyName, PsiModifier.PUBLIC, type, createSetter, !createSetter),
|
||||
IntentionAction.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,8 +947,9 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
|
||||
RefactoringUtil.fixJavadocsForParams(method, newParameters, pair -> {
|
||||
final PsiParameter parameter = pair.first;
|
||||
final String oldParamName = pair.second;
|
||||
final int idx = ArrayUtil.find(oldParameterNames, oldParamName);
|
||||
return idx >= 0 && idx == method.getParameterList().getParameterIndex(parameter) && changeInfo.getNewParameters()[idx].getOldIndex() == idx;
|
||||
final int oldIdx = ArrayUtil.find(oldParameterNames, oldParamName);
|
||||
int newIndex = method.getParameterList().getParameterIndex(parameter);
|
||||
return oldIdx >= 0 && newIndex >= 0 && changeInfo.getNewParameters()[newIndex].getOldIndex() == oldIdx;
|
||||
}, paramName -> ArrayUtil.find(oldParameterNames, paramName) >= 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.psi;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Annotation for marking {@link PsiElement} subclasses usages that they will be used in
|
||||
* language-abstracted way:
|
||||
* <ul>
|
||||
* <li>No modification methods should be directly called on such instances</li>
|
||||
* <li>Usages should be aware of {@link PsiElement#getLanguage()}, and not be hardcoded to dedicated language</li>
|
||||
* <li>Instances could be "virtual" and don't have physical representations</li>
|
||||
* <li>Complex operations should be performed via corresponding {@link com.intellij.lang.LanguageExtensionPoint} or similar API</li>
|
||||
* <li>{@link org.jetbrains.uast.UClass}-like instances should be supported</li>
|
||||
* </ul>
|
||||
* <b>Note:</b> this annotation considered as kind-of "transitional" until generic language-independent API will be implemented
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({
|
||||
ElementType.TYPE, ElementType.PARAMETER, ElementType.FIELD, ElementType.TYPE_USE, ElementType.TYPE_PARAMETER
|
||||
})
|
||||
public @interface JvmCommon {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class X {
|
||||
|
||||
/**
|
||||
* @param a aparam
|
||||
* @param b bparam
|
||||
*/
|
||||
public void <caret>mymethod(boolean a, boolean b) { }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class X {
|
||||
|
||||
/**
|
||||
* @param a aparam
|
||||
* @param c
|
||||
* @param b1 bparam
|
||||
*/
|
||||
public void mymethod(boolean a, boolean c, boolean b1) { }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
boolean bar(String[][] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
for (int j = 0; i < a[i].length; j++) {<selection>
|
||||
if (a[i][j].length() > 3 && i % 3 == 0)
|
||||
return true;
|
||||
</selection>
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
class Foo {
|
||||
boolean bar(String[][] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
for (int j = 0; i < a[i].length; j++) {
|
||||
if (newMethod(a[i][j], i)) return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean newMethod(String s, int i) {
|
||||
if (s.length() > 3 && i % 3 == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
class UseBuilder {
|
||||
void test(Builder builder, int[] arr) {
|
||||
<selection>builder.foo("xyz").bar(arr[0]).foo("abc");</selection>
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
Builder foo(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder bar(int x) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
class UseBuilder {
|
||||
void test(Builder builder, int[] arr) {
|
||||
<selection>builder.foo("xyz").bar(arr[0])</selection>.foo("abc");
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
Builder foo(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder bar(int x) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
class UseBuilder {
|
||||
void test(Builder builder, int[] arr) {
|
||||
newMethod(builder, arr[0]).foo("abc");
|
||||
}
|
||||
|
||||
private Builder newMethod(Builder builder, int x) {
|
||||
return builder.foo("xyz").bar(x);
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
Builder foo(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder bar(int x) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
boolean bar(String[] a) {
|
||||
for (int i = 0; i < a.length; i++) {<selection>
|
||||
if (a[i].length() > 3 && i % 3 == 0)
|
||||
return true;
|
||||
</selection>}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
class Foo {
|
||||
boolean bar(String[] a) {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (newMethod(a[i], i)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean newMethod(String s, int i) {
|
||||
if (s.length() > 3 && i % 3 == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
class UseBuilder {
|
||||
void test(Builder builder, int[] arr) {
|
||||
newMethod(builder, arr[0]);
|
||||
}
|
||||
|
||||
private void newMethod(Builder builder, int x) {
|
||||
builder.foo("xyz").bar(x).foo("abc");
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
Builder foo(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder bar(int x) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class C {
|
||||
int foo(String[][] vars, int i, int j) {
|
||||
return <selection>vars[i][j].length()</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class C {
|
||||
int foo(String[][] vars, int i, int j) {
|
||||
return newMethod(vars[i][j]);
|
||||
}
|
||||
|
||||
private int newMethod(String s) {
|
||||
return s.length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class C {
|
||||
int foo(String[] vars, int i) {
|
||||
return <selection>vars[i].length()</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class C {
|
||||
int foo(String[] vars, int i) {
|
||||
return newMethod(vars[i]);
|
||||
}
|
||||
|
||||
private int newMethod(String var) {
|
||||
return var.length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class C {
|
||||
String[] vars;
|
||||
int foo(C c, int i) {
|
||||
return <selection>c.vars[i].length()</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
class C {
|
||||
String[] vars;
|
||||
int foo(C c, int i) {
|
||||
return newMethod(c.vars[i]);
|
||||
}
|
||||
|
||||
private int newMethod(String var) {
|
||||
return var.length();
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,11 @@ public class InferencePerformanceTest extends LightDaemonAnalyzerTestCase {
|
||||
@NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/performance";
|
||||
|
||||
public void testPolyMethodCallArgumentPassedToVarargs() throws Exception {
|
||||
PlatformTestUtil.startPerformanceTest("50 poly method calls passed to Arrays.asList", 3500, this::doTest).assertTiming();
|
||||
PlatformTestUtil.startPerformanceTest("50 poly method calls passed to Arrays.asList", 4000, this::doTest).usesAllCPUCores().assertTiming();
|
||||
}
|
||||
|
||||
public void testDiamondConstructorCallPassedToVarargs() throws Exception {
|
||||
PlatformTestUtil.startPerformanceTest("50 diamond constructor calls passed to Arrays.asList", 10000, this::doTest).assertTiming();
|
||||
PlatformTestUtil.startPerformanceTest("50 diamond constructor calls passed to Arrays.asList", 12000, this::doTest).usesAllCPUCores().assertTiming();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
|
||||
@@ -226,6 +226,14 @@ public class ChangeSignatureTest extends ChangeSignatureBaseTest {
|
||||
}, false);
|
||||
}
|
||||
|
||||
public void testParamJavadocRenamedReordered() {
|
||||
doTest(null, new ParameterInfoImpl[]{
|
||||
new ParameterInfoImpl(0, "a", PsiType.BOOLEAN),
|
||||
new ParameterInfoImpl(-1, "c", PsiType.BOOLEAN),
|
||||
new ParameterInfoImpl(1, "b1", PsiType.BOOLEAN),
|
||||
}, false);
|
||||
}
|
||||
|
||||
public void testJavadocNoNewLineInserted() {
|
||||
doTest(null, new ParameterInfoImpl[]{
|
||||
new ParameterInfoImpl(0, "newArgs", PsiType.DOUBLE),
|
||||
|
||||
@@ -974,6 +974,34 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBuilderChainWithArrayAccess() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBuilderChainWithArrayAccessExpr() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBuilderChainWithArrayAccessIf() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBuilderChainWith2DimArrayAccess() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCallOnArrayElement() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCallOn2DimArrayElement() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCallOnFieldArrayElement() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTestDisabledParam() throws PrepareFailedException {
|
||||
final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject());
|
||||
settings.ELSE_ON_NEW_LINE = true;
|
||||
|
||||
@@ -511,7 +511,7 @@ public class PluginManagerCore {
|
||||
@NotNull
|
||||
private static ClassLoader[] getParentLoaders(@NotNull Map<PluginId, ? extends IdeaPluginDescriptor> idToDescriptorMap, @NotNull PluginId[] pluginIds) {
|
||||
if (isUnitTestMode()) return new ClassLoader[0];
|
||||
final List<ClassLoader> classLoaders = new ArrayList<>();
|
||||
LinkedHashSet<ClassLoader> loaders = new LinkedHashSet<>(pluginIds.length);
|
||||
for (final PluginId id : pluginIds) {
|
||||
IdeaPluginDescriptor pluginDescriptor = idToDescriptorMap.get(id);
|
||||
if (pluginDescriptor == null) {
|
||||
@@ -522,9 +522,9 @@ public class PluginManagerCore {
|
||||
if (loader == null) {
|
||||
getLogger().error("Plugin class loader should be initialized for plugin " + id);
|
||||
}
|
||||
classLoaders.add(loader);
|
||||
loaders.add(loader);
|
||||
}
|
||||
return classLoaders.toArray(new ClassLoader[classLoaders.size()]);
|
||||
return loaders.toArray(new ClassLoader[loaders.size()]);
|
||||
}
|
||||
|
||||
private static int countPlugins(@NotNull String pluginsPath) {
|
||||
|
||||
@@ -378,9 +378,9 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
|
||||
lines_inner {
|
||||
("A B_C D" - "A_B C_D")
|
||||
(" -- - " - " -- - ").default()
|
||||
(" -- - " - " -- ").trim()
|
||||
(" - " - " - ").ignore()
|
||||
(" - -- " - " - -- ").default()
|
||||
(" - -- " - " -- ").trim()
|
||||
(" - " - " - ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
|
||||
@@ -593,7 +593,8 @@ class MergeTest : MergeTestBase() {
|
||||
5 ======
|
||||
modify
|
||||
6 ======
|
||||
7 ======""".trimIndent()
|
||||
7 ======
|
||||
8 ======""".trimIndent()
|
||||
val text2 = """
|
||||
1 ======
|
||||
2 ======
|
||||
@@ -604,8 +605,9 @@ class MergeTest : MergeTestBase() {
|
||||
5 ======
|
||||
modify
|
||||
6 ======
|
||||
7 ======
|
||||
delete modify
|
||||
7 ======""".trimIndent()
|
||||
8 ======""".trimIndent()
|
||||
val text3 = """
|
||||
1 ======
|
||||
2 ======
|
||||
@@ -616,8 +618,9 @@ class MergeTest : MergeTestBase() {
|
||||
5 ======
|
||||
modify right
|
||||
6 ======
|
||||
7 ======
|
||||
modify
|
||||
7 ======""".trimIndent()
|
||||
8 ======""".trimIndent()
|
||||
|
||||
testN(text1, text2, text3) {
|
||||
checkUndo(1) {
|
||||
@@ -636,8 +639,9 @@ class MergeTest : MergeTestBase() {
|
||||
5 ======
|
||||
modify right
|
||||
6 ======
|
||||
7 ======
|
||||
delete modify
|
||||
7 ======""".trimIndent())
|
||||
8 ======""".trimIndent())
|
||||
}
|
||||
|
||||
testN(text1, text2, text3) {
|
||||
@@ -658,8 +662,9 @@ class MergeTest : MergeTestBase() {
|
||||
5 ======
|
||||
modify
|
||||
6 ======
|
||||
7 ======
|
||||
delete modify
|
||||
7 ======""".trimIndent())
|
||||
8 ======""".trimIndent())
|
||||
}
|
||||
|
||||
testN(text1, text2, text3) {
|
||||
@@ -678,8 +683,9 @@ class MergeTest : MergeTestBase() {
|
||||
5 ======
|
||||
modify right
|
||||
6 ======
|
||||
7 ======
|
||||
delete modify
|
||||
7 ======""".trimIndent())
|
||||
8 ======""".trimIndent())
|
||||
}
|
||||
|
||||
testN(text1, text2, text3) {
|
||||
@@ -701,8 +707,9 @@ class MergeTest : MergeTestBase() {
|
||||
5 ======
|
||||
modify right
|
||||
6 ======
|
||||
7 ======
|
||||
delete modify
|
||||
7 ======""".trimIndent())
|
||||
8 ======""".trimIndent())
|
||||
}
|
||||
|
||||
testN(text1, text2, text3) {
|
||||
@@ -723,8 +730,9 @@ class MergeTest : MergeTestBase() {
|
||||
5 ======
|
||||
USER modify
|
||||
6 ======
|
||||
7 ======
|
||||
delete modify
|
||||
7 ======""".trimIndent())
|
||||
8 ======""".trimIndent())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package com.intellij.diff.util
|
||||
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.util.containers.StringInterner
|
||||
import com.intellij.util.diff.Diff
|
||||
import com.intellij.util.diff.FilesTooBigForDiffException
|
||||
import junit.framework.TestCase
|
||||
import java.util.*
|
||||
|
||||
@@ -26,7 +28,13 @@ class DiffPerformanceTest : TestCase() {
|
||||
private var needWarmUp = true
|
||||
}
|
||||
|
||||
private val arr_20000 = generateData(20000).toTypedArray()
|
||||
private val interner: StringInterner = StringInterner();
|
||||
|
||||
val data = generateData(2000000)
|
||||
private val arr_200000 = data.take(200000).toTypedArray()
|
||||
private val arr_50000 = data.take(50000).toTypedArray()
|
||||
private val arr_20000 = data.take(20000).toTypedArray()
|
||||
private val arr_5000 = data.take(5000).toTypedArray()
|
||||
private val arr_2000 = arr_20000.take(2000).toTypedArray()
|
||||
private val arr_1000 = arr_20000.take(1000).toTypedArray()
|
||||
private val arr_100 = arr_20000.take(100).toTypedArray()
|
||||
@@ -35,16 +43,22 @@ class DiffPerformanceTest : TestCase() {
|
||||
private val shuffled_1000 = shuffled_2000.take(1000).toTypedArray()
|
||||
private val shuffled_100 = shuffled_2000.take(100).toTypedArray()
|
||||
|
||||
private val altered_200000 = alter(arr_200000)
|
||||
private val altered_50000 = alter(arr_50000)
|
||||
private val altered_20000 = alter(arr_20000)
|
||||
private val altered_2000 = alter(arr_2000)
|
||||
private val altered_1000 = alter(arr_1000)
|
||||
private val altered_100 = alter(arr_100)
|
||||
|
||||
private val heavy_altered_200000 = heavy_alter(arr_200000)
|
||||
private val heavy_altered_50000 = heavy_alter(arr_50000)
|
||||
private val heavy_altered_20000 = heavy_alter(arr_20000)
|
||||
private val heavy_altered_2000 = heavy_alter(arr_2000)
|
||||
private val heavy_altered_1000 = heavy_alter(arr_1000)
|
||||
private val heavy_altered_100 = heavy_alter(arr_100)
|
||||
|
||||
private val reversed_50000 = arr_50000.reversedArray()
|
||||
private val reversed_5000 = arr_5000.reversedArray()
|
||||
private val reversed_2000 = arr_2000.reversedArray()
|
||||
private val reversed_1000 = arr_1000.reversedArray()
|
||||
private val reversed_100 = arr_100.reversedArray()
|
||||
@@ -58,19 +72,61 @@ class DiffPerformanceTest : TestCase() {
|
||||
}
|
||||
|
||||
private fun warmUp() {
|
||||
for (i in 0..20) {
|
||||
Diff.buildChanges(arr_2000, shuffled_2000)
|
||||
for (i in 0..40) {
|
||||
Diff.buildChanges(arr_20000, heavy_altered_20000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test altered 200000`() {
|
||||
testCpu(3, 550) {
|
||||
Diff.buildChanges(arr_200000, altered_200000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test heavy altered 200000`() {
|
||||
testCpu(1, 2900) {
|
||||
Diff.buildChanges(arr_200000, heavy_altered_200000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test reversed 50000 failure`() {
|
||||
testCpu(1, 8000) {
|
||||
try {
|
||||
Diff.buildChanges(arr_50000, reversed_50000)
|
||||
}
|
||||
catch (e: FilesTooBigForDiffException) {
|
||||
return@testCpu
|
||||
}
|
||||
fail("FilesTooBigForDiffException expected")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test reversed 5000`() {
|
||||
testCpu(1, 2000) {
|
||||
Diff.buildChanges(arr_5000, reversed_5000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test altered 50000`() {
|
||||
testCpu(20, 650) {
|
||||
Diff.buildChanges(arr_50000, altered_50000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test heavy altered 50000`() {
|
||||
testCpu(3, 600) {
|
||||
Diff.buildChanges(arr_50000, heavy_altered_50000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test altered 20000`() {
|
||||
testCpu(20, 400) {
|
||||
testCpu(20, 350) {
|
||||
Diff.buildChanges(arr_20000, altered_20000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test heavy altered 20000`() {
|
||||
testCpu(10, 550) {
|
||||
testCpu(15, 600) {
|
||||
Diff.buildChanges(arr_20000, heavy_altered_20000)
|
||||
}
|
||||
}
|
||||
@@ -88,13 +144,13 @@ class DiffPerformanceTest : TestCase() {
|
||||
}
|
||||
|
||||
fun `test shuffled 2000`() {
|
||||
testCpu(1, 700) {
|
||||
testCpu(1, 500) {
|
||||
Diff.buildChanges(arr_2000, shuffled_2000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test reversed 2000`() {
|
||||
testCpu(1, 700) {
|
||||
testCpu(1, 500) {
|
||||
Diff.buildChanges(arr_2000, reversed_2000)
|
||||
}
|
||||
}
|
||||
@@ -112,19 +168,19 @@ class DiffPerformanceTest : TestCase() {
|
||||
}
|
||||
|
||||
fun `test shuffled 1000`() {
|
||||
testCpu(5, 500) {
|
||||
testCpu(10, 750) {
|
||||
Diff.buildChanges(arr_1000, shuffled_1000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test reversed 1000`() {
|
||||
testCpu(5, 550) {
|
||||
testCpu(10, 750) {
|
||||
Diff.buildChanges(arr_1000, reversed_1000)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test altered 100`() {
|
||||
testCpu(10000, 600) {
|
||||
testCpu(10000, 550) {
|
||||
Diff.buildChanges(arr_100, altered_100)
|
||||
}
|
||||
}
|
||||
@@ -142,14 +198,14 @@ class DiffPerformanceTest : TestCase() {
|
||||
}
|
||||
|
||||
fun `test reversed 100`() {
|
||||
testCpu(500, 450) {
|
||||
testCpu(1000, 500) {
|
||||
Diff.buildChanges(arr_100, reversed_100)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun generateData(size: Int): List<String> {
|
||||
return (1..size).map { "${it % 200}" }
|
||||
return (1..size).map { interner.intern("${it % 200}") }
|
||||
}
|
||||
|
||||
private fun alter(arr: Array<String>): Array<String> {
|
||||
@@ -163,7 +219,7 @@ class DiffPerformanceTest : TestCase() {
|
||||
private fun heavy_alter(arr: Array<String>): Array<String> {
|
||||
val altered = arr.copyOf()
|
||||
for (i in 1..altered.lastIndex step 20) {
|
||||
altered[i] = "${i % 200}"
|
||||
altered[i] = interner.intern("${i % 200}")
|
||||
}
|
||||
altered[0] = "===" // avoid "common prefix/suffix" optimisation
|
||||
altered[altered.lastIndex] = "==="
|
||||
|
||||
@@ -48,10 +48,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.*;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.util.ui.UIUtil.DEFAULT_HGAP;
|
||||
@@ -133,29 +130,24 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
private void trackDimensions(@Nullable String dimensionKey) {
|
||||
Window popupWindow = getPopupWindow();
|
||||
if (popupWindow == null) return;
|
||||
popupWindow.addComponentListener(new ComponentAdapter() {
|
||||
ComponentListener windowListener = new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
if (myShown) {
|
||||
processOnSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
popupWindow.addComponentListener(windowListener);
|
||||
addPopupListener(new JBPopupAdapter() {
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
popupWindow.removeComponentListener(this);
|
||||
public void onClosed(LightweightWindowEvent event) {
|
||||
popupWindow.removeComponentListener(windowListener);
|
||||
if (dimensionKey != null && myUserSizeChanged) {
|
||||
WindowStateService.getInstance(myProject).putSizeFor(myProject, dimensionKey, myPrevSize);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (dimensionKey != null) {
|
||||
addPopupListener(new JBPopupAdapter() {
|
||||
@Override
|
||||
public void onClosed(LightweightWindowEvent event) {
|
||||
if (myUserSizeChanged) {
|
||||
WindowStateService.getInstance(myProject).putSizeFor(myProject, dimensionKey, myPrevSize);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void processOnSizeChanged() {
|
||||
|
||||
|
Before Width: | Height: | Size: 136 B After Width: | Height: | Size: 131 B |
|
Before Width: | Height: | Size: 172 B After Width: | Height: | Size: 169 B |
|
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 169 B |
|
Before Width: | Height: | Size: 240 B After Width: | Height: | Size: 252 B |
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 399 B |
|
Before Width: | Height: | Size: 240 B After Width: | Height: | Size: 253 B |
|
Before Width: | Height: | Size: 136 B After Width: | Height: | Size: 131 B |
|
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 247 B |
|
Before Width: | Height: | Size: 357 B After Width: | Height: | Size: 434 B |
|
Before Width: | Height: | Size: 357 B After Width: | Height: | Size: 437 B |
|
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 251 B |
@@ -1327,7 +1327,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
|
||||
|
||||
Component rendererComponent = tree.getCellRenderer()
|
||||
.getTreeCellRendererComponent(tree, node.getUserObject(), tree.getSelectionModel().isPathSelected(path),
|
||||
.getTreeCellRendererComponent(tree, node, tree.getSelectionModel().isPathSelected(path),
|
||||
tree.isExpanded(path), node.isLeaf(), tree.getRowForPath(path), tree.hasFocus());
|
||||
clickInfo.add(new PropertyBean(RENDERER_BOUNDS, tree.getPathBounds(path)));
|
||||
clickInfo.addAll(new InspectorTableModel(rendererComponent).myProperties);
|
||||
|
||||
@@ -186,7 +186,10 @@ public class ApplicationStatisticsPersistenceComponent extends ApplicationStatis
|
||||
JobScheduler.getScheduler().scheduleWithFixedDelay(ApplicationStatisticsPersistenceComponent::persistOpenedProjects, 1, 1, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
private static void persistOpenedProjects() {
|
||||
/**
|
||||
* Collects statistics from all opened projects and persists it
|
||||
*/
|
||||
public static void persistOpenedProjects() {
|
||||
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
|
||||
UsagesCollector.doPersistProjectUsages(project);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.intellij.internal.statistic.tmp;
|
||||
import com.intellij.internal.statistic.StatisticsUploadAssistant;
|
||||
import com.intellij.internal.statistic.connect.StatisticsResult;
|
||||
import com.intellij.internal.statistic.connect.StatisticsService;
|
||||
import com.intellij.internal.statistic.persistence.ApplicationStatisticsPersistenceComponent;
|
||||
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -39,9 +41,14 @@ public class SendStatisticsAction extends AnAction {
|
||||
return;
|
||||
}
|
||||
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Sending Statistics", false) {
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Collecting And Sending Statistics", false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
UsageStatisticsPersistenceComponent statisticsPersistenceComponent = UsageStatisticsPersistenceComponent.getInstance();
|
||||
boolean sendAllowed = statisticsPersistenceComponent.isAllowed();
|
||||
statisticsPersistenceComponent.setAllowed(true);
|
||||
ApplicationStatisticsPersistenceComponent.persistOpenedProjects();
|
||||
statisticsPersistenceComponent.setAllowed(sendAllowed);
|
||||
StatisticsService service = StatisticsUploadAssistant.getStatisticsService();
|
||||
final StatisticsResult result = service.send();
|
||||
|
||||
|
||||
@@ -78,7 +78,9 @@
|
||||
<extensionPoint qualifiedName="com.intellij.ignoredFileProvider"
|
||||
interface="com.intellij.openapi.vcs.changes.IgnoredFileProvider"/>
|
||||
|
||||
<extensionPoint name="openapi.vcs.history.actions.ShowDiffWithLocalAction.ExtensionProvider"
|
||||
<extensionPoint name="openapi.vcs.history.actions.ShowDiffBeforeWithLocalAction.ExtensionProvider"
|
||||
interface="com.intellij.openapi.actionSystem.AnActionExtensionProvider"/>
|
||||
<extensionPoint name="openapi.vcs.history.actions.ShowDiffAfterWithLocalAction.ExtensionProvider"
|
||||
interface="com.intellij.openapi.actionSystem.AnActionExtensionProvider"/>
|
||||
<extensionPoint name="openapi.vcs.changes.actions.CreatePatchFromChangesAction.Dialog.ExtensionProvider"
|
||||
interface="com.intellij.openapi.actionSystem.AnActionExtensionProvider"/>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<diff.actions.ShowDiffAction.ExtensionProvider implementation="com.intellij.openapi.vcs.update.ShowUpdatedDiffActionProvider"/>
|
||||
<diff.actions.ShowDiffAction.ExtensionProvider implementation="com.intellij.openapi.vcs.changes.actions.diff.ShowDiffAction" order="last"/>
|
||||
|
||||
<openapi.vcs.history.actions.ShowDiffWithLocalAction.ExtensionProvider implementation="com.intellij.openapi.vcs.changes.shelf.DiffShelvedChangesWithLocalActionProvider"/>
|
||||
<openapi.vcs.history.actions.ShowDiffAfterWithLocalAction.ExtensionProvider implementation="com.intellij.openapi.vcs.changes.shelf.DiffShelvedChangesWithLocalActionProvider"/>
|
||||
|
||||
<selectInTarget implementation="com.intellij.openapi.vcs.changes.SelectInChangesViewTarget"/>
|
||||
|
||||
|
||||
@@ -788,7 +788,7 @@
|
||||
<separator/>
|
||||
<reference ref="MaintenanceGroup"/>
|
||||
|
||||
<action internal="true" id="SendStatistics" class="com.intellij.internal.statistic.tmp.SendStatisticsAction" text="Send Statistics"/>
|
||||
<action internal="true" id="SendStatistics" class="com.intellij.internal.statistic.tmp.SendStatisticsAction" text="Collect And Send Statistics"/>
|
||||
<add-to-group group-id="ToolsMenu" anchor="last"/>
|
||||
</group>
|
||||
|
||||
|
||||
@@ -24,9 +24,10 @@
|
||||
text="Com_pare with Specified Revision..." popup="true"/>
|
||||
<action id="Vcs.ShowHistoryForBlock" class="com.intellij.openapi.vcs.actions.SelectedBlockHistoryAction"/>
|
||||
<action id="Vcs.GetVersion" class="com.intellij.openapi.vcs.history.actions.GetVersionAction"/>
|
||||
<action id="Vcs.ShowDiffWithLocal" class="com.intellij.openapi.vcs.history.actions.ShowDiffWithLocalAction"
|
||||
text="Compare with Local" description="Compare version from selected revision with current version"
|
||||
icon="AllIcons.Actions.DiffWithCurrent"/>
|
||||
<action id="Vcs.ShowDiffWithLocal.Before" class="com.intellij.openapi.vcs.history.actions.ShowDiffBeforeWithLocalAction"
|
||||
text="Compare Before with Local" description="Compare version before selected revision with current version"/>
|
||||
<action id="Vcs.ShowDiffWithLocal" class="com.intellij.openapi.vcs.history.actions.ShowDiffAfterWithLocalAction"
|
||||
text="Compare After with Local" description="Compare version after selected revision with current version"/>
|
||||
|
||||
<group class="com.intellij.openapi.vcs.actions.VcsActionGroup" id="VcsGroup"/>
|
||||
|
||||
@@ -375,6 +376,7 @@
|
||||
<reference ref="Compare.SameVersion"/>
|
||||
<reference ref="Compare.LastVersion"/>
|
||||
<reference ref="Compare.Specified"/>
|
||||
<reference ref="Vcs.ShowDiffWithLocal.Before"/>
|
||||
<reference ref="Vcs.ShowDiffWithLocal"/>
|
||||
<separator/>
|
||||
<reference ref="Diff.PrevChange"/>
|
||||
|
||||
@@ -300,7 +300,7 @@ public class VfsUtilPerformanceTest extends BareTestFixtureTestCase {
|
||||
})
|
||||
.assertTiming();
|
||||
|
||||
PlatformTestUtil.startPerformanceTest("many files deletions", 10000, () -> {
|
||||
PlatformTestUtil.startPerformanceTest("many files deletions", 11000, () -> {
|
||||
assertEquals(N, events.size());
|
||||
processEvents(events);
|
||||
assertEquals(0, temp.getCachedChildren().size());
|
||||
|
||||
@@ -750,7 +750,7 @@ public class VirtualFilePointerTest extends PlatformTestCase {
|
||||
myVirtualFilePointerManager.create(VfsUtilCore.pathToUrl("/a/b/c/d/" + i), disposable, listener);
|
||||
events.add(new VFileCreateEvent(this, temp, "xxx" + i, false, true));
|
||||
}
|
||||
PlatformTestUtil.startPerformanceTest("vfp update", 5000, () -> {
|
||||
PlatformTestUtil.startPerformanceTest("vfp update", 6000, () -> {
|
||||
for (int i=0; i< 100; i++) {
|
||||
// simulate VFS refresh events since launching the actual refresh is too slow
|
||||
myVirtualFilePointerManager.before(events);
|
||||
|
||||
@@ -558,8 +558,9 @@ diff.verify.iterable.restartRequired=true
|
||||
diff.unimportant.line.char.count=3
|
||||
diff.unimportant.line.char.count.description=Threshold number of non-space characters to mark line as unimportant
|
||||
diff.unimportant.line.char.count.restartRequired=true
|
||||
diff.maximum.changes.array.size=10000000
|
||||
diff.maximum.changes.array.size.restartRequired=true
|
||||
diff.delta.threshold.size=20000
|
||||
diff.delta.threshold.size.description=Do not try to compare files if difference is bigger than given threshold
|
||||
diff.delta.threshold.size.restartRequired=true
|
||||
diff.divider.repainting.disable.blitting=true
|
||||
diff.divider.repainting.disable.blitting.description=Fix painting glitch on scrolling in diff - disable BLIT_SCROLL_MODE to force repainting with RepaintManager
|
||||
diff.merge.resolve.conflict.action.visible=true
|
||||
@@ -1166,3 +1167,4 @@ goto.action.skip.tophits.and.options.description=Skip top hits and options in go
|
||||
dsm.show.cycle.count.in.tooltip=false
|
||||
dsm.show.cycle.count.in.tooltip.description=Shows number of cycles found in the tooltip of the Toggle Cycles toolbar button after some calculation time
|
||||
jdk.regex.soe.workaround=true
|
||||
jdk.regex.soe.workaround.description=In regular expression pattern replace choice \\n|. with . (and DOT_ALL option) to prevent stack overflow during matching
|
||||
|
||||
@@ -111,8 +111,8 @@ public class Diff {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
IntLCS intLCS = new IntLCS(discarded[0], discarded[1]);
|
||||
intLCS.execute();
|
||||
MyersLCS intLCS = new MyersLCS(discarded[0], discarded[1]);
|
||||
intLCS.executeWithThreshold();
|
||||
changes = intLCS.getChanges();
|
||||
}
|
||||
catch (FilesTooBigForDiffException e) {
|
||||
|
||||
@@ -8,8 +8,7 @@ import com.intellij.openapi.util.registry.Registry;
|
||||
* Time: 10:30 PM
|
||||
*/
|
||||
public class FilesTooBigForDiffException extends Exception {
|
||||
// Limit for memory consumption in IntLCS algorithm. ~ 2000 changed lines, 50Mb memory
|
||||
public static final int MAX_BUFFER_LEN = Registry.intValue("diff.maximum.changes.array.size");
|
||||
public static final int DELTA_THRESHOLD_SIZE = Registry.intValue("diff.delta.threshold.size");
|
||||
// Do not try to compare two lines by-word after this much fails.
|
||||
public static final int MAX_BAD_LINES = 3;
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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 com.intellij.util.diff;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
|
||||
/**
|
||||
* @author dyoma
|
||||
*/
|
||||
class IntLCS {
|
||||
private final int[] myFirst;
|
||||
private final int[] mySecond;
|
||||
|
||||
private final int myStart1;
|
||||
private final int myStart2;
|
||||
|
||||
private final LinkedDiffPaths myPathsMatrix;
|
||||
private final int[] myPrevPathKey;
|
||||
private int[] myPrevEnds;
|
||||
private int[] myCurrentEnds;
|
||||
private final int myMaxX;
|
||||
private final int myMaxY;
|
||||
|
||||
private final BitSet myChanges1;
|
||||
private final BitSet myChanges2;
|
||||
|
||||
public IntLCS(int[] first, int[] second) {
|
||||
this(first, second, 0, first.length, 0, second.length, new BitSet(first.length), new BitSet(second.length));
|
||||
}
|
||||
|
||||
public IntLCS(int[] first, int[] second, int start1, int count1, int start2, int count2, BitSet changes1, BitSet changes2) {
|
||||
myFirst = first;
|
||||
mySecond = second;
|
||||
myStart1 = start1;
|
||||
myStart2 = start2;
|
||||
myMaxX = count1;
|
||||
myMaxY = count2;
|
||||
|
||||
myChanges1 = changes1;
|
||||
myChanges2 = changes2;
|
||||
|
||||
myPathsMatrix = new LinkedDiffPaths(myMaxX, myMaxY);
|
||||
myPrevPathKey = new int[myMaxX + myMaxY + 1];
|
||||
Arrays.fill(myPrevPathKey, -1);
|
||||
myPrevEnds = new int[myMaxX + myMaxY + 1];
|
||||
myCurrentEnds = new int[myMaxX + myMaxY + 1];
|
||||
}
|
||||
|
||||
public int execute() throws FilesTooBigForDiffException {
|
||||
for (int d =0; d <= myMaxX + myMaxY; d++) {
|
||||
int minDiag = -calcBound(myMaxY, d);
|
||||
int maxDiag = calcBound(myMaxX, d);
|
||||
if (d != 0)
|
||||
System.arraycopy(myPrevEnds, minDiag + myMaxY, myCurrentEnds, minDiag + myMaxY, maxDiag - minDiag);
|
||||
else {
|
||||
int end = skipEquals(0, 0);
|
||||
if (end > 0) {
|
||||
int xy = (end) - 1;
|
||||
myPrevPathKey[myMaxY] = myPathsMatrix.encodeStep(xy, xy, end, false, -1);
|
||||
}
|
||||
if (myMaxX == myMaxY && end == myMaxX) return 0;
|
||||
myPrevEnds[myMaxY] = end;
|
||||
continue;
|
||||
}
|
||||
for (int k = minDiag; k <= maxDiag; k += 2) {
|
||||
int end;
|
||||
if (k == -d) {
|
||||
int prevEndV = myPrevEnds[k + 1 + myMaxY];
|
||||
int vertical = findDiagonalEnd(k + 1, prevEndV, true);
|
||||
end = encodeStep(prevEndV, vertical, k, true);
|
||||
} else if (k == d) {
|
||||
int prevEndH = myPrevEnds[k - 1 + myMaxY];
|
||||
int horisontal = findDiagonalEnd(k - 1, prevEndH, false);
|
||||
end = encodeStep(prevEndH, horisontal, k, false);
|
||||
} else {
|
||||
int prevEndH = myPrevEnds[k - 1 + myMaxY];
|
||||
int prevEndV = myPrevEnds[k + 1 + myMaxY];
|
||||
if (prevEndH+1 > prevEndV) {
|
||||
int horisontal = findDiagonalEnd(k - 1, prevEndH, false);
|
||||
end = encodeStep(prevEndH, horisontal, k, false);
|
||||
} else {
|
||||
int vertical = findDiagonalEnd(k + 1, prevEndV, true);
|
||||
end = encodeStep(prevEndV, vertical, k, true);
|
||||
}
|
||||
}
|
||||
myCurrentEnds[k + myMaxY] = end;
|
||||
if (k == myMaxX - myMaxY && end == myMaxX) {
|
||||
myPathsMatrix.applyChanges(myStart1, myStart2, myChanges1, myChanges2);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
int[] temps = myCurrentEnds;
|
||||
myCurrentEnds = myPrevEnds;
|
||||
myPrevEnds = temps;
|
||||
}
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
public BitSet[] getChanges() {
|
||||
return new BitSet[]{myChanges1, myChanges2};
|
||||
}
|
||||
|
||||
private int findDiagonalEnd(int prevDiagonal, int prevEnd, boolean isVertical) {
|
||||
int x = prevEnd;
|
||||
int y = x - prevDiagonal;
|
||||
if (isVertical) y++;
|
||||
else x++;
|
||||
return skipEquals(x, y);
|
||||
}
|
||||
|
||||
private int encodeStep(int prevEnd, int diagLength, int tDiagonal, boolean afterVertical) throws FilesTooBigForDiffException {
|
||||
int end = prevEnd + diagLength;
|
||||
int prevDiagonal = tDiagonal + myMaxY;
|
||||
if (!afterVertical) end++;
|
||||
if (afterVertical) prevDiagonal++;
|
||||
else prevDiagonal--;
|
||||
int x = end - 1;
|
||||
int y = x - tDiagonal;
|
||||
if (x == -1 || y == -1 || x >= myMaxX || y >= myMaxY) return end;
|
||||
myPrevPathKey[tDiagonal + myMaxY] = myPathsMatrix.encodeStep(x, y, diagLength, afterVertical, myPrevPathKey[prevDiagonal]);
|
||||
return end;
|
||||
}
|
||||
|
||||
private int calcBound(int bound, int d) {
|
||||
return (d <= bound) ? d : 2 * bound - d;
|
||||
}
|
||||
|
||||
private int skipEquals(int x, int y) {
|
||||
int skipped = 0;
|
||||
while (x < myMaxX && y < myMaxY && myFirst[myStart1 + x] == mySecond[myStart2 + y]) {
|
||||
skipped += 1;
|
||||
x++;
|
||||
y++;
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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 com.intellij.util.diff;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
/**
|
||||
* @author dyoma
|
||||
*/
|
||||
final class LinkedDiffPaths {
|
||||
|
||||
private int[] mySteps = new int[10];
|
||||
private int[] myPrevSteps = new int[10];
|
||||
private int myPosition = 0;
|
||||
private final int myMaxX;
|
||||
private final int myMaxY;
|
||||
private int myCornerIndex = -1;
|
||||
private static final int VERTICAL_DIRECTION_FLAG = 1 << 31;
|
||||
private static final int DISTANCE_MASK = ~VERTICAL_DIRECTION_FLAG;
|
||||
|
||||
public LinkedDiffPaths(int maxX, int maxY) {
|
||||
myMaxX = maxX;
|
||||
myMaxY = maxY;
|
||||
}
|
||||
|
||||
public void applyChanges(final int start1, final int start2, final BitSet changes1, final BitSet changes2) {
|
||||
decodePath(new LCSBuilder() {
|
||||
int x = myMaxX;
|
||||
int y = myMaxY;
|
||||
|
||||
@Override
|
||||
public void addEqual(int length) {
|
||||
x -= length;
|
||||
y -= length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChange(int first, int second) {
|
||||
if (first > 0) {
|
||||
changes1.set(start1 + x - first, start1 + x);
|
||||
x -= first;
|
||||
}
|
||||
if (second > 0) {
|
||||
changes2.set(start2 + y - second, start2 + y);
|
||||
y -= second;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Path is decoded in reverse order (from the last change to the first)
|
||||
*/
|
||||
public <Builder extends LCSBuilder> Builder decodePath(Builder builder) {
|
||||
Decoder decoder = new Decoder(getXSize(), getYSize(), builder);
|
||||
int index = myCornerIndex;
|
||||
while (index != -1) {
|
||||
int encodedStep = mySteps[index];
|
||||
decoder.decode(encodedStep);
|
||||
index = myPrevSteps[index];
|
||||
}
|
||||
decoder.beforeFinish();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public int getXSize() {
|
||||
return myMaxX;
|
||||
}
|
||||
|
||||
public int getYSize() {
|
||||
return myMaxY;
|
||||
}
|
||||
|
||||
public int encodeStep(int x, int y, int diagLength, boolean afterVertical, int prevIndex) throws FilesTooBigForDiffException {
|
||||
int encodedPath = diagLength;
|
||||
if (afterVertical) encodedPath |= VERTICAL_DIRECTION_FLAG;
|
||||
int position = incPosition();
|
||||
|
||||
myPrevSteps[position] = prevIndex;
|
||||
mySteps[position] = encodedPath;
|
||||
if (x == myMaxX - 1 && y == myMaxY - 1) myCornerIndex = position;
|
||||
return position;
|
||||
}
|
||||
|
||||
private int incPosition() throws FilesTooBigForDiffException {
|
||||
int length = myPrevSteps.length;
|
||||
if (myPosition == length - 1) {
|
||||
myPrevSteps = copy(length, myPrevSteps);
|
||||
mySteps = copy(length, mySteps);
|
||||
}
|
||||
myPosition++;
|
||||
return myPosition;
|
||||
}
|
||||
|
||||
private int[] copy(int length, int[] prevArray) throws FilesTooBigForDiffException {
|
||||
if (length * 2 >= FilesTooBigForDiffException.MAX_BUFFER_LEN) {
|
||||
throw new FilesTooBigForDiffException(FilesTooBigForDiffException.MAX_BUFFER_LEN);
|
||||
}
|
||||
int[] array = new int[length * 2];
|
||||
System.arraycopy(prevArray, 0, array, 0, length);
|
||||
return array;
|
||||
}
|
||||
|
||||
class Decoder {
|
||||
private final LCSBuilder builder;
|
||||
private int x;
|
||||
private int y;
|
||||
private int dx = 0;
|
||||
private int dy = 0;
|
||||
|
||||
public Decoder(int x, int y, LCSBuilder builder) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void decode(int encodedStep) {
|
||||
int diagDist = encodedStep & DISTANCE_MASK;
|
||||
if (diagDist != 0) {
|
||||
if (dx != 0 || dy != 0) {
|
||||
builder.addChange(dx, dy);
|
||||
dx = 0;
|
||||
dy = 0;
|
||||
}
|
||||
builder.addEqual(diagDist);
|
||||
}
|
||||
x -= diagDist;
|
||||
y -= diagDist;
|
||||
boolean verticalStep = (encodedStep & VERTICAL_DIRECTION_FLAG) != 0;
|
||||
if (verticalStep) {
|
||||
y--;
|
||||
dy++;
|
||||
} else {
|
||||
x--;
|
||||
dx++;
|
||||
}
|
||||
}
|
||||
|
||||
public void beforeFinish() {
|
||||
dx += x;
|
||||
dy += y;
|
||||
if (dx != 0 || dy != 0) builder.addChange(dx, dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.util.diff;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
/**
|
||||
* Algorithm for finding the longest common subsequence of two strings
|
||||
* Based on E.W. Myers / An O(ND) Difference Algorithm and Its Variations / 1986
|
||||
* O(ND) runtime, O(N) memory
|
||||
* <p/>
|
||||
* Created by Anton Bannykh
|
||||
*/
|
||||
class MyersLCS {
|
||||
private final int[] myFirst;
|
||||
private final int[] mySecond;
|
||||
|
||||
private final int myStart1;
|
||||
private final int myStart2;
|
||||
private final int myCount1;
|
||||
private final int myCount2;
|
||||
|
||||
private final BitSet myChanges1;
|
||||
private final BitSet myChanges2;
|
||||
|
||||
private final int[] VForward;
|
||||
private final int[] VBackward;
|
||||
|
||||
public MyersLCS(int[] first, int[] second) {
|
||||
this(first, second, 0, first.length, 0, second.length, new BitSet(first.length), new BitSet(second.length));
|
||||
}
|
||||
|
||||
public MyersLCS(int[] first, int[] second, int start1, int count1, int start2, int count2, BitSet changes1, BitSet changes2) {
|
||||
myFirst = first;
|
||||
mySecond = second;
|
||||
myStart1 = start1;
|
||||
myStart2 = start2;
|
||||
myCount1 = count1;
|
||||
myCount2 = count2;
|
||||
|
||||
myChanges1 = changes1;
|
||||
myChanges2 = changes2;
|
||||
|
||||
myChanges1.set(myStart1, myStart1 + myCount1);
|
||||
myChanges2.set(myStart2, myStart2 + myCount2);
|
||||
|
||||
final int totalSequenceLength = myCount1 + myCount2;
|
||||
VForward = new int[totalSequenceLength + 1];
|
||||
VBackward = new int[totalSequenceLength + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs O(ND) Myers algorithm where D is bound by A + B * sqrt(N)
|
||||
* <p/>
|
||||
* Under certains assumptions about the distribution of the elements of the sequences the expected
|
||||
* running time of the myers algorithm is O(N + D^2). Thus under given constraints it reduces to O(N).
|
||||
*/
|
||||
public void executeLinear() {
|
||||
try {
|
||||
int threshold = 20000 + 10 * (int)Math.sqrt(myCount1 + myCount2);
|
||||
execute(threshold, false);
|
||||
}
|
||||
catch (FilesTooBigForDiffException e) {
|
||||
throw new IllegalStateException(e); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
try {
|
||||
execute(myCount1 + myCount2, false);
|
||||
}
|
||||
catch (FilesTooBigForDiffException e) {
|
||||
throw new IllegalStateException(e); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
public void executeWithThreshold() throws FilesTooBigForDiffException {
|
||||
int threshold = Math.max(20000 + 10 * (int)Math.sqrt(myCount1 + myCount2),
|
||||
FilesTooBigForDiffException.DELTA_THRESHOLD_SIZE);
|
||||
execute(threshold, true);
|
||||
}
|
||||
|
||||
private void execute(int threshold, boolean throwException) throws FilesTooBigForDiffException {
|
||||
if (myCount1 == 0 || myCount2 == 0) return;
|
||||
execute(0, myCount1, 0, myCount2, Math.min(threshold, myCount1 + myCount2), throwException);
|
||||
}
|
||||
|
||||
//LCS( old[oldStart, oldEnd), new[newStart, newEnd) )
|
||||
private void execute(int oldStart, int oldEnd, int newStart, int newEnd, int differenceEstimate,
|
||||
boolean throwException) throws FilesTooBigForDiffException {
|
||||
assert oldStart <= oldEnd && newStart <= newEnd;
|
||||
if (oldStart < oldEnd && newStart < newEnd) {
|
||||
final int oldLength = oldEnd - oldStart;
|
||||
final int newLength = newEnd - newStart;
|
||||
VForward[newLength + 1] = 0;
|
||||
VBackward[newLength + 1] = 0;
|
||||
final int halfD = (differenceEstimate + 1) / 2;
|
||||
int xx, kk, td;
|
||||
xx = kk = td = -1;
|
||||
|
||||
loop:
|
||||
for (int d = 0; d <= halfD; ++d) {
|
||||
final int L = newLength + Math.max(-d, -newLength + ((d ^ newLength) & 1));
|
||||
final int R = newLength + Math.min(d, oldLength - ((d ^ oldLength) & 1));
|
||||
for (int k = L; k <= R; k += 2) {
|
||||
int x = k == L || k != R && VForward[k - 1] < VForward[k + 1] ? VForward[k + 1] : VForward[k - 1] + 1;
|
||||
int y = x - k + newLength;
|
||||
x += commonSubsequenceLengthForward(oldStart + x, newStart + y,
|
||||
Math.min(oldEnd - oldStart - x, newEnd - newStart - y));
|
||||
VForward[k] = x;
|
||||
}
|
||||
|
||||
if ((oldLength - newLength) % 2 != 0) {
|
||||
for (int k = L; k <= R; k += 2) {
|
||||
if (oldLength - (d - 1) <= k && k <= oldLength + (d - 1)) {
|
||||
if (VForward[k] + VBackward[newLength + oldLength - k] >= oldLength) {
|
||||
xx = VForward[k];
|
||||
kk = k;
|
||||
td = 2 * d - 1;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = L; k <= R; k += 2) {
|
||||
int x = k == L || k != R && VBackward[k - 1] < VBackward[k + 1] ? VBackward[k + 1] : VBackward[k - 1] + 1;
|
||||
int y = x - k + newLength;
|
||||
x += commonSubsequenceLengthBackward(oldEnd - 1 - x, newEnd - 1 - y,
|
||||
Math.min(oldEnd - oldStart - x, newEnd - newStart - y));
|
||||
VBackward[k] = x;
|
||||
}
|
||||
|
||||
if ((oldLength - newLength) % 2 == 0) {
|
||||
for (int k = L; k <= R; k += 2) {
|
||||
if (oldLength - d <= k && k <= oldLength + d) {
|
||||
if (VForward[oldLength + newLength - k] + VBackward[k] >= oldLength) {
|
||||
xx = oldLength - VBackward[k];
|
||||
kk = oldLength + newLength - k;
|
||||
td = 2 * d;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (td > 1) {
|
||||
final int yy = xx - kk + newLength;
|
||||
final int oldDiff = (td + 1) / 2;
|
||||
if (0 < xx && 0 < yy) execute(oldStart, oldStart + xx, newStart, newStart + yy, oldDiff, throwException);
|
||||
if (oldStart + xx < oldEnd && newStart + yy < newEnd) execute(oldStart + xx, oldEnd, newStart + yy, newEnd, td - oldDiff, throwException);
|
||||
}
|
||||
else if (td >= 0) {
|
||||
int x = oldStart;
|
||||
int y = newStart;
|
||||
while (x < oldEnd && y < newEnd) {
|
||||
final int commonLength = commonSubsequenceLengthForward(x, y, Math.min(oldEnd - x, newEnd - y));
|
||||
if (commonLength > 0) {
|
||||
addUnchanged(x, y, commonLength);
|
||||
x += commonLength;
|
||||
y += commonLength;
|
||||
}
|
||||
else if (oldEnd - oldStart > newEnd - newStart) {
|
||||
++x;
|
||||
}
|
||||
else {
|
||||
++y;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//The difference is more than the given estimate
|
||||
if (throwException) throw new FilesTooBigForDiffException(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addUnchanged(int start1, int start2, int count) {
|
||||
myChanges1.set(myStart1 + start1, myStart1 + start1 + count, false);
|
||||
myChanges2.set(myStart2 + start2, myStart2 + start2 + count, false);
|
||||
}
|
||||
|
||||
private int commonSubsequenceLengthForward(int oldIndex, int newIndex, int maxLength) {
|
||||
int x = oldIndex;
|
||||
int y = newIndex;
|
||||
|
||||
maxLength = Math.min(maxLength, Math.min(myCount1 - oldIndex, myCount2 - newIndex));
|
||||
while (x - oldIndex < maxLength && myFirst[myStart1 + x] == mySecond[myStart2 + y]) {
|
||||
++x;
|
||||
++y;
|
||||
}
|
||||
return x - oldIndex;
|
||||
}
|
||||
|
||||
private int commonSubsequenceLengthBackward(int oldIndex, int newIndex, int maxLength) {
|
||||
int x = oldIndex;
|
||||
int y = newIndex;
|
||||
|
||||
maxLength = Math.min(maxLength, Math.min(oldIndex, newIndex) + 1);
|
||||
while (oldIndex - x < maxLength && myFirst[myStart1 + x] == mySecond[myStart2 + y]) {
|
||||
--x;
|
||||
--y;
|
||||
}
|
||||
return oldIndex - x;
|
||||
}
|
||||
|
||||
public BitSet[] getChanges() {
|
||||
return new BitSet[]{myChanges1, myChanges2};
|
||||
}
|
||||
}
|
||||
@@ -86,8 +86,8 @@ class PatienceIntLCS {
|
||||
|
||||
if (matching == null) {
|
||||
if (thresholdCheckCounter >= 0) checkReduction(count1, count2);
|
||||
IntLCS intLCS = new IntLCS(myFirst, mySecond, start1, count1, start2, count2, myChanges1, myChanges2);
|
||||
intLCS.execute();
|
||||
MyersLCS intLCS = new MyersLCS(myFirst, mySecond, start1, count1, start2, count2, myChanges1, myChanges2);
|
||||
intLCS.executeLinear();
|
||||
}
|
||||
else {
|
||||
int s1, s2, c1, c2;
|
||||
|
||||
@@ -76,7 +76,10 @@ public class ClassPath {
|
||||
push(urls);
|
||||
}
|
||||
|
||||
/** @deprecated to be removed in IDEA 15 */
|
||||
/**
|
||||
* @deprecated Adding additional urls to classpath at runtime could lead to hard-to-debug errors
|
||||
*/
|
||||
@Deprecated
|
||||
void addURL(URL url) {
|
||||
push(Collections.singletonList(url));
|
||||
}
|
||||
@@ -269,8 +272,21 @@ public class ClassPath {
|
||||
if (myCanUseCache && myAllUrlsWereProcessed) {
|
||||
loaders = new SmartList<Loader>();
|
||||
myCache.iterateLoaders(name, ourLoaderCollector, loaders, this);
|
||||
if (!name.endsWith("/")) {
|
||||
myCache.iterateLoaders(name.concat("/"), ourLoaderCollector, loaders, this);
|
||||
|
||||
if (!name.endsWith("/")) { // avoid loader duplicates when we are requesting nondirectory name
|
||||
boolean nameIsDirectory = name.endsWith("/");
|
||||
Collection<Loader> loadersSet = nameIsDirectory ? new SmartList<Loader>() : new LinkedHashSet<Loader>();
|
||||
myCache.iterateLoaders(name, ourLoaderCollector, loadersSet, this);
|
||||
|
||||
if (!nameIsDirectory) {
|
||||
myCache.iterateLoaders(name.concat("/"), ourLoaderCollector, loadersSet, this);
|
||||
}
|
||||
|
||||
if (nameIsDirectory) {
|
||||
loaders = (List<Loader>)loadersSet;
|
||||
} else {
|
||||
loaders = new ArrayList<Loader>(loadersSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,9 +357,9 @@ public class ClassPath {
|
||||
}
|
||||
}
|
||||
|
||||
private static class LoaderCollector extends ClasspathCache.LoaderIterator<Object, List<Loader>, Object> {
|
||||
private static class LoaderCollector extends ClasspathCache.LoaderIterator<Object, Collection<Loader>, Object> {
|
||||
@Override
|
||||
Object process(Loader loader, List<Loader> parameter, Object parameter2) {
|
||||
Object process(Loader loader, Collection<Loader> parameter, Object parameter2) {
|
||||
parameter.add(loader);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -19,12 +19,11 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.reference.SoftReference;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.jar.Attributes;
|
||||
@@ -131,7 +130,7 @@ class JarLoader extends Loader {
|
||||
try {
|
||||
ZipEntry entry = zipFile.getEntry(name);
|
||||
if (entry != null) {
|
||||
return MemoryResource.load(getBaseURL(), zipFile, entry, myAttributes);
|
||||
return new MyResource(getBaseURL(), entry);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -144,6 +143,49 @@ class JarLoader extends Loader {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class MyResource extends Resource {
|
||||
private final URL myUrl;
|
||||
private final ZipEntry myEntry;
|
||||
|
||||
public MyResource(URL url, ZipEntry entry) throws IOException {
|
||||
myUrl = new URL(url, entry.getName());
|
||||
myEntry = entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getURL() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() throws IOException {
|
||||
byte[] result = ArrayUtil.EMPTY_BYTE_ARRAY;
|
||||
try {
|
||||
ZipFile file = getZipFile();
|
||||
try {
|
||||
result = FileUtil.loadBytes(file.getInputStream(myEntry), (int)myEntry.getSize());
|
||||
} finally {
|
||||
releaseZipFile(file);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
error("file: " + myCanonicalFile, e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(Attribute key) {
|
||||
return myAttributes != null ? myAttributes.get(key) : null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void error(String message, Throwable t) {
|
||||
Logger.getInstance(JarLoader.class).error(message, t);
|
||||
|
||||
@@ -195,8 +195,12 @@ public class UrlClassLoader extends ClassLoader {
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated to be removed in IDEA 15 */
|
||||
/**
|
||||
* @deprecated Adding additional urls to classloader at runtime could lead to hard-to-debug errors
|
||||
* <b>Note:</b> Used via reflection because of classLoaders incompatibility
|
||||
*/
|
||||
@SuppressWarnings({"unused", "deprecation"})
|
||||
@Deprecated
|
||||
public void addURL(URL url) {
|
||||
getClassPath().addURL(url);
|
||||
myURLs.add(url);
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.util.diff;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Random;
|
||||
|
||||
public class IntLCSAutoTest extends TestCase {
|
||||
private final Random RNG = new Random();
|
||||
|
||||
private static final int ITERATIONS = 1000;
|
||||
private static final int MAX_LENGTH = 300;
|
||||
private static final int CHAR_COUNT = 20;
|
||||
|
||||
private enum Type {MyersLCS, PatienceLCS}
|
||||
|
||||
public void testMyersLCS() throws Exception {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
doTestLCS(MAX_LENGTH, CHAR_COUNT, Type.MyersLCS);
|
||||
}
|
||||
}
|
||||
|
||||
public void testPatienceLCS() throws Exception {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
doTestLCS(MAX_LENGTH, CHAR_COUNT, Type.PatienceLCS);
|
||||
}
|
||||
}
|
||||
|
||||
private void doTestLCS(int maxLength, int charCount, @NotNull Type type) throws FilesTooBigForDiffException {
|
||||
int[] sequence1 = generateSequence(maxLength, charCount);
|
||||
int[] sequence2 = generateSequence(maxLength, charCount);
|
||||
|
||||
int start1 = RNG.nextInt(sequence1.length);
|
||||
int start2 = RNG.nextInt(sequence2.length);
|
||||
int count1 = RNG.nextInt(sequence1.length - start1);
|
||||
int count2 = RNG.nextInt(sequence2.length - start2);
|
||||
|
||||
BitSet changes1 = new BitSet(sequence1.length);
|
||||
BitSet changes2 = new BitSet(sequence2.length);
|
||||
|
||||
switch (type) {
|
||||
case MyersLCS:
|
||||
MyersLCS myersLCS = new MyersLCS(sequence1, sequence2, start1, count1, start2, count2, changes1, changes2);
|
||||
myersLCS.execute();
|
||||
break;
|
||||
case PatienceLCS:
|
||||
PatienceIntLCS patienceLCS = new PatienceIntLCS(sequence1, sequence2, start1, count1, start2, count2, changes1, changes2);
|
||||
patienceLCS.execute();
|
||||
break;
|
||||
}
|
||||
|
||||
verifyLCS(sequence1, sequence2, start1, count1, start2, count2, changes1, changes2);
|
||||
}
|
||||
|
||||
public static void verifyLCS(@NotNull int[] sequence1, @NotNull int[] sequence2,
|
||||
@NotNull BitSet changes1, @NotNull BitSet changes2) {
|
||||
verifyLCS(sequence1, sequence2, 0, sequence1.length, 0, sequence2.length, changes1, changes2);
|
||||
}
|
||||
|
||||
private static void verifyLCS(@NotNull int[] sequence1, @NotNull int[] sequence2,
|
||||
int start1, int count1, int start2, int count2,
|
||||
@NotNull BitSet changes1, @NotNull BitSet changes2) {
|
||||
int index1 = changes1.nextClearBit(start1);
|
||||
int index2 = changes2.nextClearBit(start2);
|
||||
|
||||
while (index1 < start1 + count1 || index2 < start2 + count2) {
|
||||
assertTrue(index1 < start1 + count1);
|
||||
assertTrue(index2 < start2 + count2);
|
||||
|
||||
assertEquals(sequence1[index1], sequence2[index2]);
|
||||
|
||||
index1 = changes1.nextClearBit(index1 + 1);
|
||||
index2 = changes2.nextClearBit(index2 + 1);
|
||||
}
|
||||
assertTrue(index1 >= start1 + count1 && index2 >= start2 + count2);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private int[] generateSequence(int maxLength, int charCount) {
|
||||
int[] result = new int[RNG.nextInt(maxLength / 2) + maxLength / 2];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = RNG.nextInt(charCount);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -71,9 +71,9 @@ public class IntLCSNewTest extends TestCase {
|
||||
}
|
||||
|
||||
private static BitSet[] buildChange(int[] first, int[] second) throws FilesTooBigForDiffException {
|
||||
IntLCS intLCS = new IntLCS(first, second);
|
||||
intLCS.execute();
|
||||
return intLCS.getChanges();
|
||||
MyersLCS myersLCS = new MyersLCS(first, second);
|
||||
myersLCS.execute();
|
||||
return myersLCS.getChanges();
|
||||
}
|
||||
|
||||
private static void checkChange(BitSet[] change, int[] expected1, int[] expected2) {
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.intellij.util.diff;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
/**
|
||||
* @author dyoma
|
||||
*/
|
||||
@@ -48,7 +50,7 @@ public class IntLCSTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testOneTail() throws FilesTooBigForDiffException {
|
||||
assertEquals(1, new IntLCS(new int[]{1, 2}, new int[]{1, 2, 3}).execute());
|
||||
assertEquals(1, countChanges(new int[]{1, 2}, new int[]{1, 2, 3}));
|
||||
}
|
||||
|
||||
public void testSingleMiddle() throws FilesTooBigForDiffException {
|
||||
@@ -58,13 +60,14 @@ public class IntLCSTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testAbsolutelyDifferent() throws FilesTooBigForDiffException {
|
||||
assertEquals(4, new IntLCS(new int[]{1, 2}, new int[]{3, 4}).execute());
|
||||
assertEquals(6, new IntLCS(new int[]{1, 2, 3}, new int[]{4, 5, 6}).execute());
|
||||
assertEquals(4, countChanges(new int[]{1, 2}, new int[]{3, 4}));
|
||||
assertEquals(6, countChanges(new int[]{1, 2, 3}, new int[]{4, 5, 6}));
|
||||
}
|
||||
|
||||
private Diff.Change buildChange(int[] first, int[] second, int expectedNonDiags) throws FilesTooBigForDiffException {
|
||||
IntLCS intLCS = new IntLCS(first, second);
|
||||
assertEquals(expectedNonDiags, intLCS.execute());
|
||||
private static Diff.Change buildChange(int[] first, int[] second, int expectedNonDiags) throws FilesTooBigForDiffException {
|
||||
assertEquals(expectedNonDiags, countChanges(first, second));
|
||||
MyersLCS intLCS = new MyersLCS(first, second);
|
||||
intLCS.execute();
|
||||
Reindexer reindexer = new Reindexer();
|
||||
reindexer.idInit(first.length, second.length);
|
||||
Diff.ChangeBuilder builder = new Diff.ChangeBuilder(0);
|
||||
@@ -85,4 +88,11 @@ public class IntLCSTest extends TestCase {
|
||||
checkChange(change, line0, line1, inserted, deleted);
|
||||
assertNull("Expected last change", change.link);
|
||||
}
|
||||
|
||||
private static int countChanges(int[] first, int[] second) throws FilesTooBigForDiffException {
|
||||
MyersLCS lcs = new MyersLCS(first, second);
|
||||
lcs.execute();
|
||||
BitSet[] changes = lcs.getChanges();
|
||||
return changes[0].cardinality() + changes[1].cardinality();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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 com.intellij.util.diff;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
/**
|
||||
* @author dyoma
|
||||
*/
|
||||
public class LinkedDiffPathsTest extends TestCase {
|
||||
protected LinkedDiffPaths createPaths(int maxX, int maxY) {
|
||||
return new LinkedDiffPaths(maxX, maxY);
|
||||
}
|
||||
|
||||
public void testOneDeleteAtferEnd() throws FilesTooBigForDiffException {
|
||||
LinkedDiffPaths paths = createPaths(2, 3);
|
||||
int key = paths.encodeStep(1, 1, 2, false, -1);
|
||||
paths.encodeStep(1, 2, 0, true, key);
|
||||
Diff.Change change = decode(paths);
|
||||
IntLCSTest.checkLastChange(change, 2, 2, 1, 0);
|
||||
}
|
||||
|
||||
public void testOneInsertedAtBegging() throws FilesTooBigForDiffException {
|
||||
LinkedDiffPaths paths = createPaths(3, 2);
|
||||
paths.encodeStep(2, 1, 2, false, -1);
|
||||
Diff.Change change = decode(paths);
|
||||
IntLCSTest.checkLastChange(change, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
public void testSingleMiddleChange() throws FilesTooBigForDiffException {
|
||||
LinkedDiffPaths paths = createPaths(3, 3);
|
||||
int key = paths.encodeStep(0, 0, 1, true, -1);
|
||||
key = paths.encodeStep(1, 0, 0, false, key);
|
||||
paths.encodeStep(2, 2, 1, true, key);
|
||||
IntLCSTest.checkLastChange(decode(paths), 1, 1, 1, 1);
|
||||
}
|
||||
|
||||
public void testSingleChangeAtEnd() throws FilesTooBigForDiffException {
|
||||
LinkedDiffPaths paths = createPaths(2, 2);
|
||||
int key = paths.encodeStep(0, 0, 1, false, -1);
|
||||
key = paths.encodeStep(0, 1, 0, true, key);
|
||||
paths.encodeStep(1, 1, 0, false, key);
|
||||
IntLCSTest.checkLastChange(decode(paths), 1, 1, 1, 1);
|
||||
}
|
||||
|
||||
public void testNotSquareChangeAtEnd() throws FilesTooBigForDiffException {
|
||||
LinkedDiffPaths paths = createPaths(2, 3);
|
||||
int key = paths.encodeStep(0, 0, 1, false, -1);
|
||||
key = paths.encodeStep(0, 1, 0, true, key);
|
||||
key = paths.encodeStep(0, 2, 0, true, key);
|
||||
paths.encodeStep(1, 2, 0, false, key);
|
||||
IntLCSTest.checkLastChange(decode(paths), 1, 1, 2, 1);
|
||||
}
|
||||
|
||||
private Diff.Change decode(LinkedDiffPaths paths) {
|
||||
BitSet[] changes = new BitSet[]{new BitSet(), new BitSet()};
|
||||
paths.applyChanges(0, 0, changes[0], changes[1]);
|
||||
Reindexer reindexer = new Reindexer();
|
||||
reindexer.idInit(paths.getXSize(), paths.getYSize());
|
||||
Diff.ChangeBuilder builder = new Diff.ChangeBuilder(0);
|
||||
reindexer.reindex(changes, builder);
|
||||
return builder.getFirstChange();
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class ReindexerNewTest extends TestCase {
|
||||
}
|
||||
|
||||
public static void checkCase(int[] ints1, int[] ints2) throws FilesTooBigForDiffException {
|
||||
checkCase(ints1, ints2, null);
|
||||
checkCase(ints1, ints2, "");
|
||||
}
|
||||
|
||||
public static void checkCase(int[] ints1, int[] ints2, String message) throws FilesTooBigForDiffException {
|
||||
@@ -102,24 +102,12 @@ public class ReindexerNewTest extends TestCase {
|
||||
}
|
||||
};
|
||||
|
||||
IntLCS lcs = new IntLCS(ints1, ints2);
|
||||
lcs.execute();
|
||||
BitSet[] expectedChanges = lcs.getChanges();
|
||||
|
||||
Reindexer reindexer = new Reindexer();
|
||||
int[][] discarded = reindexer.discardUnique(ints1, ints2);
|
||||
lcs = new IntLCS(discarded[0], discarded[1]);
|
||||
MyersLCS lcs = new MyersLCS(discarded[0], discarded[1]);
|
||||
lcs.execute();
|
||||
BitSet[] changes = lcs.getChanges();
|
||||
reindexer.reindex(changes, builder);
|
||||
reindexer.reindex(lcs.getChanges(), builder);
|
||||
|
||||
if (message != null) {
|
||||
assertEquals(message, expectedChanges[0], reindexChanges[0]);
|
||||
assertEquals(message, expectedChanges[1], reindexChanges[1]);
|
||||
}
|
||||
else {
|
||||
assertEquals(expectedChanges[0], reindexChanges[0]);
|
||||
assertEquals(expectedChanges[1], reindexChanges[1]);
|
||||
}
|
||||
IntLCSAutoTest.verifyLCS(ints1, ints2, reindexChanges[0], reindexChanges[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.vcs.changes.actions;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
@@ -24,6 +25,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.committed.CommittedChangesBrowserUseCase;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -32,12 +34,17 @@ import java.util.List;
|
||||
|
||||
import static com.intellij.openapi.vcs.changes.actions.diff.ShowDiffAction.showDiffForChange;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class ShowDiffWithLocalAction extends AnAction implements DumbAware {
|
||||
private final boolean myBeforeWithLocal;
|
||||
|
||||
public ShowDiffWithLocalAction() {
|
||||
ActionUtil.copyFrom(this, "Vcs.ShowDiffWithLocal");
|
||||
this(false);
|
||||
getTemplatePresentation().setIcon(AllIcons.Actions.DiffWithCurrent);
|
||||
}
|
||||
|
||||
public ShowDiffWithLocalAction(boolean beforeWithLocal) {
|
||||
myBeforeWithLocal = beforeWithLocal;
|
||||
ActionUtil.copyFrom(this, beforeWithLocal ? "Vcs.ShowDiffWithLocal.Before" : "Vcs.ShowDiffWithLocal");
|
||||
}
|
||||
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
@@ -49,9 +56,9 @@ public class ShowDiffWithLocalAction extends AnAction implements DumbAware {
|
||||
List<Change> changesToLocal = new ArrayList<>();
|
||||
for (int i = 0; i < selection.getChanges().size(); i++) {
|
||||
if (i == selection.getIndex()) index = changesToLocal.size();
|
||||
ContentRevision afterRevision = selection.getChanges().get(i).getAfterRevision();
|
||||
if (afterRevision != null && isValidAfterRevision(afterRevision)) {
|
||||
changesToLocal.add(new Change(afterRevision, getCurrentRevision(afterRevision, e)));
|
||||
Change change = getChangeWithLocal(selection.getChanges().get(i));
|
||||
if (change != null) {
|
||||
changesToLocal.add(change);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,29 +67,30 @@ public class ShowDiffWithLocalAction extends AnAction implements DumbAware {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected ContentRevision getCurrentRevision(@NotNull ContentRevision afterRevision, @NotNull AnActionEvent e) {
|
||||
return CurrentContentRevision.create(afterRevision.getFile());
|
||||
}
|
||||
|
||||
public void update(final AnActionEvent e) {
|
||||
Project project = e.getData(CommonDataKeys.PROJECT);
|
||||
ChangesSelection selection = e.getData(VcsDataKeys.CHANGES_SELECTION);
|
||||
boolean isInAir = CommittedChangesBrowserUseCase.IN_AIR.equals(CommittedChangesBrowserUseCase.DATA_KEY.getData(e.getDataContext()));
|
||||
boolean isToolbar = "ChangesBrowser".equals(e.getPlace());
|
||||
|
||||
e.getPresentation().setEnabled(project != null && selection != null && !isInAir && anyHasAfterRevision(selection.getChanges()));
|
||||
e.getPresentation().setEnabled(project != null && !isToolbar && selection != null && !isInAir && canShowDiff(selection.getChanges()));
|
||||
e.getPresentation().setVisible(!isToolbar);
|
||||
}
|
||||
|
||||
private static boolean isValidAfterRevision(@Nullable final ContentRevision afterRevision) {
|
||||
return afterRevision != null && !afterRevision.getFile().isNonLocal() && !afterRevision.getFile().isDirectory();
|
||||
@Nullable
|
||||
private Change getChangeWithLocal(@NotNull Change c) {
|
||||
ContentRevision revision = myBeforeWithLocal ? c.getBeforeRevision() : c.getAfterRevision();
|
||||
if (!isValidRevision(revision)) return null;
|
||||
|
||||
ContentRevision contentRevision = CurrentContentRevision.create(revision.getFile());
|
||||
return new Change(revision, contentRevision);
|
||||
}
|
||||
|
||||
private static boolean anyHasAfterRevision(@NotNull final List<Change> changes) {
|
||||
for (Change c : changes) {
|
||||
if (isValidAfterRevision(c.getAfterRevision())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
private boolean canShowDiff(@NotNull List<Change> changes) {
|
||||
return ContainerUtil.exists(changes, c -> getChangeWithLocal(c) != null);
|
||||
}
|
||||
|
||||
private static boolean isValidRevision(@Nullable ContentRevision revision) {
|
||||
return revision != null && !revision.getFile().isNonLocal() && !revision.getFile().isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,9 @@ public class RepositoryChangesBrowser extends ChangesBrowser implements DataProv
|
||||
protected void buildToolBar(final DefaultActionGroup toolBarGroup) {
|
||||
super.buildToolBar(toolBarGroup);
|
||||
|
||||
toolBarGroup.add(new ShowDiffWithLocalAction());
|
||||
toolBarGroup.add(new ShowDiffWithLocalAction(true));
|
||||
toolBarGroup.add(new ShowDiffWithLocalAction(false));
|
||||
|
||||
myEditSourceAction = new MyEditSourceAction();
|
||||
myEditSourceAction.registerCustomShortcutSet(CommonShortcuts.getEditSource(), this);
|
||||
toolBarGroup.add(myEditSourceAction);
|
||||
|
||||
@@ -408,7 +408,9 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton impleme
|
||||
diffAction.registerCustomShortcutSet(CommonShortcuts.getDiff(), null);
|
||||
result.add(diffAction);
|
||||
|
||||
result.add(ActionManager.getInstance().getAction("Vcs.ShowDiffWithLocal"));
|
||||
if (popup) {
|
||||
result.add(ActionManager.getInstance().getAction("Vcs.ShowDiffWithLocal"));
|
||||
}
|
||||
|
||||
final AnAction diffGroup = ActionManager.getInstance().getAction(VCS_HISTORY_ACTIONS_GROUP);
|
||||
if (diffGroup != null) result.add(diffGroup);
|
||||
|
||||
@@ -30,11 +30,11 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ShowDiffWithLocalAction extends ExtendableAction implements DumbAware {
|
||||
public class ShowDiffAfterWithLocalAction extends ExtendableAction implements DumbAware {
|
||||
private static final ExtensionPointName<AnActionExtensionProvider> EP_NAME =
|
||||
ExtensionPointName.create("com.intellij.openapi.vcs.history.actions.ShowDiffWithLocalAction.ExtensionProvider");
|
||||
ExtensionPointName.create("com.intellij.openapi.vcs.history.actions.ShowDiffAfterWithLocalAction.ExtensionProvider");
|
||||
|
||||
public ShowDiffWithLocalAction() {
|
||||
public ShowDiffAfterWithLocalAction() {
|
||||
super(EP_NAME);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.openapi.vcs.history.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.AnActionExtensionProvider;
|
||||
import com.intellij.openapi.actionSystem.ExtendableAction;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ShowDiffBeforeWithLocalAction extends ExtendableAction implements DumbAware {
|
||||
private static final ExtensionPointName<AnActionExtensionProvider> EP_NAME =
|
||||
ExtensionPointName.create("com.intellij.openapi.vcs.history.actions.ShowDiffBeforeWithLocalAction.ExtensionProvider");
|
||||
|
||||
public ShowDiffBeforeWithLocalAction() {
|
||||
super(EP_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultActionPerformed(@NotNull AnActionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultUpdate(@NotNull AnActionEvent e) {
|
||||
e.getPresentation().setEnabledAndVisible(false);
|
||||
}
|
||||
}
|
||||
@@ -208,7 +208,7 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi
|
||||
|
||||
final DefaultActionGroup popupActions = new DefaultActionGroup();
|
||||
popupActions.add(new MyDiffAction());
|
||||
popupActions.add(new MyDiffLocalAction());
|
||||
popupActions.add(new MyDiffAfterWithLocalAction());
|
||||
popupActions.add(ShowAllAffectedGenericAction.getInstance());
|
||||
popupActions.add(ActionManager.getInstance().getAction(VcsActions.ACTION_COPY_REVISION_NUMBER));
|
||||
PopupHandler.installPopupHandler(myList, popupActions, ActionPlaces.UPDATE_POPUP, ActionManager.getInstance());
|
||||
@@ -496,8 +496,8 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi
|
||||
}
|
||||
}
|
||||
|
||||
private class MyDiffLocalAction extends DumbAwareAction {
|
||||
public MyDiffLocalAction() {
|
||||
private class MyDiffAfterWithLocalAction extends DumbAwareAction {
|
||||
public MyDiffAfterWithLocalAction() {
|
||||
ActionUtil.copyFrom(this, "Vcs.ShowDiffWithLocal");
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
<getDataRule key="Vcs.FileHistory.Ui" implementationClass="com.intellij.vcs.log.history.FileHistoryUiDataRule"/>
|
||||
|
||||
<diff.actions.ShowDiffAction.ExtensionProvider implementation="com.intellij.vcs.log.ui.actions.history.CompareRevisionsFromHistoryActionProvider"/>
|
||||
<openapi.vcs.history.actions.ShowDiffWithLocalAction.ExtensionProvider implementation="com.intellij.vcs.log.ui.actions.history.ShowDiffWithLocalFromHistoryActionProvider"/>
|
||||
<openapi.vcs.history.actions.ShowDiffBeforeWithLocalAction.ExtensionProvider implementation="com.intellij.vcs.log.ui.actions.history.ShowDiffBeforeWithLocalFromHistoryActionProvider"/>
|
||||
<openapi.vcs.history.actions.ShowDiffAfterWithLocalAction.ExtensionProvider implementation="com.intellij.vcs.log.ui.actions.history.ShowDiffAfterWithLocalFromHistoryActionProvider"/>
|
||||
<openapi.vcs.changes.actions.CreatePatchFromChangesAction.Dialog.ExtensionProvider implementation="com.intellij.vcs.log.ui.actions.history.CreatePatchFromHistoryActionProvider$Dialog"/>
|
||||
<openapi.vcs.changes.actions.CreatePatchFromChangesAction.Clipboard.ExtensionProvider implementation="com.intellij.vcs.log.ui.actions.history.CreatePatchFromHistoryActionProvider$Clipboard"/>
|
||||
</extensions>
|
||||
@@ -122,6 +123,7 @@
|
||||
<group id="Vcs.FileHistory.ContextMenu">
|
||||
<reference id="Vcs.Log.OpenRepositoryVersion"/>
|
||||
<reference id="Diff.ShowDiff"/>
|
||||
<reference id="Vcs.ShowDiffWithLocal.Before"/>
|
||||
<reference id="Vcs.ShowDiffWithLocal"/>
|
||||
<reference id="ChangesView.CreatePatchFromChanges"/>
|
||||
<reference id="Vcs.Log.GetVersion"/>
|
||||
@@ -132,7 +134,6 @@
|
||||
</group>
|
||||
<group id="Vcs.FileHistory.Toolbar">
|
||||
<reference id="Diff.ShowDiff"/>
|
||||
<reference id="Vcs.ShowDiffWithLocal"/>
|
||||
<reference id="ChangesView.CreatePatchFromChanges"/>
|
||||
<reference id="Vcs.Log.GetVersion"/>
|
||||
<reference id="Vcs.Log.AnnotateRevisionAction"/>
|
||||
@@ -176,6 +177,7 @@
|
||||
<group id="Log.FileHistory.KeymapGroup" popup="false">
|
||||
<reference id="Vcs.Log.OpenRepositoryVersion"/>
|
||||
<reference id="Diff.ShowDiff"/>
|
||||
<reference id="Vcs.ShowDiffWithLocal.Before"/>
|
||||
<reference id="Vcs.ShowDiffWithLocal"/>
|
||||
<reference id="ChangesView.CreatePatchFromChanges"/>
|
||||
<reference id="Vcs.Log.GetVersion"/>
|
||||
|
||||
@@ -129,7 +129,7 @@ public class FileHistoryUi extends AbstractVcsLogUi {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FilePath getPath(@NotNull VcsFullCommitDetails details) {
|
||||
public FilePath getAfterPath(@NotNull VcsFullCommitDetails details) {
|
||||
if (myPath.isDirectory()) return myPath;
|
||||
|
||||
List<Change> changes = collectRelevantChanges(details);
|
||||
@@ -143,6 +143,21 @@ public class FileHistoryUi extends AbstractVcsLogUi {
|
||||
return null;// file was deleted
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FilePath getBeforePath(@NotNull VcsFullCommitDetails details) {
|
||||
if (myPath.isDirectory()) return myPath;
|
||||
|
||||
List<Change> changes = collectRelevantChanges(details);
|
||||
for (Change change : changes) {
|
||||
ContentRevision revision = change.getBeforeRevision();
|
||||
if (revision != null) {
|
||||
return revision.getFile();
|
||||
}
|
||||
}
|
||||
|
||||
return null;// file was created
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Change> collectRelevantChanges(@NotNull VcsFullCommitDetails details) {
|
||||
Set<FilePath> fileNames = getFileNames(details);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.vcs.log.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
@@ -49,6 +50,7 @@ import java.util.List;
|
||||
* Delegates to the VcsLogManager.
|
||||
*/
|
||||
public class VcsLogContentProvider implements ChangesViewContentProvider {
|
||||
private static final Logger LOG = Logger.getInstance(VcsLogContentProvider.class);
|
||||
public static final String TAB_NAME = "Log";
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
@@ -167,6 +169,7 @@ public class VcsLogContentProvider implements ChangesViewContentProvider {
|
||||
for (String tabName : logManager.getTabNames()) {
|
||||
if (!TAB_NAME.equals(tabName)) { // main tab is closed by the ChangesViewContentManager
|
||||
Content content = toolWindow.getContentManager().findContent(tabName);
|
||||
LOG.assertTrue(content != null, "Could not find content for tab " + tabName);
|
||||
ContentsUtil.closeContentTab(toolWindow.getContentManager(), content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,8 +113,8 @@ public class CompareRevisionsFromHistoryActionProvider implements AnActionExtens
|
||||
// so that it could return a single file path for each revision
|
||||
VcsFullCommitDetails newestDetail = details.get(0);
|
||||
VcsFullCommitDetails olderDetail = details.get(1);
|
||||
notNull(handler).showDiff(olderDetail.getRoot(), ui.getPath(olderDetail), olderDetail.getId(),
|
||||
ui.getPath(newestDetail), newestDetail.getId());
|
||||
notNull(handler).showDiff(olderDetail.getRoot(), ui.getAfterPath(olderDetail), olderDetail.getId(),
|
||||
ui.getAfterPath(newestDetail), newestDetail.getId());
|
||||
}
|
||||
else if (details.size() == 1) {
|
||||
VcsFullCommitDetails detail = notNull(ContainerUtil.getFirstItem(details));
|
||||
|
||||
@@ -28,19 +28,12 @@ import com.intellij.vcs.log.ui.VcsLogInternalDataKeys;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ShowDiffWithLocalFromHistoryActionProvider extends FileHistorySingleCommitAction implements AnActionExtensionProvider {
|
||||
public class ShowDiffAfterWithLocalFromHistoryActionProvider extends FileHistorySingleCommitAction implements AnActionExtensionProvider {
|
||||
@Override
|
||||
public boolean isActive(@NotNull AnActionEvent e) {
|
||||
return e.getData(VcsLogInternalDataKeys.FILE_HISTORY_UI) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
super.update(e);
|
||||
|
||||
e.getPresentation().setDescription("Compare selected revision with the local version of the file");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled(@NotNull FileHistoryUi ui, @Nullable VcsFullCommitDetails detail, @NotNull AnActionEvent e) {
|
||||
FilePath filePath = e.getData(VcsDataKeys.FILE_PATH);
|
||||
@@ -59,6 +52,6 @@ public class ShowDiffWithLocalFromHistoryActionProvider extends FileHistorySingl
|
||||
FilePath path = e.getRequiredData(VcsDataKeys.FILE_PATH);
|
||||
VcsLogDiffHandler handler = e.getRequiredData(VcsLogInternalDataKeys.LOG_DIFF_HANDLER);
|
||||
|
||||
handler.showDiffWithLocal(detail.getRoot(), ui.getPath(detail), detail.getId(), path);
|
||||
handler.showDiffWithLocal(detail.getRoot(), ui.getAfterPath(detail), detail.getId(), path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.vcs.log.ui.actions.history;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.AnActionExtensionProvider;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.vcs.log.VcsFullCommitDetails;
|
||||
import com.intellij.vcs.log.VcsLogDiffHandler;
|
||||
import com.intellij.vcs.log.history.FileHistoryUi;
|
||||
import com.intellij.vcs.log.ui.VcsLogInternalDataKeys;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ShowDiffBeforeWithLocalFromHistoryActionProvider extends FileHistorySingleCommitAction implements AnActionExtensionProvider {
|
||||
@Override
|
||||
public boolean isActive(@NotNull AnActionEvent e) {
|
||||
return e.getData(VcsLogInternalDataKeys.FILE_HISTORY_UI) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled(@NotNull FileHistoryUi ui, @Nullable VcsFullCommitDetails detail, @NotNull AnActionEvent e) {
|
||||
FilePath filePath = e.getData(VcsDataKeys.FILE_PATH);
|
||||
VcsLogDiffHandler handler = e.getData(VcsLogInternalDataKeys.LOG_DIFF_HANDLER);
|
||||
|
||||
if (filePath == null || filePath.getVirtualFile() == null || handler == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (detail != null) {
|
||||
return detail.getParents().size() == 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performAction(@NotNull Project project,
|
||||
@NotNull FileHistoryUi ui,
|
||||
@NotNull VcsFullCommitDetails detail,
|
||||
@NotNull AnActionEvent e) {
|
||||
if (ChangeListManager.getInstance(project).isFreezedWithNotification(null)) return;
|
||||
if (detail.getParents().size() != 1) return;
|
||||
|
||||
FilePath path = e.getRequiredData(VcsDataKeys.FILE_PATH);
|
||||
VcsLogDiffHandler handler = e.getRequiredData(VcsLogInternalDataKeys.LOG_DIFF_HANDLER);
|
||||
|
||||
handler.showDiffWithLocal(detail.getRoot(), ui.getBeforePath(detail), detail.getParents().get(0), path);
|
||||
}
|
||||
}
|
||||
@@ -460,13 +460,13 @@ vfs.listener.delete.title=Delete Files from Git
|
||||
|
||||
general.error = Git error
|
||||
executable.error.title = Git executable problem
|
||||
executable.error.description = Git couldn't be started. Probably the path to Git executable is not valid. <a href="">Fix it.</a>
|
||||
executable.error.description = Git couldn't be started. The path to the Git executable is probably not valid. <a href="">Fix it.</a>
|
||||
|
||||
git.commit.message.empty=Please specify commit message
|
||||
git.commit.message.empty.title=Commit Message Is Empty
|
||||
|
||||
git.executable.notification.title=Can't start Git
|
||||
git.executable.notification.description=Probably the path to Git executable is not valid.
|
||||
git.executable.notification.description=The path to Git executable is probably not valid.
|
||||
git.executable.dialog.title=Git executable
|
||||
git.executable.dialog.description=Specify the full path to Git executable
|
||||
git.executable.dialog.error=It doesn't appear to be a valid Git executable
|
||||
@@ -485,4 +485,4 @@ vcs.popup.git.github.section=GitHub
|
||||
vcs.history.action.gitlog=Select in Git Log
|
||||
vcs.history.action.gitlog.error=Git Log is not Ready
|
||||
|
||||
exportable.Git.Application.Settings.presentable.name=Git
|
||||
exportable.Git.Application.Settings.presentable.name=Git
|
||||
|
||||
@@ -70,16 +70,20 @@ public class GitPushOptionsPanel extends VcsPushOptionsPanel {
|
||||
myRunHooks.setSelected(true);
|
||||
myRunHooks.setVisible(showSkipHookOption);
|
||||
|
||||
myRunHooks.setBorder(JBUI.Borders.empty());
|
||||
myPushTagsMode.setBorder(JBUI.Borders.empty());
|
||||
myPushTags.setBorder(JBUI.Borders.empty());
|
||||
|
||||
setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||
add(myPushTags);
|
||||
add(Box.createHorizontalStrut(JBUI.scale(3)));
|
||||
add(myPushTagsMode);
|
||||
add(Box.createHorizontalStrut(JBUI.scale(37)));
|
||||
add(myRunHooks);
|
||||
if (myPushTagsMode.isVisible()) {
|
||||
add(Box.createHorizontalStrut(calcStrutWidth(8, myPushTags, myPushTagsMode)));
|
||||
add(myPushTagsMode);
|
||||
}
|
||||
if (myRunHooks.isVisible()) {
|
||||
add(Box.createHorizontalStrut(calcStrutWidth(40, myPushTagsMode, myRunHooks)));
|
||||
add(myRunHooks);
|
||||
}
|
||||
}
|
||||
|
||||
private static int calcStrutWidth(int plannedWidth, @NotNull JComponent leftComponent, @NotNull JComponent rightComponent) {
|
||||
return JBUI.scale(plannedWidth) - JBUI.insets(rightComponent.getInsets()).left - JBUI.insets(leftComponent.getInsets()).right;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -335,6 +335,8 @@
|
||||
<codeInsight.parameterNameHints
|
||||
language="Groovy" implementationClass="org.jetbrains.plugins.groovy.codeInsight.hint.GroovyInlayParameterHintsProvider"
|
||||
/>
|
||||
<codeInsight.intention.jvmCommonIntentionActionsFactory language="Groovy"
|
||||
implementationClass="com.intellij.codeInsight.intention.impl.JavaCommonIntentionActionsFactory"/>
|
||||
|
||||
<fileTypeFactory implementation="org.jetbrains.plugins.groovy.GroovyFileTypeLoader"/>
|
||||
<fileTypeFactory implementation="org.jetbrains.plugins.groovy.dgm.DGMFileTypeFactory"/>
|
||||
|
||||
@@ -65,7 +65,7 @@ hg4idea.commit.partial.merge.title=Partial Merge Commit
|
||||
hg4idea.commit.error.messageEmpty=Please provide a commit message
|
||||
|
||||
hg4idea.executable.notification.title=Can't start Mercurial
|
||||
hg4idea.executable.notification.description=Probably the path to hg executable is not valid.
|
||||
hg4idea.executable.notification.description=The path to the hg executable is probably not valid.
|
||||
|
||||
hg4idea.init.dialog.title=Create Mercurial repository
|
||||
hg4idea.init.dialog.incorrect.path=The specified path is incorrect
|
||||
|
||||
@@ -40,12 +40,12 @@ import java.util.Set;
|
||||
public class JavaFXQuickfixTest extends LightCodeInsightFixtureTestCase {
|
||||
public static final DefaultLightProjectDescriptor JAVA_FX_WITH_GROOVY_DESCRIPTOR = new DefaultLightProjectDescriptor() {
|
||||
@Override
|
||||
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
|
||||
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
|
||||
AbstractJavaFXTestCase.addJavaFxJarAsLibrary(module, model);
|
||||
PsiTestUtil.addLibrary(module, model, "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "groovy-1.8.0.jar");
|
||||
super.configureModule(module, model, contentEntry);
|
||||
}
|
||||
};
|
||||
PsiTestUtil.addLibrary(module, model, "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "groovy-1.8.0.jar");
|
||||
super.configureModule(module, model, contentEntry);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -106,7 +106,8 @@ public class JavaFXQuickfixTest extends LightCodeInsightFixtureTestCase {
|
||||
}
|
||||
|
||||
public void testCreateMethodEscalateVisibility() throws Exception {
|
||||
doTestWithDefaultVisibility("Create method 'void onAction(ActionEvent)'", "CreateMethod", VisibilityUtil.ESCALATE_VISIBILITY, ".java");
|
||||
doTestWithDefaultVisibility("Create method 'void onAction(ActionEvent)'", "CreateMethod", VisibilityUtil.ESCALATE_VISIBILITY,
|
||||
".java");
|
||||
}
|
||||
|
||||
public void testCreateFieldEmptyName() throws Exception {
|
||||
@@ -122,7 +123,8 @@ public class JavaFXQuickfixTest extends LightCodeInsightFixtureTestCase {
|
||||
assertNotNull(intention);
|
||||
Set<String> languages = JavaFxInjectPageLanguageIntention.getAvailableLanguages(getProject());
|
||||
assertContainsElements(languages, "groovy");
|
||||
JavaFxInjectPageLanguageIntention languageIntention = (JavaFxInjectPageLanguageIntention)((IntentionActionDelegate)intention).getDelegate();
|
||||
JavaFxInjectPageLanguageIntention languageIntention =
|
||||
(JavaFxInjectPageLanguageIntention)((IntentionActionDelegate)intention).getDelegate();
|
||||
languageIntention.registerPageLanguage(getProject(), (XmlFile)myFixture.getFile(), "groovy");
|
||||
myFixture.checkResultByFile(getTestName(true) + ".fxml", getTestName(true) + "_after.fxml", true);
|
||||
}
|
||||
@@ -168,7 +170,7 @@ public class JavaFXQuickfixTest extends LightCodeInsightFixtureTestCase {
|
||||
super.setUp();
|
||||
myFixture.enableInspections(new JavaFxUnresolvedFxIdReferenceInspection());
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
|
||||
@@ -16,12 +16,16 @@
|
||||
package org.jetbrains.plugins.javaFX.fxml.refs;
|
||||
|
||||
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateMethodQuickFix;
|
||||
import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory;
|
||||
import com.intellij.codeInsight.intention.MethodInsertionInfo;
|
||||
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.psi.xml.XmlAttribute;
|
||||
@@ -34,6 +38,7 @@ import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames;
|
||||
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class JavaFxEventHandlerReference extends PsiReferenceBase<XmlAttributeValue> {
|
||||
@@ -59,8 +64,8 @@ public class JavaFxEventHandlerReference extends PsiReferenceBase<XmlAttributeVa
|
||||
final List<PsiMethod> availableHandlers = new ArrayList<>();
|
||||
for (PsiMethod psiMethod : myController.getAllMethods()) {
|
||||
if (isHandlerMethodSignature(psiMethod, myController) && JavaFxPsiUtil.isVisibleInFxml(psiMethod)) {
|
||||
availableHandlers.add(psiMethod);
|
||||
}
|
||||
availableHandlers.add(psiMethod);
|
||||
}
|
||||
}
|
||||
return availableHandlers.isEmpty() ? EMPTY_ARRAY : ArrayUtil.toObjectArray(availableHandlers);
|
||||
}
|
||||
@@ -92,30 +97,58 @@ public class JavaFxEventHandlerReference extends PsiReferenceBase<XmlAttributeVa
|
||||
return new TextRange(range.getStartOffset() + 1, range.getEndOffset());
|
||||
}
|
||||
|
||||
public static class JavaFxUnresolvedReferenceHandlerQuickfixProvider extends UnresolvedReferenceQuickFixProvider<JavaFxEventHandlerReference> {
|
||||
public static class JavaFxUnresolvedReferenceHandlerQuickfixProvider
|
||||
extends UnresolvedReferenceQuickFixProvider<JavaFxEventHandlerReference> {
|
||||
|
||||
@Override
|
||||
public void registerFixes(@NotNull final JavaFxEventHandlerReference ref, @NotNull final QuickFixActionRegistrar registrar) {
|
||||
if (ref.myController != null && ref.myEventHandler == null) {
|
||||
final CreateMethodQuickFix quickFix = CreateMethodQuickFix.createFix(ref.myController, getHandlerSignature(ref), "");
|
||||
if (quickFix != null) {
|
||||
registrar.register(quickFix);
|
||||
}
|
||||
JvmCommonIntentionActionsFactory intentionActionsFactory =
|
||||
JvmCommonIntentionActionsFactory.forLanguage(ref.myController.getLanguage());
|
||||
if (intentionActionsFactory == null) return;
|
||||
|
||||
String javaSignature = getHandlerSignature(ref);
|
||||
PsiMethod javaMethod = JavaPsiFacade.getElementFactory(ref.myController.getProject())
|
||||
.createMethodFromText(javaSignature, ref.myController);
|
||||
|
||||
MethodInsertionInfo.Method method =
|
||||
MethodInsertionInfo.simpleMethodInfo(ref.myController,
|
||||
javaMethod.getName(),
|
||||
javaMethod.getModifierList().getText(),
|
||||
javaMethod.getReturnType(),
|
||||
Arrays.asList(javaMethod.getParameterList().getParameters()));
|
||||
intentionActionsFactory.createAddCallableMemberActions(method).forEach(registrar::register);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getHandlerSignature(JavaFxEventHandlerReference ref) {
|
||||
final XmlAttributeValue element = ref.getElement();
|
||||
String canonicalText = JavaFxCommonNames.JAVAFX_EVENT;
|
||||
PsiType eventType = getEventType(element);
|
||||
final String modifiers = getModifiers(element.getProject());
|
||||
return modifiers + " void " + element.getValue().substring(1) + "(" +
|
||||
eventType.getCanonicalText() + " " + suggestParamName(element.getProject(), eventType) +
|
||||
")";
|
||||
}
|
||||
|
||||
private static String suggestParamName(Project project, PsiType eventType) {
|
||||
SuggestedNameInfo suggestedInfo = JavaCodeStyleManager.getInstance(project)
|
||||
.suggestVariableName(VariableKind.PARAMETER, null, null, eventType);
|
||||
if (suggestedInfo.names.length < 1) {
|
||||
return "e";
|
||||
}
|
||||
return suggestedInfo.names[0];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiType getEventType(XmlAttributeValue element) {
|
||||
final PsiElement parent = element.getParent();
|
||||
if (parent instanceof XmlAttribute) {
|
||||
final PsiClassType eventType = JavaFxPsiUtil.getDeclaredEventType((XmlAttribute)parent);
|
||||
if (eventType != null) {
|
||||
canonicalText = eventType.getCanonicalText();
|
||||
return eventType;
|
||||
}
|
||||
}
|
||||
final String modifiers = getModifiers(element.getProject());
|
||||
return modifiers + " void " + element.getValue().substring(1) + "(" + canonicalText + " e)";
|
||||
return PsiType.getTypeByName(JavaFxCommonNames.JAVAFX_EVENT, element.getProject(), element.getResolveScope());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -7,6 +7,5 @@ public class QuickfixHalfRaw {
|
||||
@FXML TableView<Pair> table;
|
||||
|
||||
public void onSort(SortEvent<TableView<Pair>> tableViewSortEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,5 @@ import javafx.scene.control.TableColumn.CellEditEvent;
|
||||
|
||||
public class QuickfixNoFieldNested {
|
||||
public void onColumnEditStart(CellEditEvent cellEditEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,5 @@ import javafx.scene.control.TableView;
|
||||
|
||||
public class QuickfixNoField {
|
||||
public void onSort(SortEvent<TableView> tableViewSortEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,5 @@ public class QuickfixRaw {
|
||||
@FXML TableView table;
|
||||
|
||||
public void onSort(SortEvent<TableView> tableViewSortEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,5 @@ public class QuickfixSpecific {
|
||||
TableView<Pair<Integer, String>> table;
|
||||
|
||||
public void onSort(SortEvent<TableView<Pair<Integer, String>>> tableViewSortEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,5 @@ import javafx.scene.input.MouseEvent;
|
||||
|
||||
public class QuickfixSuper{
|
||||
public void click(MouseEvent mouseEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,5 @@ public class CreateControllerMethodGeneric {
|
||||
TableView<Map<Integer, String>> table;
|
||||
|
||||
public void onSort(SortEvent<TableView<Map<Integer, String>>> tableViewSortEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,5 @@ public class CreateControllerMethodHalfRaw {
|
||||
TableView<Map> table;
|
||||
|
||||
public void onSort(SortEvent<TableView<Map>> tableViewSortEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import javafx.event.ActionEvent
|
||||
|
||||
public class CreateControllerMethodInGroovy {
|
||||
public void bar(ActionEvent actionEvent) {
|
||||
|
||||
}
|
||||
public void bar(ActionEvent actionEvent) {}
|
||||
}
|
||||
@@ -2,6 +2,5 @@ import javafx.event.ActionEvent;
|
||||
|
||||
public class CreateControllerMethod {
|
||||
public void bar(ActionEvent actionEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,5 @@ import javafx.fxml.FXML;
|
||||
public class CreateMethod {
|
||||
@FXML
|
||||
private void onAction(ActionEvent actionEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,5 @@ import javafx.fxml.FXML;
|
||||
public class CreateMethod {
|
||||
@FXML
|
||||
void onAction(ActionEvent actionEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,5 @@ import javafx.fxml.FXML;
|
||||
public class CreateMethod {
|
||||
@FXML
|
||||
private void onAction(ActionEvent actionEvent) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,5 @@ import javafx.fxml.FXML;
|
||||
public class CreateMethod {
|
||||
@FXML
|
||||
protected void onAction(ActionEvent actionEvent) {
|
||||
|
||||
}
|
||||
}
|
||||