mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -74,7 +74,7 @@ public class RefactoringConflictsUtil {
|
||||
public static void checkAccessibilityConflicts(@NotNull PsiMember member,
|
||||
@PsiModifier.ModifierConstant @Nullable String newVisibility,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull Set<? extends PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts) {
|
||||
PsiModifierList modifierListCopy = member.getModifierList();
|
||||
if (modifierListCopy != null) {
|
||||
@@ -97,7 +97,7 @@ public class RefactoringConflictsUtil {
|
||||
public static void checkAccessibilityConflicts(@NotNull PsiMember member,
|
||||
@Nullable PsiModifierList modifierListCopy,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull Set<? extends PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts) {
|
||||
for (PsiReference psiReference : ReferencesSearch.search(member)) {
|
||||
checkAccessibilityConflicts(psiReference, member, modifierListCopy, targetClass, membersToMove, conflicts);
|
||||
@@ -108,7 +108,7 @@ public class RefactoringConflictsUtil {
|
||||
@NotNull PsiMember member,
|
||||
@Nullable PsiModifierList modifierListCopy,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull Set<? extends PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts) {
|
||||
JavaPsiFacade manager = JavaPsiFacade.getInstance(member.getProject());
|
||||
PsiElement ref = reference.getElement();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -47,7 +47,7 @@ public class RefactoringHierarchyUtil {
|
||||
private RefactoringHierarchyUtil() {}
|
||||
|
||||
public static boolean willBeInTargetClass(PsiElement place,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull Set<? extends PsiMember> membersToMove,
|
||||
@Nullable PsiClass targetClass,
|
||||
boolean includeSubclasses) {
|
||||
PsiElement parent = place;
|
||||
|
||||
@@ -113,6 +113,7 @@ public abstract class PullUpDialogBase<Storage extends AbstractMemberInfoStorage
|
||||
}
|
||||
}
|
||||
});
|
||||
updateMemberInfo();
|
||||
gbConstraints.gridy++;
|
||||
panel.add(myClassCombo, gbConstraints);
|
||||
|
||||
@@ -123,7 +124,7 @@ public abstract class PullUpDialogBase<Storage extends AbstractMemberInfoStorage
|
||||
|
||||
protected abstract Class getPreselection();
|
||||
|
||||
private void updateMemberInfo() {
|
||||
protected void updateMemberInfo() {
|
||||
final Class targetClass = (Class) myClassCombo.getSelectedItem();
|
||||
myMemberInfos = myMemberInfoStorage.getIntermediateMemberInfosList(targetClass);
|
||||
}
|
||||
|
||||
+11
-7
@@ -53,7 +53,10 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
|
||||
@Override
|
||||
protected boolean isStringLiteral(@NotNull PsiElement token) {
|
||||
ASTNode node = token.getNode();
|
||||
return node != null && (TokenSets.STRING_LITERALS.contains(node.getElementType()) || node.getElementType() == GroovyElementTypes.GSTRING_INJECTION);
|
||||
return node != null &&
|
||||
(TokenSets.STRING_LITERALS.contains(node.getElementType()) ||
|
||||
node.getElementType() == GroovyElementTypes.GSTRING_INJECTION ||
|
||||
node.getElementType() == GroovyElementTypes.GSTRING_CONTENT);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -74,11 +77,7 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
|
||||
elementType = elementAtSelectionStart.getNode().getElementType();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!isStringLiteral(elementAtSelectionStart) &&
|
||||
!isCharLiteral(elementAtSelectionStart) &&
|
||||
!(elementType == GroovyElementTypes.GSTRING_INJECTION)) {
|
||||
if (!isStringLiteral(elementAtSelectionStart)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -103,9 +102,14 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
|
||||
selectionStart++;
|
||||
selectionEnd--;
|
||||
}
|
||||
if (selectionStart <= textRange.getStartOffset() || selectionEnd >= textRange.getEndOffset()) {
|
||||
if (textRange.getLength() > 0 && (selectionStart <= textRange.getStartOffset() || selectionEnd >= textRange.getEndOffset())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (elementType == GroovyElementTypes.GSTRING_CONTENT) {
|
||||
elementAtSelectionStart = elementAtSelectionStart.getFirstChild();
|
||||
}
|
||||
|
||||
return elementAtSelectionStart;
|
||||
}
|
||||
|
||||
|
||||
+13
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -35,30 +35,24 @@ public class RemoveUnnecessaryBracesInGStringIntention extends Intention {
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiElementPredicate getElementPredicate() {
|
||||
return new MyPredicate();
|
||||
return new PsiElementPredicate() {
|
||||
public boolean satisfiedBy(PsiElement element) {
|
||||
if (!(element instanceof GrString)) return false;
|
||||
|
||||
if (ErrorUtil.containsError(element)) return false;
|
||||
|
||||
for (GrStringInjection child : ((GrString)element).getInjections()) {
|
||||
if (GrStringUtil.checkGStringInjectionForUnnecessaryBraces(child)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException {
|
||||
GrStringUtil.removeUnnecessaryBracesInGString((GrString)element);
|
||||
}
|
||||
|
||||
public static class MyPredicate implements PsiElementPredicate {
|
||||
public boolean satisfiedBy(PsiElement element) {
|
||||
return isIntentionAvailable(element);
|
||||
}
|
||||
|
||||
public static boolean isIntentionAvailable(PsiElement element) {
|
||||
if (!(element instanceof GrString)) return false;
|
||||
|
||||
if (ErrorUtil.containsError(element)) return false;
|
||||
|
||||
for (GrStringInjection child : ((GrString)element).getInjections()) {
|
||||
if (GrStringUtil.checkGStringInjectionForUnnecessaryBraces(child)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -47,15 +47,13 @@ import java.util.List;
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public abstract class ClosureCompleter {
|
||||
private static ExtensionPointName<ClosureCompleter> EP_NAME = ExtensionPointName.create("org.intellij.groovy.closureCompleter");
|
||||
private static final ExtensionPointName<ClosureCompleter> EP_NAME = ExtensionPointName.create("org.intellij.groovy.closureCompleter");
|
||||
|
||||
@Nullable
|
||||
protected abstract List<ClosureParameterInfo> getParameterInfos(InsertionContext context,
|
||||
PsiMethod method,
|
||||
PsiSubstitutor substitutor,
|
||||
Document document,
|
||||
int offset,
|
||||
PsiElement parent);
|
||||
PsiElement place);
|
||||
|
||||
public static boolean runClosureCompletion(InsertionContext context,
|
||||
PsiMethod method,
|
||||
@@ -64,7 +62,7 @@ public abstract class ClosureCompleter {
|
||||
int offset,
|
||||
PsiElement parent) {
|
||||
for (ClosureCompleter completer : EP_NAME.getExtensions()) {
|
||||
final List<ClosureParameterInfo> parameterInfos = completer.getParameterInfos(context, method, substitutor, document, offset, parent);
|
||||
final List<ClosureParameterInfo> parameterInfos = completer.getParameterInfos(context, method, substitutor, parent);
|
||||
if (parameterInfos != null) {
|
||||
runClosureTemplate(context, document, offset, substitutor, method, parameterInfos);
|
||||
return true;
|
||||
|
||||
+4
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.jetbrains.plugins.groovy.lang.completion;
|
||||
|
||||
import com.intellij.codeInsight.completion.InsertionContext;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
@@ -42,9 +41,7 @@ public class EachWithIndexClosureCompleter extends ClosureCompleter {
|
||||
protected List<ClosureParameterInfo> getParameterInfos(InsertionContext context,
|
||||
PsiMethod method,
|
||||
PsiSubstitutor substitutor,
|
||||
Document document,
|
||||
int offset,
|
||||
PsiElement parent) {
|
||||
PsiElement place) {
|
||||
final String name = method.getName();
|
||||
if (!"eachWithIndex".equals(name)) return null;
|
||||
|
||||
@@ -63,7 +60,7 @@ public class EachWithIndexClosureCompleter extends ClosureCompleter {
|
||||
final PsiType type = parameters[0].getType();
|
||||
final PsiType collection = substitutor.substitute(type);
|
||||
|
||||
final PsiType iterable = getIteratedType(parent, collection);
|
||||
final PsiType iterable = getIteratedType(place, collection);
|
||||
if (iterable != null) {
|
||||
return Arrays.asList(
|
||||
new ClosureParameterInfo(iterable.getCanonicalText(), "entry"),
|
||||
@@ -76,7 +73,7 @@ public class EachWithIndexClosureCompleter extends ClosureCompleter {
|
||||
|
||||
final Project project = context.getProject();
|
||||
|
||||
final PsiClass entry = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_UTIL_MAP_ENTRY, parent.getResolveScope());
|
||||
final PsiClass entry = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_UTIL_MAP_ENTRY, place.getResolveScope());
|
||||
if (entry == null) return null;
|
||||
|
||||
final PsiClassType entryType = JavaPsiFacade.getElementFactory(project).createType(entry, typeParams);
|
||||
|
||||
+1
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 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.
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.jetbrains.plugins.groovy.lang.completion;
|
||||
|
||||
import com.intellij.codeInsight.completion.InsertionContext;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.scope.BaseScopeProcessor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -42,8 +41,6 @@ public class GdslClosureCompleter extends ClosureCompleter {
|
||||
protected List<ClosureParameterInfo> getParameterInfos(InsertionContext context,
|
||||
PsiMethod method,
|
||||
PsiSubstitutor substitutor,
|
||||
Document document,
|
||||
int offset,
|
||||
PsiElement place) {
|
||||
final ArrayList<ClosureDescriptor> descriptors = new ArrayList<ClosureDescriptor>();
|
||||
GrReferenceExpression ref = (GrReferenceExpression)place;
|
||||
|
||||
+2
-2
@@ -93,9 +93,9 @@ public abstract class GrDocCommentUtil {
|
||||
PsiElement parent = owner.getParent();
|
||||
|
||||
ASTNode node = owner.getNode();
|
||||
parent.getNode().addLeaf(GroovyTokenTypes.mNLS, "\n", node);
|
||||
parent.getNode().addLeaf(GroovyTokenTypes.mNLS, "\n ", node);
|
||||
|
||||
PsiElement added = parent.addBefore(comment, node.getPsi());
|
||||
PsiElement added = parent.addBefore(comment, owner);
|
||||
assert added instanceof GrDocComment;
|
||||
|
||||
return (GrDocComment)added;
|
||||
|
||||
+131
-75
@@ -19,6 +19,7 @@ package org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.GroovyBundle;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType;
|
||||
@@ -33,6 +34,128 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
|
||||
*/
|
||||
public class CompoundStringExpression implements GroovyElementTypes {
|
||||
private static final Logger LOG = Logger.getInstance(CompoundStringExpression.class);
|
||||
private final PsiBuilder myBuilder;
|
||||
private final GroovyParser myParser;
|
||||
private final boolean myForRefExpr;
|
||||
private final IElementType myBegin;
|
||||
private final IElementType myContent;
|
||||
private final IElementType myEnd;
|
||||
private final IElementType mySimpleLiteral;
|
||||
private final GroovyElementType myCompoundLiteral;
|
||||
private final String myMessage;
|
||||
|
||||
private CompoundStringExpression(PsiBuilder builder,
|
||||
GroovyParser parser,
|
||||
boolean forRefExpr,
|
||||
IElementType begin,
|
||||
IElementType content,
|
||||
IElementType end,
|
||||
IElementType literal,
|
||||
GroovyElementType compoundLiteral,
|
||||
String message) {
|
||||
|
||||
myBuilder = builder;
|
||||
myParser = parser;
|
||||
myForRefExpr = forRefExpr;
|
||||
myBegin = begin;
|
||||
myContent = content;
|
||||
myEnd = end;
|
||||
mySimpleLiteral = literal;
|
||||
myCompoundLiteral = compoundLiteral;
|
||||
myMessage = message;
|
||||
}
|
||||
|
||||
private boolean parse() {
|
||||
PsiBuilder.Marker marker = myBuilder.mark();
|
||||
final PsiBuilder.Marker marker2 = myBuilder.mark();
|
||||
LOG.assertTrue(ParserUtils.getToken(myBuilder, myBegin));
|
||||
|
||||
|
||||
if (mySimpleLiteral != null && myBuilder.getTokenType() == myEnd) {
|
||||
myBuilder.advanceLexer();
|
||||
finishSimpleLiteral(marker, marker2);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (myBuilder.getTokenType() == myContent) {
|
||||
final PsiBuilder.Marker contentMarker = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
if (myBuilder.getTokenType() == mDOLLAR || mySimpleLiteral == null) {
|
||||
contentMarker.done(GSTRING_CONTENT);
|
||||
}
|
||||
else {
|
||||
contentMarker.drop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
processContent();
|
||||
}
|
||||
|
||||
boolean hasInjection = myBuilder.getTokenType() == mDOLLAR;
|
||||
while (myBuilder.getTokenType() == mDOLLAR) {
|
||||
parseInjection();
|
||||
processContent();
|
||||
}
|
||||
|
||||
if (!ParserUtils.getToken(myBuilder, myEnd)) {
|
||||
myBuilder.error(myMessage);
|
||||
}
|
||||
|
||||
if (hasInjection || mySimpleLiteral == null) {
|
||||
marker2.drop();
|
||||
marker.done(myCompoundLiteral);
|
||||
}
|
||||
else {
|
||||
finishSimpleLiteral(marker, marker2);
|
||||
}
|
||||
return hasInjection;
|
||||
}
|
||||
|
||||
private void processContent() {
|
||||
PsiBuilder.Marker marker = myBuilder.mark();
|
||||
if (myBuilder.getTokenType() == myContent) {
|
||||
myBuilder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
myBuilder.mark().done(myContent);
|
||||
}
|
||||
marker.done(GSTRING_CONTENT);
|
||||
}
|
||||
|
||||
private void finishSimpleLiteral(PsiBuilder.Marker marker, PsiBuilder.Marker marker2) {
|
||||
marker2.done(mySimpleLiteral);
|
||||
if (myForRefExpr) {
|
||||
marker.drop();
|
||||
}
|
||||
else {
|
||||
marker.done(LITERAL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses heredoc's content in GString
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
private boolean parseInjection() {
|
||||
if (myBuilder.getTokenType() != mDOLLAR) return false;
|
||||
|
||||
final PsiBuilder.Marker injection = myBuilder.mark();
|
||||
ParserUtils.getToken(myBuilder, mDOLLAR);
|
||||
|
||||
if (mIDENT.equals(myBuilder.getTokenType())) {
|
||||
PathExpression.parse(myBuilder, myParser);
|
||||
}
|
||||
else if (mLCURLY.equals(myBuilder.getTokenType())) {
|
||||
OpenOrClosableBlock.parseClosableBlock(myBuilder, myParser);
|
||||
}
|
||||
else {
|
||||
ParserUtils.wrapError(myBuilder, GroovyBundle.message("identifier.or.block.expected"));
|
||||
}
|
||||
|
||||
injection.done(GSTRING_INJECTION);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Groovy lexer does not smart enough to understand whether a regex contents injections or not. So the parser should do this job.
|
||||
@@ -48,82 +171,15 @@ public class CompoundStringExpression implements GroovyElementTypes {
|
||||
*
|
||||
* @return true if there are any injections
|
||||
*/
|
||||
public static boolean parse(PsiBuilder builder,
|
||||
GroovyParser parser,
|
||||
public static boolean parse(@NotNull PsiBuilder builder,
|
||||
@NotNull GroovyParser parser,
|
||||
boolean forRefExpr,
|
||||
IElementType begin,
|
||||
IElementType content,
|
||||
IElementType end,
|
||||
@NotNull IElementType begin,
|
||||
@NotNull IElementType content,
|
||||
@NotNull IElementType end,
|
||||
@Nullable IElementType literal,
|
||||
GroovyElementType compoundLiteral, String message) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
final PsiBuilder.Marker marker2 = builder.mark();
|
||||
LOG.assertTrue(ParserUtils.getToken(builder, begin));
|
||||
|
||||
if (builder.getTokenType() == content) {
|
||||
final PsiBuilder.Marker contentMarker = builder.mark();
|
||||
builder.advanceLexer();
|
||||
if (builder.getTokenType() == mDOLLAR || literal == null) {
|
||||
contentMarker.done(GSTRING_CONTENT);
|
||||
}
|
||||
else {
|
||||
contentMarker.drop();
|
||||
}
|
||||
}
|
||||
|
||||
boolean inj = builder.getTokenType() == mDOLLAR;
|
||||
while (builder.getTokenType() == mDOLLAR || builder.getTokenType() == content) {
|
||||
if (builder.getTokenType() == mDOLLAR) {
|
||||
parseInjection(builder, parser);
|
||||
}
|
||||
else {
|
||||
ParserUtils.eatElement(builder, GSTRING_CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParserUtils.getToken(builder, end)) {
|
||||
builder.error(message);
|
||||
}
|
||||
|
||||
if (inj || literal == null) {
|
||||
marker2.drop();
|
||||
marker.done(compoundLiteral);
|
||||
}
|
||||
else {
|
||||
marker2.done(literal);
|
||||
if (forRefExpr) {
|
||||
marker.drop();
|
||||
}
|
||||
else {
|
||||
marker.done(LITERAL);
|
||||
}
|
||||
}
|
||||
return inj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses heredoc's content in GString
|
||||
*
|
||||
* @param builder given builder
|
||||
* @return nothing
|
||||
*/
|
||||
private static boolean parseInjection(PsiBuilder builder, GroovyParser parser) {
|
||||
if (builder.getTokenType() != mDOLLAR) return false;
|
||||
|
||||
final PsiBuilder.Marker injection = builder.mark();
|
||||
ParserUtils.getToken(builder, mDOLLAR);
|
||||
|
||||
if (mIDENT.equals(builder.getTokenType())) {
|
||||
PathExpression.parse(builder, parser);
|
||||
}
|
||||
else if (mLCURLY.equals(builder.getTokenType())) {
|
||||
OpenOrClosableBlock.parseClosableBlock(builder, parser);
|
||||
}
|
||||
else {
|
||||
ParserUtils.wrapError(builder, GroovyBundle.message("identifier.or.block.expected"));
|
||||
}
|
||||
|
||||
injection.done(GSTRING_INJECTION);
|
||||
return true;
|
||||
@NotNull GroovyElementType compoundLiteral,
|
||||
@NotNull String message) {
|
||||
return new CompoundStringExpression(builder, parser, forRefExpr, begin, content, end, literal, compoundLiteral, message).parse();
|
||||
}
|
||||
}
|
||||
+5
-6
@@ -19,8 +19,7 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.LiteralTextEscaper;
|
||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrStringContent;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiElementImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
|
||||
@@ -48,10 +47,10 @@ public class GrStringContentImpl extends GroovyPsiElementImpl implements GrStrin
|
||||
|
||||
@Override
|
||||
public GrStringContentImpl updateText(@NotNull String text) {
|
||||
|
||||
final GrString fromText = (GrString)GroovyPsiElementFactory.getInstance(getProject()).createExpressionFromText("\"${0}" + text + "\"");
|
||||
final GrStringContent content = fromText.getContents()[0];
|
||||
getNode().replaceChild(getFirstChild().getNode(), content.getFirstChild().getNode());
|
||||
if (getFirstChild() != null) {
|
||||
getFirstChild().delete();
|
||||
}
|
||||
getNode().addLeaf(GroovyTokenTypes.mGSTRING_CONTENT, text, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -61,7 +61,10 @@ public abstract class GrReferenceListImpl extends GrStubElementBase<GrReferenceL
|
||||
keyword.delete();
|
||||
}
|
||||
else {
|
||||
PsiElement comma = PsiUtil.skipWhitespacesAndComments(psi, refs[0] == psi, true);
|
||||
boolean forward = refs[0] == psi;
|
||||
PsiElement comma = forward
|
||||
? PsiUtil.skipWhitespacesAndComments(psi.getNextSibling(), forward, true)
|
||||
: PsiUtil.skipWhitespacesAndComments(psi.getPrevSibling(), forward, true);
|
||||
if (comma != null && comma.getNode().getElementType() == GroovyTokenTypes.mCOMMA) {
|
||||
comma.delete();
|
||||
}
|
||||
|
||||
@@ -468,9 +468,10 @@ public class GrStringUtil {
|
||||
if (literal instanceof GrString) {
|
||||
final GrStringInjection[] injections = ((GrString)literal).getInjections();
|
||||
if (injections.length > 0) {
|
||||
if (injections[injections.length - 1].getExpression() != null) {
|
||||
if (!checkBraceIsUnnecessary(injections[injections.length - 1].getExpression(), injection.getNextSibling())) {
|
||||
wrapInjection(injections[injections.length - 1]);
|
||||
GrStringInjection last = injections[injections.length - 1];
|
||||
if (last.getExpression() != null) {
|
||||
if (!checkBraceIsUnnecessary(last.getExpression(), injection.getNextSibling())) {
|
||||
wrapInjection(last);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -488,8 +489,9 @@ public class GrStringUtil {
|
||||
|
||||
final GrExpression expression = factory.createExpressionFromText("\"\"\"${}" + literalText + "\"\"\"");
|
||||
|
||||
expression.getFirstChild().delete();
|
||||
expression.getFirstChild().delete();
|
||||
expression.getFirstChild().delete();//quote
|
||||
expression.getFirstChild().delete();//empty gstring content
|
||||
expression.getFirstChild().delete();//empty injection
|
||||
|
||||
final ASTNode node = grString.getNode();
|
||||
if (expression.getFirstChild() != null) {
|
||||
@@ -541,12 +543,12 @@ public class GrStringUtil {
|
||||
|
||||
if (!(statements[0] instanceof GrReferenceExpression)) return false;
|
||||
|
||||
final PsiElement next = injection.getNextSibling();
|
||||
|
||||
return checkBraceIsUnnecessary(statements[0], next);
|
||||
return checkBraceIsUnnecessary(statements[0], injection.getNextSibling());
|
||||
}
|
||||
|
||||
private static boolean checkBraceIsUnnecessary(GrStatement injected, PsiElement next) {
|
||||
if (next.getTextLength() == 0) next = next.getNextSibling();
|
||||
|
||||
char nextChar = next.getText().charAt(0);
|
||||
if (nextChar == '"' || nextChar == '$') {
|
||||
return true;
|
||||
@@ -561,8 +563,14 @@ public class GrStringUtil {
|
||||
}
|
||||
if (!(gString instanceof GrString)) return false;
|
||||
|
||||
final PsiElement child = gString.getChildren()[0];
|
||||
if (!(child instanceof GrStringInjection)) return false;
|
||||
PsiElement child = gString.getFirstChild();
|
||||
if (!(child.getNode().getElementType() == mGSTRING_BEGIN)) return false;
|
||||
|
||||
child = child.getNextSibling();
|
||||
if (child == null || !(child instanceof GrStringContent)) return false;
|
||||
|
||||
child = child.getNextSibling();
|
||||
if (child == null || !(child instanceof GrStringInjection)) return false;
|
||||
|
||||
final PsiElement refExprCopy = ((GrStringInjection)child).getExpression();
|
||||
if (!(refExprCopy instanceof GrReferenceExpression)) return false;
|
||||
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiSearchScopeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.*;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FilteringIterator;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Max Medvedev on 9/28/13
|
||||
*/
|
||||
public class GrRefactoringConflictsUtil {
|
||||
private GrRefactoringConflictsUtil() { }
|
||||
|
||||
public static void analyzeAccessibilityConflicts(@NotNull Set<GrMember> membersToMove,
|
||||
@NotNull PsiClass targetClass,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts,
|
||||
@Nullable String newVisibility) {
|
||||
analyzeAccessibilityConflicts(membersToMove, targetClass, conflicts, newVisibility, targetClass, null);
|
||||
}
|
||||
|
||||
public static void analyzeAccessibilityConflicts(@NotNull Set<GrMember> membersToMove,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts,
|
||||
@Nullable String newVisibility,
|
||||
@NotNull PsiElement context,
|
||||
@Nullable Set<PsiMethod> abstractMethods) {
|
||||
if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { //Still need to check for access object
|
||||
newVisibility = PsiModifier.PUBLIC;
|
||||
}
|
||||
|
||||
for (GrMember member : membersToMove) {
|
||||
checkUsedElements(member, member, membersToMove, abstractMethods, targetClass, context, conflicts);
|
||||
RefactoringConflictsUtil.checkAccessibilityConflicts(member, newVisibility, targetClass, membersToMove, conflicts);
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkUsedElements(PsiMember member,
|
||||
PsiElement scope,
|
||||
@NotNull Set<GrMember> membersToMove,
|
||||
@Nullable Set<PsiMethod> abstractMethods,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull PsiElement context,
|
||||
MultiMap<PsiElement, String> conflicts) {
|
||||
final Set<PsiMember> moving = new HashSet<PsiMember>(membersToMove);
|
||||
if (abstractMethods != null) {
|
||||
moving.addAll(abstractMethods);
|
||||
}
|
||||
if (scope instanceof GrReferenceExpression) {
|
||||
GrReferenceExpression refExpr = (GrReferenceExpression)scope;
|
||||
PsiElement refElement = refExpr.resolve();
|
||||
if (refElement instanceof PsiMember) {
|
||||
if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) {
|
||||
GrExpression qualifier = refExpr.getQualifierExpression();
|
||||
PsiClass accessClass = (PsiClass)(qualifier != null ? PsiUtil.getAccessObjectClass(
|
||||
qualifier).getElement() : null);
|
||||
RefactoringConflictsUtil.checkAccessibility((PsiMember)refElement, context, accessClass, member, conflicts);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scope instanceof GrNewExpression) {
|
||||
final GrNewExpression newExpression = (GrNewExpression)scope;
|
||||
final GrAnonymousClassDefinition anonymousClass = newExpression.getAnonymousClassDefinition();
|
||||
if (anonymousClass != null) {
|
||||
if (!RefactoringHierarchyUtil.willBeInTargetClass(anonymousClass, moving, targetClass, false)) {
|
||||
RefactoringConflictsUtil.checkAccessibility(anonymousClass, context, anonymousClass, member, conflicts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
final PsiMethod refElement = newExpression.resolveMethod();
|
||||
if (refElement != null) {
|
||||
if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) {
|
||||
RefactoringConflictsUtil.checkAccessibility(refElement, context, null, member, conflicts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scope instanceof GrCodeReferenceElement) {
|
||||
GrCodeReferenceElement refExpr = (GrCodeReferenceElement)scope;
|
||||
PsiElement refElement = refExpr.resolve();
|
||||
if (refElement instanceof PsiMember) {
|
||||
if (!RefactoringHierarchyUtil.willBeInTargetClass(refElement, moving, targetClass, false)) {
|
||||
RefactoringConflictsUtil.checkAccessibility((PsiMember)refElement, context, null, member, conflicts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiElement child : scope.getChildren()) {
|
||||
if (child instanceof PsiWhiteSpace || child instanceof PsiComment) continue;
|
||||
checkUsedElements(member, child, membersToMove, abstractMethods, targetClass, context, conflicts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void analyzeModuleConflicts(final Project project,
|
||||
final Collection<? extends PsiElement> scopes,
|
||||
final UsageInfo[] usages,
|
||||
final PsiElement target,
|
||||
final MultiMap<PsiElement,String> conflicts) {
|
||||
if (scopes == null) return;
|
||||
final VirtualFile vFile = PsiUtilCore.getVirtualFile(target);
|
||||
if (vFile == null) return;
|
||||
|
||||
|
||||
List<GroovyPsiElement> groovyScopes =
|
||||
ContainerUtil.collect(scopes.iterator(), new FilteringIterator.InstanceOf<GroovyPsiElement>(GroovyPsiElement.class));
|
||||
analyzeModuleConflicts(project, groovyScopes, usages, vFile, conflicts);
|
||||
scopes.removeAll(groovyScopes);
|
||||
RefactoringConflictsUtil.analyzeModuleConflicts(project, scopes, usages, vFile, conflicts);
|
||||
}
|
||||
|
||||
public static void analyzeModuleConflicts(final Project project,
|
||||
final Collection<? extends GroovyPsiElement> scopes,
|
||||
final UsageInfo[] usages,
|
||||
final VirtualFile vFile,
|
||||
final MultiMap<PsiElement, String> conflicts) {
|
||||
if (scopes == null) return;
|
||||
for (final PsiElement scope : scopes) {
|
||||
if (scope instanceof PsiPackage) return;
|
||||
}
|
||||
|
||||
final Module targetModule = ModuleUtilCore.findModuleForFile(vFile, project);
|
||||
if (targetModule == null) return;
|
||||
final GlobalSearchScope resolveScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(targetModule);
|
||||
final HashSet<PsiElement> reported = new HashSet<PsiElement>();
|
||||
for (final GroovyPsiElement scope : scopes) {
|
||||
scope.accept(new GroovyRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitCodeReferenceElement(GrCodeReferenceElement refElement) {
|
||||
super.visitCodeReferenceElement(refElement);
|
||||
visit(refElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(GrReferenceExpression reference) {
|
||||
super.visitReferenceExpression(reference);
|
||||
visit(reference);
|
||||
}
|
||||
|
||||
private void visit(GrReferenceElement<? extends GroovyPsiElement> reference) {
|
||||
final PsiElement resolved = reference.resolve();
|
||||
if (resolved != null &&
|
||||
!reported.contains(resolved) &&
|
||||
!CommonRefactoringUtil.isAncestor(resolved, scopes) &&
|
||||
!PsiSearchScopeUtil.isInScope(resolveScope, resolved) &&
|
||||
!(resolved instanceof LightElement)) {
|
||||
final String scopeDescription = RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(reference), true);
|
||||
final String message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.in.module.2",
|
||||
RefactoringUIUtil.getDescription(resolved, true),
|
||||
scopeDescription,
|
||||
CommonRefactoringUtil.htmlEmphasize(targetModule.getName()));
|
||||
conflicts.putValue(resolved, CommonRefactoringUtil.capitalize(message));
|
||||
reported.add(resolved);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
boolean isInTestSources = ModuleRootManager.getInstance(targetModule).getFileIndex().isInTestSourceContent(vFile);
|
||||
NextUsage:
|
||||
for (UsageInfo usage : usages) {
|
||||
final PsiElement element = usage.getElement();
|
||||
if (element != null && PsiTreeUtil.getParentOfType(element, GrImportStatement.class, false) == null) {
|
||||
|
||||
for (PsiElement scope : scopes) {
|
||||
if (PsiTreeUtil.isAncestor(scope, element, false)) continue NextUsage;
|
||||
}
|
||||
|
||||
final GlobalSearchScope resolveScope1 = element.getResolveScope();
|
||||
if (!resolveScope1.isSearchInModuleContent(targetModule, isInTestSources)) {
|
||||
final PsiFile usageFile = element.getContainingFile();
|
||||
PsiElement container;
|
||||
if (usageFile instanceof PsiJavaFile) {
|
||||
container = ConflictsUtil.getContainer(element);
|
||||
}
|
||||
else {
|
||||
container = usageFile;
|
||||
}
|
||||
final String scopeDescription = RefactoringUIUtil.getDescription(container, true);
|
||||
final VirtualFile usageVFile = usageFile.getVirtualFile();
|
||||
if (usageVFile != null) {
|
||||
Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(usageVFile);
|
||||
if (module != null) {
|
||||
final String message;
|
||||
final PsiElement referencedElement;
|
||||
if (usage instanceof MoveRenameUsageInfo) {
|
||||
referencedElement = ((MoveRenameUsageInfo)usage).getReferencedElement();
|
||||
}
|
||||
else {
|
||||
referencedElement = usage.getElement();
|
||||
}
|
||||
assert referencedElement != null : usage;
|
||||
if (module == targetModule && isInTestSources) {
|
||||
message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.from.production.of.module.2",
|
||||
RefactoringUIUtil.getDescription(referencedElement, true),
|
||||
scopeDescription,
|
||||
CommonRefactoringUtil.htmlEmphasize(module.getName()));
|
||||
}
|
||||
else {
|
||||
message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.from.module.2",
|
||||
RefactoringUIUtil.getDescription(referencedElement, true),
|
||||
scopeDescription,
|
||||
CommonRefactoringUtil.htmlEmphasize(module.getName()));
|
||||
}
|
||||
conflicts.putValue(referencedElement, CommonRefactoringUtil.capitalize(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-20
@@ -31,14 +31,13 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
@@ -92,7 +91,7 @@ class GrChangeSignatureConflictSearcher {
|
||||
PsiClass accessObjectClass = null;
|
||||
GrExpression qualifier = ((GrReferenceExpression)element).getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
accessObjectClass = getAccessObjectClass(qualifier);
|
||||
accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement();
|
||||
}
|
||||
|
||||
PsiResolveHelper helper = JavaPsiFacade.getInstance(element.getProject()).getResolveHelper();
|
||||
@@ -112,23 +111,6 @@ class GrChangeSignatureConflictSearcher {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass getAccessObjectClass(GrExpression expression) {
|
||||
if (expression instanceof GrConstructorInvocation) return null;
|
||||
PsiType type = expression.getType();
|
||||
if (type instanceof PsiClassType) {
|
||||
return ((PsiClassType)type).resolveGenerics().getElement();
|
||||
}
|
||||
if (type == null && expression instanceof PsiReferenceExpression) {
|
||||
JavaResolveResult resolveResult = ((PsiReferenceExpression)expression).advancedResolve(false);
|
||||
if (resolveResult.getElement() instanceof PsiClass) {
|
||||
return (PsiClass)resolveResult.getElement();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void addMethodConflicts(MultiMap<PsiElement, String> conflicts) {
|
||||
try {
|
||||
GrMethod prototype;
|
||||
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.memberPullUp;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoBase;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.RefactoringHierarchyUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUIUtil;
|
||||
import com.intellij.refactoring.util.classMembers.InterfaceContainmentVerifier;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.refactoring.GrRefactoringConflictsUtil;
|
||||
import org.jetbrains.plugins.groovy.refactoring.classMembers.GrClassMemberReferenceVisitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Max Medvedev on 9/28/13
|
||||
*/
|
||||
public class GrPullUpConflictsUtil {
|
||||
private GrPullUpConflictsUtil() {}
|
||||
|
||||
public static MultiMap<PsiElement, String> checkConflicts(MemberInfoBase<? extends GrMember>[] infos,
|
||||
PsiClass subclass,
|
||||
@Nullable PsiClass superClass,
|
||||
@NotNull PsiPackage targetPackage,
|
||||
@NotNull PsiDirectory targetDirectory,
|
||||
final InterfaceContainmentVerifier interfaceContainmentVerifier) {
|
||||
return checkConflicts(infos, subclass, superClass, targetPackage, targetDirectory, interfaceContainmentVerifier, true);
|
||||
}
|
||||
|
||||
public static MultiMap<PsiElement, String> checkConflicts(final MemberInfoBase<? extends GrMember>[] infos,
|
||||
@NotNull final PsiClass subclass,
|
||||
@Nullable PsiClass superClass,
|
||||
@NotNull final PsiPackage targetPackage,
|
||||
@NotNull PsiDirectory targetDirectory,
|
||||
final InterfaceContainmentVerifier interfaceContainmentVerifier,
|
||||
boolean movedMembers2Super) {
|
||||
final PsiElement targetRepresentativeElement;
|
||||
final boolean isInterfaceTarget;
|
||||
if (superClass != null) {
|
||||
isInterfaceTarget = superClass.isInterface();
|
||||
targetRepresentativeElement = superClass;
|
||||
}
|
||||
else {
|
||||
isInterfaceTarget = false;
|
||||
targetRepresentativeElement = targetDirectory;
|
||||
}
|
||||
|
||||
final Set<GrMember> movedMembers = ContainerUtil.newHashSet();
|
||||
final Set<GrMethod> abstractMethods = ContainerUtil.newHashSet();
|
||||
for (MemberInfoBase<? extends GrMember> info : infos) {
|
||||
GrMember member = info.getMember();
|
||||
if (member instanceof GrMethod) {
|
||||
if (!info.isToAbstract() && !isInterfaceTarget) {
|
||||
movedMembers.add(member);
|
||||
}
|
||||
else {
|
||||
abstractMethods.add((GrMethod)member);
|
||||
}
|
||||
}
|
||||
else {
|
||||
movedMembers.add(member);
|
||||
}
|
||||
}
|
||||
|
||||
final Set<PsiMethod> allAbstractMethods = new HashSet<PsiMethod>(abstractMethods);
|
||||
if (superClass != null) {
|
||||
for (PsiMethod method : subclass.getMethods()) {
|
||||
if (!movedMembers.contains(method) && !method.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
if (method.findSuperMethods(superClass).length > 0) {
|
||||
allAbstractMethods.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
|
||||
|
||||
GrRefactoringConflictsUtil.analyzeAccessibilityConflicts(movedMembers, superClass, conflicts, VisibilityUtil.ESCALATE_VISIBILITY, targetRepresentativeElement,
|
||||
allAbstractMethods);
|
||||
|
||||
if (superClass != null) {
|
||||
if (movedMembers2Super) {
|
||||
checkSuperclassMembers(superClass, infos, conflicts);
|
||||
if (isInterfaceTarget) {
|
||||
checkInterfaceTarget(infos, conflicts);
|
||||
}
|
||||
} else {
|
||||
final String qualifiedName = superClass.getQualifiedName();
|
||||
assert qualifiedName != null;
|
||||
if (superClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
|
||||
if (!Comparing.strEqual(StringUtil.getPackageName(qualifiedName), targetPackage.getQualifiedName())) {
|
||||
conflicts.putValue(superClass, RefactoringUIUtil.getDescription(superClass, true) + " won't be accessible from " +RefactoringUIUtil.getDescription(targetPackage, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if moved methods use other members in the classes between Subclass and Superclass
|
||||
List<PsiElement> checkModuleConflictsList = new ArrayList<PsiElement>();
|
||||
for (PsiMember member : movedMembers) {
|
||||
if (member instanceof PsiMethod || member instanceof PsiClass && !(member instanceof PsiCompiledElement)) {
|
||||
GrClassMemberReferenceVisitor visitor =
|
||||
movedMembers2Super? new ConflictingUsagesOfSubClassMembers(member, movedMembers, abstractMethods, subclass, superClass,
|
||||
superClass != null ? null : targetPackage, conflicts,
|
||||
interfaceContainmentVerifier)
|
||||
: new ConflictingUsagesOfSuperClassMembers(member, subclass, targetPackage, movedMembers, conflicts);
|
||||
((GroovyPsiElement)member).accept(visitor);
|
||||
}
|
||||
checkModuleConflictsList.add(member);
|
||||
}
|
||||
for (final PsiMethod method : abstractMethods) {
|
||||
ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getParameterList());
|
||||
ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getReturnTypeElement());
|
||||
ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getTypeParameterList());
|
||||
}
|
||||
GrRefactoringConflictsUtil.analyzeModuleConflicts(subclass.getProject(), checkModuleConflictsList, new UsageInfo[0], targetRepresentativeElement, conflicts);
|
||||
final String fqName = subclass.getQualifiedName();
|
||||
final String packageName;
|
||||
if (fqName != null) {
|
||||
packageName = StringUtil.getPackageName(fqName);
|
||||
} else {
|
||||
final PsiFile psiFile = PsiTreeUtil.getParentOfType(subclass, PsiFile.class);
|
||||
if (psiFile instanceof PsiClassOwner) {
|
||||
packageName = ((PsiClassOwner)psiFile).getPackageName();
|
||||
} else {
|
||||
packageName = null;
|
||||
}
|
||||
}
|
||||
final boolean toDifferentPackage = !Comparing.strEqual(targetPackage.getQualifiedName(), packageName);
|
||||
for (final GrMethod abstractMethod : abstractMethods) {
|
||||
abstractMethod.accept(new GrClassMemberReferenceVisitor(subclass) {
|
||||
@Override
|
||||
protected void visitClassMemberReferenceElement(GrMember classMember, GrReferenceElement classMemberReference) {
|
||||
if (classMember != null && willBeMoved(classMember, movedMembers)) {
|
||||
boolean isAccessible = false;
|
||||
if (classMember.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
isAccessible = true;
|
||||
}
|
||||
else if (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) &&
|
||||
toDifferentPackage) {
|
||||
isAccessible = true;
|
||||
}
|
||||
if (isAccessible) {
|
||||
String message = RefactoringUIUtil.getDescription(abstractMethod, false) +
|
||||
" uses " +
|
||||
RefactoringUIUtil.getDescription(classMember, true) +
|
||||
" which won't be accessible from the subclass.";
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflicts.putValue(classMember, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (abstractMethod.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && toDifferentPackage) {
|
||||
if (!isInterfaceTarget) {
|
||||
String message = "Can't make " + RefactoringUIUtil.getDescription(abstractMethod, false) +
|
||||
" abstract as it won't be accessible from the subclass.";
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflicts.putValue(abstractMethod, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
private static void checkInterfaceTarget(MemberInfoBase<? extends GrMember>[] infos, MultiMap<PsiElement, String> conflictsList) {
|
||||
for (MemberInfoBase<? extends GrMember> info : infos) {
|
||||
GrMember member = info.getMember();
|
||||
|
||||
if (member instanceof PsiField || member instanceof PsiClass) {
|
||||
if (!member.hasModifierProperty(PsiModifier.STATIC) && !(member instanceof PsiClass && ((PsiClass)member).isInterface())) {
|
||||
String message = RefactoringBundle.message("0.is.not.static.it.cannot.be.moved.to.the.interface", RefactoringUIUtil.getDescription(member, false));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflictsList.putValue(member, message);
|
||||
}
|
||||
}
|
||||
|
||||
if (member instanceof PsiField && ((PsiField)member).getInitializer() == null) {
|
||||
String message = RefactoringBundle.message("0.is.not.initialized.in.declaration.such.fields.are.not.allowed.in.interfaces",
|
||||
RefactoringUIUtil.getDescription(member, false));
|
||||
conflictsList.putValue(member, CommonRefactoringUtil.capitalize(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkSuperclassMembers(PsiClass superClass,
|
||||
MemberInfoBase<? extends GrMember>[] infos,
|
||||
MultiMap<PsiElement, String> conflictsList) {
|
||||
for (MemberInfoBase<? extends GrMember> info : infos) {
|
||||
GrMember member = info.getMember();
|
||||
boolean isConflict = false;
|
||||
if (member instanceof PsiField) {
|
||||
String name = member.getName();
|
||||
|
||||
isConflict = superClass.findFieldByName(name, false) != null;
|
||||
}
|
||||
else if (member instanceof PsiMethod) {
|
||||
PsiSubstitutor superSubstitutor = TypeConversionUtil
|
||||
.getSuperClassSubstitutor(superClass, member.getContainingClass(), PsiSubstitutor.EMPTY);
|
||||
MethodSignature signature = ((PsiMethod) member).getSignature(superSubstitutor);
|
||||
final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(superClass, signature, false);
|
||||
isConflict = superClassMethod != null;
|
||||
}
|
||||
|
||||
if (isConflict) {
|
||||
String message = RefactoringBundle.message("0.already.contains.a.1",
|
||||
RefactoringUIUtil.getDescription(superClass, false),
|
||||
RefactoringUIUtil.getDescription(member, false));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflictsList.putValue(superClass, message);
|
||||
}
|
||||
|
||||
if (member instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)member;
|
||||
final PsiModifierList modifierList = method.getModifierList();
|
||||
if (!modifierList.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
for (PsiClass subClass : ClassInheritorsSearch.search(superClass)) {
|
||||
if (method.getContainingClass() != subClass) {
|
||||
MethodSignature signature = ((PsiMethod) member).getSignature(TypeConversionUtil.getSuperClassSubstitutor(superClass, subClass, PsiSubstitutor.EMPTY));
|
||||
final PsiMethod wouldBeOverriden = MethodSignatureUtil.findMethodBySignature(subClass, signature, false);
|
||||
if (wouldBeOverriden != null && VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(wouldBeOverriden.getModifierList()),
|
||||
VisibilityUtil.getVisibilityModifier(modifierList)) > 0) {
|
||||
conflictsList.putValue(wouldBeOverriden, CommonRefactoringUtil.capitalize(RefactoringUIUtil.getDescription(method, true) + " in super class would clash with local method from " + RefactoringUIUtil.getDescription(subClass, true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean willBeMoved(PsiElement element, Set<GrMember> movedMembers) {
|
||||
PsiElement parent = element;
|
||||
while (parent != null) {
|
||||
if (movedMembers.contains(parent)) return true;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class ConflictingUsagesOfSuperClassMembers extends GrClassMemberReferenceVisitor {
|
||||
|
||||
private PsiMember myMember;
|
||||
private PsiClass mySubClass;
|
||||
private PsiPackage myTargetPackage;
|
||||
private Set<GrMember> myMovedMembers;
|
||||
private MultiMap<PsiElement, String> myConflicts;
|
||||
|
||||
public ConflictingUsagesOfSuperClassMembers(PsiMember member, PsiClass aClass,
|
||||
PsiPackage targetPackage,
|
||||
Set<GrMember> movedMembers,
|
||||
MultiMap<PsiElement, String> conflicts) {
|
||||
super(aClass);
|
||||
myMember = member;
|
||||
mySubClass = aClass;
|
||||
myTargetPackage = targetPackage;
|
||||
myMovedMembers = movedMembers;
|
||||
myConflicts = conflicts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitClassMemberReferenceElement(GrMember classMember, GrReferenceElement ref) {
|
||||
if (classMember != null && !willBeMoved(classMember, myMovedMembers)) {
|
||||
final PsiClass containingClass = classMember.getContainingClass();
|
||||
if (containingClass != null &&
|
||||
!PsiUtil.isAccessibleFromPackage(classMember, myTargetPackage) &&
|
||||
(classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) ||
|
||||
classMember.hasModifierProperty(PsiModifier.PROTECTED) && !mySubClass.isInheritor(containingClass, true))) {
|
||||
myConflicts.putValue(myMember, RefactoringUIUtil.getDescription(classMember, true) + " won't be accessible");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ConflictingUsagesOfSubClassMembers extends GrClassMemberReferenceVisitor {
|
||||
private final PsiElement myScope;
|
||||
private final Set<GrMember> myMovedMembers;
|
||||
private final Set<GrMethod> myAbstractMethods;
|
||||
private final PsiClass mySubclass;
|
||||
private final PsiClass mySuperClass;
|
||||
private final PsiPackage myTargetPackage;
|
||||
private final MultiMap<PsiElement, String> myConflictsList;
|
||||
private final InterfaceContainmentVerifier myInterfaceContainmentVerifier;
|
||||
|
||||
ConflictingUsagesOfSubClassMembers(PsiElement scope,
|
||||
Set<GrMember> movedMembers, Set<GrMethod> abstractMethods,
|
||||
PsiClass subclass, PsiClass superClass,
|
||||
PsiPackage targetPackage, MultiMap<PsiElement, String> conflictsList,
|
||||
InterfaceContainmentVerifier interfaceContainmentVerifier) {
|
||||
super(subclass);
|
||||
myScope = scope;
|
||||
myMovedMembers = movedMembers;
|
||||
myAbstractMethods = abstractMethods;
|
||||
mySubclass = subclass;
|
||||
mySuperClass = superClass;
|
||||
myTargetPackage = targetPackage;
|
||||
myConflictsList = conflictsList;
|
||||
myInterfaceContainmentVerifier = interfaceContainmentVerifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitClassMemberReferenceElement(GrMember classMember, GrReferenceElement ref) {
|
||||
if (classMember != null && RefactoringHierarchyUtil.isMemberBetween(mySuperClass, mySubclass, classMember)) {
|
||||
if (classMember.hasModifierProperty(PsiModifier.STATIC) && !willBeMoved(classMember, myMovedMembers)) {
|
||||
final boolean isAccessible = mySuperClass != null ? PsiUtil.isAccessible(classMember, mySuperClass, null) :
|
||||
myTargetPackage != null ? PsiUtil.isAccessibleFromPackage(classMember, myTargetPackage):
|
||||
classMember.hasModifierProperty(PsiModifier.PUBLIC);
|
||||
if (!isAccessible) {
|
||||
String message = RefactoringBundle.message("0.uses.1.which.is.not.accessible.from.the.superclass",
|
||||
RefactoringUIUtil.getDescription(myScope, false),
|
||||
RefactoringUIUtil.getDescription(classMember, true));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
myConflictsList.putValue(classMember, message);
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!myAbstractMethods.contains(classMember) && !willBeMoved(classMember, myMovedMembers)) {
|
||||
if (!existsInSuperClass(classMember)) {
|
||||
String message = RefactoringBundle.message("0.uses.1.which.is.not.moved.to.the.superclass",
|
||||
RefactoringUIUtil.getDescription(myScope, false),
|
||||
RefactoringUIUtil.getDescription(classMember, true));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
myConflictsList.putValue(classMember, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean existsInSuperClass(PsiElement classMember) {
|
||||
if (!(classMember instanceof PsiMethod)) return false;
|
||||
final PsiMethod method = ((PsiMethod)classMember);
|
||||
if (myInterfaceContainmentVerifier.checkedInterfacesContain(method)) return true;
|
||||
if (mySuperClass == null) return false;
|
||||
final PsiMethod methodBySignature = mySuperClass.findMethodBySignature(method, true);
|
||||
return methodBySignature != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+12
-17
@@ -46,8 +46,6 @@ import org.jetbrains.plugins.groovy.refactoring.classMembers.GrMemberSelectionTa
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -93,20 +91,19 @@ class GrPullUpDialog extends PullUpDialogBase<GrMemberInfoStorage, GrMemberInfo,
|
||||
return myInterfaceContainmentVerifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateMemberInfo() {
|
||||
super.updateMemberInfo();
|
||||
if (myMemberSelectionPanel != null) {
|
||||
((MyMemberInfoModel)myMemberInfoModel).setSuperClass(getSuperClass());
|
||||
myMemberSelectionPanel.getTable().setMemberInfos(myMemberInfos);
|
||||
myMemberSelectionPanel.getTable().fireExternalDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initClassCombo(JComboBox classCombo) {
|
||||
classCombo.setRenderer(new ClassCellRenderer(classCombo.getRenderer()));
|
||||
classCombo.addItemListener(new ItemListener() {
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
if (myMemberSelectionPanel != null) {
|
||||
// ((MyMemberInfoModel)myMemberInfoModel).setSuperClass(getSuperClass());
|
||||
myMemberSelectionPanel.getTable().setMemberInfos(myMemberInfos);
|
||||
myMemberSelectionPanel.getTable().fireExternalDataChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected PsiClass getPreselection() {
|
||||
@@ -140,13 +137,11 @@ class GrPullUpDialog extends PullUpDialogBase<GrMemberInfoStorage, GrMemberInfo,
|
||||
final PsiClass superClass = getSuperClass();
|
||||
String name = superClass.getQualifiedName();
|
||||
if (name != null) {
|
||||
StatisticsManager
|
||||
.getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(), name));
|
||||
StatisticsManager.getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(), name));
|
||||
}
|
||||
|
||||
List<GrMemberInfo> infos = getSelectedMemberInfos();
|
||||
GrPullUpHelper processor =
|
||||
new GrPullUpHelper(myClass, superClass, infos.toArray(new GrMemberInfo[infos.size()]), new DocCommentPolicy(getJavaDocPolicy()));
|
||||
GrPullUpHelper processor = new GrPullUpHelper(myClass, superClass, infos.toArray(new GrMemberInfo[infos.size()]), new DocCommentPolicy(getJavaDocPolicy()));
|
||||
invokeRefactoring(processor);
|
||||
close(OK_EXIT_CODE);
|
||||
}
|
||||
|
||||
+1
-3
@@ -29,7 +29,6 @@ import com.intellij.refactoring.RefactoringActionHandler;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoBase;
|
||||
import com.intellij.refactoring.lang.ElementsHandler;
|
||||
import com.intellij.refactoring.memberPullUp.PullUpConflictsUtil;
|
||||
import com.intellij.refactoring.ui.ConflictsDialog;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.RefactoringHierarchyUtil;
|
||||
@@ -168,8 +167,7 @@ public class GrPullUpHandler implements RefactoringActionHandler, GrPullUpDialog
|
||||
public void run() {
|
||||
final PsiDirectory targetDirectory = superClass.getContainingFile().getContainingDirectory();
|
||||
final PsiPackage targetPackage = targetDirectory != null ? JavaDirectoryService.getInstance().getPackage(targetDirectory) : null;
|
||||
conflicts.putAllValues(PullUpConflictsUtil.checkConflicts(infos, mySubclass, superClass, targetPackage, targetDirectory,
|
||||
dialog.getContainmentVerifier()));
|
||||
conflicts.putAllValues(GrPullUpConflictsUtil.checkConflicts(infos, mySubclass, superClass, targetPackage, targetDirectory, dialog.getContainmentVerifier()));
|
||||
}
|
||||
}, RefactoringBundle.message("detecting.possible.conflicts"), true, myProject)) {
|
||||
return false;
|
||||
|
||||
+34
-26
@@ -25,7 +25,6 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.OverridingMethodsSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.MethodSignatureUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -45,6 +44,9 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
|
||||
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocCommentOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.impl.GrDocCommentUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
@@ -187,13 +189,13 @@ public class GrPullUpHelper extends BaseRefactoringProcessor {
|
||||
// do actual move
|
||||
for (GrMemberInfo info : myMembersToMove) {
|
||||
if (info.getMember() instanceof PsiMethod) {
|
||||
doMoveMethod(movedMembers, substitutor, info);
|
||||
doMoveMethod(substitutor, info);
|
||||
}
|
||||
else if (info.getMember() instanceof GrField) {
|
||||
doMoveField(movedMembers, substitutor, info);
|
||||
doMoveField(substitutor, info);
|
||||
}
|
||||
else if (info.getMember() instanceof PsiClass) {
|
||||
doMoveClass(movedMembers, substitutor, info);
|
||||
doMoveClass(substitutor, info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +317,7 @@ public class GrPullUpHelper extends BaseRefactoringProcessor {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void doMoveMethod(Set<PsiMember> movedMembers, PsiSubstitutor substitutor, GrMemberInfo info) {
|
||||
private void doMoveMethod(PsiSubstitutor substitutor, GrMemberInfo info) {
|
||||
GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(myProject);
|
||||
GrMethod method = (GrMethod)info.getMember();
|
||||
PsiMethod sibling = method;
|
||||
@@ -346,10 +348,8 @@ public class GrPullUpHelper extends BaseRefactoringProcessor {
|
||||
}
|
||||
replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
|
||||
|
||||
myDocCommentPolicy.processCopiedJavaDoc(methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract);
|
||||
|
||||
final PsiMember movedElement =
|
||||
anchor != null ? (PsiMember)myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember)myTargetSuperClass.add(methodCopy);
|
||||
final GrMethod movedElement =
|
||||
anchor != null ? (GrMethod)myTargetSuperClass.addBefore(methodCopy, anchor) : (GrMethod)myTargetSuperClass.add(methodCopy);
|
||||
CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject());
|
||||
if (styleSettings.INSERT_OVERRIDE_ANNOTATION) {
|
||||
if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myTargetSuperClass.isInterface() ||
|
||||
@@ -359,19 +359,16 @@ public class GrPullUpHelper extends BaseRefactoringProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myTargetSuperClass.isInterface()) {
|
||||
if (isOriginalMethodAbstract) {
|
||||
for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) {
|
||||
deleteOverrideAnnotationIfFound(oMethod);
|
||||
}
|
||||
}
|
||||
|
||||
deleteOverrideAnnotationIfFound(method);
|
||||
GrDocComment oldDoc = method.getDocComment();
|
||||
if (oldDoc != null) {
|
||||
GrDocCommentUtil.setDocComment(movedElement, oldDoc);
|
||||
}
|
||||
|
||||
myDocCommentPolicy.processCopiedJavaDoc(methodCopy.getDocComment(), oldDoc, isOriginalMethodAbstract);
|
||||
|
||||
myMembersAfterMove.add(movedElement);
|
||||
if (isOriginalMethodAbstract) {
|
||||
method.delete();
|
||||
deleteMemberWithDocComment(method);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -382,19 +379,30 @@ public class GrPullUpHelper extends BaseRefactoringProcessor {
|
||||
//fixReferencesToStatic(methodCopy, movedMembers);
|
||||
replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
|
||||
final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false);
|
||||
final GrMethod movedElement;
|
||||
if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
superClassMethod.replace(methodCopy);
|
||||
movedElement = (GrMethod)superClassMethod.replace(methodCopy);
|
||||
}
|
||||
else {
|
||||
final PsiMember movedElement =
|
||||
anchor != null ? (PsiMember)myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember)myTargetSuperClass.add(methodCopy);
|
||||
movedElement =
|
||||
anchor != null ? (GrMethod)myTargetSuperClass.addBefore(methodCopy, anchor) : (GrMethod)myTargetSuperClass.add(methodCopy);
|
||||
myMembersAfterMove.add(movedElement);
|
||||
}
|
||||
|
||||
method.delete();
|
||||
GrDocCommentUtil.setDocComment(movedElement, method.getDocComment());
|
||||
|
||||
deleteMemberWithDocComment(method);
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteMemberWithDocComment(GrDocCommentOwner docCommentOwner) {
|
||||
GrDocComment oldDoc = docCommentOwner.getDocComment();
|
||||
if (oldDoc != null) {
|
||||
oldDoc.delete();
|
||||
}
|
||||
docCommentOwner.delete();
|
||||
}
|
||||
|
||||
private static void deleteOverrideAnnotationIfFound(PsiMethod oMethod) {
|
||||
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(oMethod, CommonClassNames.JAVA_LANG_OVERRIDE);
|
||||
if (annotation != null) {
|
||||
@@ -594,7 +602,7 @@ public class GrPullUpHelper extends BaseRefactoringProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private void doMoveField(Set<PsiMember> movedMembers, PsiSubstitutor substitutor, GrMemberInfo info) {
|
||||
private void doMoveField(PsiSubstitutor substitutor, GrMemberInfo info) {
|
||||
GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(myProject);
|
||||
GrField field = (GrField)info.getMember();
|
||||
field.normalizeDeclaration();
|
||||
@@ -605,10 +613,10 @@ public class GrPullUpHelper extends BaseRefactoringProcessor {
|
||||
}
|
||||
final PsiMember movedElement = (PsiMember)myTargetSuperClass.add(field);
|
||||
myMembersAfterMove.add(movedElement);
|
||||
field.delete();
|
||||
deleteMemberWithDocComment(field);
|
||||
}
|
||||
|
||||
private void doMoveClass(Set<PsiMember> movedMembers, PsiSubstitutor substitutor, GrMemberInfo info) {
|
||||
private void doMoveClass(PsiSubstitutor substitutor, GrMemberInfo info) {
|
||||
GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(myProject);
|
||||
GrTypeDefinition aClass = (GrTypeDefinition)info.getMember();
|
||||
if (Boolean.FALSE.equals(info.getOverrides())) {
|
||||
@@ -654,7 +662,7 @@ public class GrPullUpHelper extends BaseRefactoringProcessor {
|
||||
PsiMember movedElement = (PsiMember)myTargetSuperClass.addAfter(aClass, null);
|
||||
//movedElement = (PsiMember)CodeStyleManager.getInstance(myProject).reformat(movedElement);
|
||||
myMembersAfterMove.add(movedElement);
|
||||
aClass.delete();
|
||||
deleteMemberWithDocComment(aClass);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-3
@@ -137,12 +137,24 @@ class GrPullUpTest extends LightGroovyTestCase {
|
||||
doTest(false, new MemberDescriptor("foo", PsiMethod));
|
||||
}
|
||||
|
||||
public void _testExtensionMethod() {
|
||||
public void testPreserveOverride() {
|
||||
doTest(false, new MemberDescriptor("foo", PsiMethod));
|
||||
}
|
||||
|
||||
public void testPreserveOverride() {
|
||||
doTest(false, new MemberDescriptor("foo", PsiMethod));
|
||||
void testImplementsList1() {
|
||||
doTest(false, new MemberDescriptor("I1", PsiClass))
|
||||
}
|
||||
|
||||
void testImplementsList2() {
|
||||
doTest(false, new MemberDescriptor("I2", PsiClass))
|
||||
}
|
||||
|
||||
void testImplementsList3() {
|
||||
doTest(false, new MemberDescriptor("I1", PsiClass), new MemberDescriptor("I2", PsiClass))
|
||||
}
|
||||
|
||||
void testDocCommentInMethod() {
|
||||
doTest(false, new MemberDescriptor("foo", PsiMethod))
|
||||
}
|
||||
|
||||
private void doTest(MemberDescriptor... membersToFind) {
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
Groovy script
|
||||
Compound Gstring
|
||||
PsiElement(Gstring begin)('"')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Reference expression
|
||||
|
||||
@@ -10,6 +10,9 @@ Groovy script
|
||||
PsiElement($)('$')
|
||||
Reference expression
|
||||
PsiElement(identifier)('str')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Reference expression
|
||||
@@ -31,6 +34,9 @@ Groovy script
|
||||
Reference expression
|
||||
PsiElement(identifier)('str')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Reference expression
|
||||
|
||||
@@ -9,5 +9,8 @@ Groovy script
|
||||
PsiWhiteSpace(' ')
|
||||
Compound Gstring
|
||||
PsiElement(Gstring begin)('"')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
PsiErrorElement:String end expected
|
||||
<empty list>
|
||||
@@ -10,6 +10,9 @@ Groovy script
|
||||
PsiWhiteSpace(' ')
|
||||
Compound Gstring
|
||||
PsiElement(Gstring begin)('"')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
PsiErrorElement:String end expected
|
||||
<empty list>
|
||||
PsiElement(new line)('\n')
|
||||
|
||||
+6
@@ -14,8 +14,14 @@ Groovy script
|
||||
Reference expression
|
||||
PsiElement(identifier)('href')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Reference expression
|
||||
PsiElement(identifier)('x')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
PsiElement(Gstring end)('"""')
|
||||
@@ -23,6 +23,9 @@ Groovy script
|
||||
PsiElement(.)('.')
|
||||
Compound regular expression
|
||||
PsiElement(regex begin)('/')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(regex content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Closable block
|
||||
@@ -32,6 +35,9 @@ Groovy script
|
||||
Reference expression
|
||||
PsiElement(identifier)('a')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(regex content)
|
||||
<empty list>
|
||||
PsiElement(regex end)('/')
|
||||
PsiElement(.)('.')
|
||||
Compound regular expression
|
||||
@@ -42,4 +48,7 @@ Groovy script
|
||||
PsiElement($)('$')
|
||||
Reference expression
|
||||
PsiElement(identifier)('g')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement($/ regex content)
|
||||
<empty list>
|
||||
PsiElement($/ regex end)('/$')
|
||||
@@ -13,5 +13,8 @@ Groovy script
|
||||
Literal
|
||||
GroovyASTPsiElementImpl($/ regex literal)
|
||||
PsiElement($/ regex begin)('$/')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement($/ regex content)
|
||||
<empty list>
|
||||
PsiErrorElement:Dollar slash ending expected
|
||||
<empty list>
|
||||
@@ -38,6 +38,9 @@ Groovy script
|
||||
Reference expression
|
||||
PsiElement(identifier)('b')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
PsiElement(Gstring end)('"')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
|
||||
@@ -3,9 +3,15 @@
|
||||
Groovy script
|
||||
Compound regular expression
|
||||
PsiElement(regex begin)('/')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(regex content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
PsiErrorElement:Identifier or code block expected
|
||||
<empty list>
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(regex content)
|
||||
<empty list>
|
||||
PsiErrorElement:Regex ending expected
|
||||
<empty list>
|
||||
@@ -20,5 +20,8 @@ Groovy script
|
||||
Literal
|
||||
PsiElement(Integer)('2')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(regex content)
|
||||
<empty list>
|
||||
PsiElement(regex end)('/')
|
||||
PsiElement())(')')
|
||||
@@ -3,6 +3,9 @@
|
||||
Groovy script
|
||||
Compound regular expression
|
||||
PsiElement(regex begin)('/')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(regex content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Closable block
|
||||
@@ -12,6 +15,9 @@ Groovy script
|
||||
Literal
|
||||
PsiElement(Integer)('1')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(regex content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Closable block
|
||||
@@ -21,4 +27,7 @@ Groovy script
|
||||
Literal
|
||||
PsiElement(Integer)('2')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(regex content)
|
||||
<empty list>
|
||||
PsiElement(regex end)('/')
|
||||
@@ -3,6 +3,9 @@ $/${1}${2}/$
|
||||
Groovy script
|
||||
Compound regular expression
|
||||
PsiElement($/ regex begin)('$/')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement($/ regex content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Closable block
|
||||
@@ -12,6 +15,9 @@ Groovy script
|
||||
Literal
|
||||
PsiElement(Integer)('1')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement($/ regex content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Closable block
|
||||
@@ -21,4 +27,7 @@ Groovy script
|
||||
Literal
|
||||
PsiElement(Integer)('2')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement($/ regex content)
|
||||
<empty list>
|
||||
PsiElement($/ regex end)('/$')
|
||||
@@ -39,6 +39,9 @@ Groovy script
|
||||
Reference expression
|
||||
PsiElement(identifier)('b')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
PsiElement(Gstring end)('"')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
|
||||
@@ -40,6 +40,9 @@ Groovy script
|
||||
Reference expression
|
||||
PsiElement(identifier)('b')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
PsiElement(Gstring end)('"')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
|
||||
@@ -7,6 +7,9 @@ Groovy script
|
||||
Argument label
|
||||
Compound Gstring
|
||||
PsiElement(Gstring begin)('"')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Reference expression
|
||||
@@ -21,6 +24,9 @@ Groovy script
|
||||
PsiWhiteSpace(' ')
|
||||
Compound Gstring
|
||||
PsiElement(Gstring begin)('"')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
GString injection
|
||||
PsiElement($)('$')
|
||||
Reference expression
|
||||
|
||||
@@ -39,6 +39,9 @@ Groovy script
|
||||
Literal
|
||||
PsiElement(Integer)('3')
|
||||
PsiElement(})('}')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
PsiErrorElement:String end expected
|
||||
<empty list>
|
||||
PsiElement(new line)('\n ')
|
||||
@@ -48,5 +51,8 @@ Groovy script
|
||||
Command arguments
|
||||
Compound Gstring
|
||||
PsiElement(Gstring begin)('"""')
|
||||
GrStringContentImpl(GString content element)
|
||||
ASTWrapperPsiElement(Gstring content)
|
||||
<empty list>
|
||||
PsiErrorElement:String end expected
|
||||
<empty list>
|
||||
@@ -0,0 +1,9 @@
|
||||
class Super {
|
||||
}
|
||||
|
||||
class Foo extends Super {
|
||||
/**
|
||||
* doc
|
||||
*/
|
||||
def fo<caret>o() {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class Super {
|
||||
|
||||
/**
|
||||
* doc
|
||||
*/
|
||||
def foo() {}
|
||||
}
|
||||
|
||||
class Foo extends Super {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
|
||||
class Super {}
|
||||
|
||||
class Foo extends Super impleme<caret>nts I1, I2 {}
|
||||
@@ -0,0 +1,6 @@
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
|
||||
class Super implements I1 {}
|
||||
|
||||
class Foo extends Super implements I2 {}
|
||||
@@ -0,0 +1,6 @@
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
|
||||
class Super {}
|
||||
|
||||
class Foo extends Super imp<caret>lements I1, I2 {}
|
||||
@@ -0,0 +1,6 @@
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
|
||||
class Super implements I2 {}
|
||||
|
||||
class Foo extends Super implements I1 {}
|
||||
@@ -0,0 +1,6 @@
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
|
||||
class Super {}
|
||||
|
||||
class Foo extends Super impl<caret>ements I1, I2 {}
|
||||
@@ -0,0 +1,6 @@
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
|
||||
class Super implements I1, I2 {}
|
||||
|
||||
class Foo extends Super {}
|
||||
@@ -101,6 +101,10 @@ public enum WorkingCopyFormat {
|
||||
return myFormat;
|
||||
}
|
||||
|
||||
public boolean isOrGreater(@NotNull WorkingCopyFormat format) {
|
||||
return myVersion.isOrGreaterThan(format.getVersion().major, format.getVersion().minor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WorkingCopyFormat from(@NotNull Version version) {
|
||||
WorkingCopyFormat result = UNKNOWN;
|
||||
|
||||
@@ -3,10 +3,17 @@ package org.jetbrains.idea.svn.api;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.SvnVcs;
|
||||
import org.jetbrains.idea.svn.WorkingCopyFormat;
|
||||
import org.jetbrains.idea.svn.commandLine.SvnBindException;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
|
||||
import org.tmatesoft.svn.core.wc.SVNEvent;
|
||||
import org.tmatesoft.svn.core.wc.SVNEventAction;
|
||||
import org.tmatesoft.svn.core.wc2.SvnTarget;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
@@ -56,4 +63,20 @@ public abstract class BaseSvnClient implements SvnClient {
|
||||
String.format("%s format is not supported. Supported formats are: %s.", format.getName(), StringUtil.join(supported, ",")));
|
||||
}
|
||||
}
|
||||
|
||||
protected static void callHandler(@Nullable ISVNEventHandler handler, @NotNull SVNEvent event) throws VcsException {
|
||||
if (handler != null) {
|
||||
try {
|
||||
handler.handleEvent(event, 0);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
throw new SvnBindException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static SVNEvent createEvent(@NotNull File path, @Nullable SVNEventAction action) {
|
||||
return new SVNEvent(path, null, null, 0, null, null, null, null, action, null, null, null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.idea.svn.portable.SvnWcClientI;
|
||||
import org.jetbrains.idea.svn.properties.PropertyClient;
|
||||
import org.jetbrains.idea.svn.revert.RevertClient;
|
||||
import org.jetbrains.idea.svn.update.RelocateClient;
|
||||
import org.jetbrains.idea.svn.upgrade.UpgradeClient;
|
||||
|
||||
/**
|
||||
* @author Konstantin Kolosovsky.
|
||||
@@ -51,6 +52,7 @@ public abstract class ClientFactory {
|
||||
protected VersionClient myVersionClient;
|
||||
protected ImportClient myImportClient;
|
||||
protected ExportClient myExportClient;
|
||||
protected UpgradeClient myUpgradeClient;
|
||||
|
||||
protected ClientFactory(@NotNull SvnVcs vcs) {
|
||||
myVcs = vcs;
|
||||
@@ -166,6 +168,11 @@ public abstract class ClientFactory {
|
||||
return prepare(myExportClient);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public UpgradeClient createUpgradeClient() {
|
||||
return prepare(myUpgradeClient);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected <T extends SvnClient> T prepare(@NotNull T client) {
|
||||
client.setVcs(myVcs);
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.idea.svn.update.UpdateClient;
|
||||
import org.jetbrains.idea.svn.properties.CmdPropertyClient;
|
||||
import org.jetbrains.idea.svn.revert.CmdRevertClient;
|
||||
import org.jetbrains.idea.svn.update.CmdRelocateClient;
|
||||
import org.jetbrains.idea.svn.upgrade.CmdUpgradeClient;
|
||||
|
||||
/**
|
||||
* @author Konstantin Kolosovsky.
|
||||
@@ -53,6 +54,7 @@ public class CmdClientFactory extends ClientFactory {
|
||||
myVersionClient = new CmdVersionClient();
|
||||
myImportClient = new CmdImportClient();
|
||||
myExportClient = new CmdExportClient();
|
||||
myUpgradeClient = new CmdUpgradeClient();
|
||||
statusClient = new SvnCommandLineStatusClient(myVcs);
|
||||
infoClient = new SvnCommandLineInfoClient(myVcs);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.idea.svn.api;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
|
||||
/**
|
||||
* @author Konstantin Kolosovsky.
|
||||
*/
|
||||
public class Repository {
|
||||
|
||||
@NotNull private final SVNURL myUrl;
|
||||
|
||||
public Repository(@NotNull SVNURL url) {
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SVNURL getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.idea.svn.portable.SvnkitSvnWcClient;
|
||||
import org.jetbrains.idea.svn.properties.SvnKitPropertyClient;
|
||||
import org.jetbrains.idea.svn.revert.SvnKitRevertClient;
|
||||
import org.jetbrains.idea.svn.update.SvnKitRelocateClient;
|
||||
import org.jetbrains.idea.svn.upgrade.SvnKitUpgradeClient;
|
||||
|
||||
/**
|
||||
* @author Konstantin Kolosovsky.
|
||||
@@ -53,6 +54,7 @@ public class SvnKitClientFactory extends ClientFactory {
|
||||
myVersionClient = new SvnKitVersionClient();
|
||||
myImportClient = new SvnKitImportClient();
|
||||
myExportClient = new SvnKitExportClient();
|
||||
myUpgradeClient = new SvnKitUpgradeClient();
|
||||
statusClient = new SvnkitSvnStatusClient(myVcs, null);
|
||||
infoClient = new SvnkitSvnWcClient(myVcs);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
public class SvnCheckoutProvider implements CheckoutProvider {
|
||||
|
||||
public void doCheckout(@NotNull final Project project, Listener listener) {
|
||||
// TODO: Several dialogs is invoked while dialog.show() - seems code should be rewritten to be more transparent
|
||||
CheckoutDialog dialog = new CheckoutDialog(project, listener);
|
||||
dialog.show();
|
||||
}
|
||||
@@ -308,8 +309,9 @@ public class SvnCheckoutProvider implements CheckoutProvider {
|
||||
|
||||
private WorkingCopyFormat displayUpgradeDialog(@NotNull WorkingCopyFormat defaultSelection) {
|
||||
final UpgradeFormatDialog dialog = new UpgradeFormatDialog(myProject, myPath, false);
|
||||
dialog.startLoading();
|
||||
final ModalityState dialogState = ModalityState.any();
|
||||
|
||||
dialog.startLoading();
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -331,7 +333,7 @@ public class SvnCheckoutProvider implements CheckoutProvider {
|
||||
dialog.stopLoading();
|
||||
}
|
||||
}
|
||||
}, ModalityState.stateForComponent(dialog.getWindow()));
|
||||
}, dialogState);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.List;
|
||||
*/
|
||||
public class SvnKitCheckoutClient extends BaseSvnClient implements CheckoutClient {
|
||||
|
||||
private static final List<WorkingCopyFormat> SUPPORTED_FORMATS;
|
||||
public static final List<WorkingCopyFormat> SUPPORTED_FORMATS;
|
||||
|
||||
static {
|
||||
List<WorkingCopyFormat> supportedFormats = new ArrayList<WorkingCopyFormat>();
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.RootUrlInfo;
|
||||
import org.jetbrains.idea.svn.SvnVcs;
|
||||
import org.jetbrains.idea.svn.api.Repository;
|
||||
import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
@@ -215,19 +216,15 @@ public class CommandUtil {
|
||||
}
|
||||
|
||||
private static SVNURL resolveRepositoryUrl(@NotNull SvnVcs vcs, @NotNull SvnCommandName name, @NotNull SvnTarget target) {
|
||||
RootUrlInfo rootInfo = target.isFile()
|
||||
? vcs.getSvnFileUrlMapping().getWcRootForFilePath(target.getFile())
|
||||
: vcs.getSvnFileUrlMapping().getWcRootForUrl(target.getURL().toDecodedString());
|
||||
SVNURL repositoryUrl = rootInfo != null ? rootInfo.getRepositoryUrlUrl() : null;
|
||||
UrlMappingRepositoryProvider urlMappingProvider = new UrlMappingRepositoryProvider(vcs, target);
|
||||
InfoCommandRepositoryProvider infoCommandProvider = new InfoCommandRepositoryProvider(vcs, target);
|
||||
|
||||
// resolve repository url using "svn info" command except the case when that command is executing right now.
|
||||
if (repositoryUrl == null && !SvnCommandName.info.equals(name)) {
|
||||
SVNInfo info = getInfo(vcs, target);
|
||||
|
||||
repositoryUrl = info != null ? info.getRepositoryRootURL() : null;
|
||||
Repository repository = urlMappingProvider.get();
|
||||
if (repository == null && !SvnCommandName.info.equals(name)) {
|
||||
repository = infoCommandProvider.get();
|
||||
}
|
||||
|
||||
return repositoryUrl;
|
||||
return repository != null ? repository.getUrl() : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -296,4 +293,67 @@ public class CommandUtil {
|
||||
}
|
||||
return contentsStatus;
|
||||
}
|
||||
|
||||
public interface RepositoryProvider {
|
||||
|
||||
@Nullable
|
||||
Repository get();
|
||||
}
|
||||
|
||||
public static abstract class BaseRepositoryProvider implements RepositoryProvider {
|
||||
|
||||
@NotNull protected final SvnVcs myVcs;
|
||||
@NotNull protected final SvnTarget myTarget;
|
||||
|
||||
protected BaseRepositoryProvider(@NotNull SvnVcs vcs, @NotNull SvnTarget target) {
|
||||
myVcs = vcs;
|
||||
myTarget = target;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UrlMappingRepositoryProvider extends BaseRepositoryProvider {
|
||||
|
||||
public UrlMappingRepositoryProvider(@NotNull SvnVcs vcs, @NotNull SvnTarget target) {
|
||||
super(vcs, target);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Repository get() {
|
||||
RootUrlInfo rootInfo = null;
|
||||
|
||||
if (!myVcs.getProject().isDefault()) {
|
||||
rootInfo = myTarget.isFile()
|
||||
? myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myTarget.getFile())
|
||||
: myVcs.getSvnFileUrlMapping().getWcRootForUrl(myTarget.getURL().toDecodedString());
|
||||
}
|
||||
|
||||
return rootInfo != null ? new Repository(rootInfo.getRepositoryUrlUrl()) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class InfoCommandRepositoryProvider extends BaseRepositoryProvider {
|
||||
|
||||
public InfoCommandRepositoryProvider(@NotNull SvnVcs vcs, @NotNull SvnTarget target) {
|
||||
super(vcs, target);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Repository get() {
|
||||
Repository result;
|
||||
|
||||
if (myTarget.isURL()) {
|
||||
// TODO: Also could still execute info when target is url - either to use info for authentication or to just get correct repository
|
||||
// TODO: url in case of "read" operations are allowed anonymously.
|
||||
result = new Repository(myTarget.getURL());
|
||||
}
|
||||
else {
|
||||
SVNInfo info = getInfo(myVcs, myTarget);
|
||||
result = info != null ? new Repository(info.getRepositoryRootURL()) : null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,8 @@ public enum SvnCommandName {
|
||||
lock("lock", true),
|
||||
unlock("unlock", true),
|
||||
importFolder("import", false),
|
||||
export("export", false);
|
||||
export("export", false),
|
||||
upgrade("upgrade", true);
|
||||
|
||||
private final String myName;
|
||||
private final boolean myWriteable;
|
||||
|
||||
@@ -17,12 +17,14 @@ package org.jetbrains.idea.svn.dialogs;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
@@ -61,11 +63,13 @@ import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public class CopiesPanel {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(CopiesPanel.class);
|
||||
|
||||
private final Project myProject;
|
||||
private MessageBusConnection myConnection;
|
||||
private SvnVcs myVcs;
|
||||
@@ -98,6 +102,7 @@ public class CopiesPanel {
|
||||
@Override
|
||||
public void run() {
|
||||
final List<WCInfo> infoList = myVcs.getAllWcInfos();
|
||||
final List<WorkingCopyFormat> supportedFormats = getSupportedFormats();
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -117,7 +122,7 @@ public class CopiesPanel {
|
||||
myCurrentInfoList = newList;
|
||||
}
|
||||
Collections.sort(infoList, WCComparator.getInstance());
|
||||
updateList(infoList);
|
||||
updateList(infoList, supportedFormats);
|
||||
myRefreshLabel.setEnabled(true);
|
||||
SwingUtilities.invokeLater(focus);
|
||||
}
|
||||
@@ -178,7 +183,7 @@ public class CopiesPanel {
|
||||
return myRefreshLabel;
|
||||
}
|
||||
|
||||
private void updateList(final List<WCInfo> infoList) {
|
||||
private void updateList(@NotNull final List<WCInfo> infoList, @NotNull final List<WorkingCopyFormat> supportedFormats) {
|
||||
myPanel.removeAll();
|
||||
final Insets nullIndent = new Insets(1, 3, 1, 0);
|
||||
final GridBagConstraints gb =
|
||||
@@ -217,7 +222,7 @@ public class CopiesPanel {
|
||||
SVNDepth.INFINITY, false, null, wcInfo.getFormat());
|
||||
}
|
||||
} else if (CHANGE_FORMAT.equals(e.getDescription())) {
|
||||
changeFormat(wcInfo);
|
||||
changeFormat(wcInfo, supportedFormats);
|
||||
} else if (MERGE_FROM.equals(e.getDescription())) {
|
||||
if (! checkRoot(root, wcInfo.getPath(), " invoke Merge From")) return;
|
||||
mergeFrom(wcInfo, root, editorPane);
|
||||
@@ -237,7 +242,7 @@ public class CopiesPanel {
|
||||
}
|
||||
});
|
||||
editorPane.setBorder(null);
|
||||
editorPane.setText(formatWc(wcInfo));
|
||||
editorPane.setText(formatWc(wcInfo, supportedFormats));
|
||||
|
||||
final JPanel copyPanel = new JPanel(new GridBagLayout());
|
||||
|
||||
@@ -263,14 +268,14 @@ public class CopiesPanel {
|
||||
}
|
||||
|
||||
@SuppressWarnings("MethodMayBeStatic")
|
||||
private String formatWc(WCInfo info) {
|
||||
private String formatWc(@NotNull WCInfo info, @NotNull List<WorkingCopyFormat> supportedFormats) {
|
||||
final StringBuilder sb = new StringBuilder().append("<html><head>").append(UIUtil.getCssFontDeclaration(UIUtil.getLabelFont()))
|
||||
.append("</head><body><table bgColor=\"").append(ColorUtil.toHex(UIUtil.getPanelBackground())).append("\">");
|
||||
|
||||
sb.append("<tr valign=\"top\"><td colspan=\"3\"><b>").append(info.getPath()).append("</b></td></tr>");
|
||||
sb.append("<tr valign=\"top\"><td>URL:</td><td colspan=\"2\">").append(info.getRootUrl()).append("</td></tr>");
|
||||
if (! WorkingCopyFormat.ONE_DOT_SEVEN.equals(info.getFormat())) {
|
||||
// can convert
|
||||
Collection<WorkingCopyFormat> upgradeFormats = getUpgradeFormats(info, supportedFormats);
|
||||
if (upgradeFormats.size() > 1) {
|
||||
sb.append("<tr valign=\"top\"><td>Format:</td><td>").append(info.getFormat().getName()).append("</td><td><a href=\"").
|
||||
append(CHANGE_FORMAT).append("\">Change</a></td></tr>");
|
||||
} else {
|
||||
@@ -302,6 +307,33 @@ public class CopiesPanel {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<WorkingCopyFormat> getSupportedFormats() {
|
||||
List<WorkingCopyFormat> result = Collections.emptyList();
|
||||
|
||||
try {
|
||||
result = myVcs.getFactory().createUpgradeClient().getSupportedFormats();
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Set<WorkingCopyFormat> getUpgradeFormats(@NotNull WCInfo info, @NotNull List<WorkingCopyFormat> supportedFormats) {
|
||||
Set<WorkingCopyFormat> canUpgradeTo = EnumSet.noneOf(WorkingCopyFormat.class);
|
||||
|
||||
for (WorkingCopyFormat format : supportedFormats) {
|
||||
if (format.isOrGreater(info.getFormat())) {
|
||||
canUpgradeTo.add(format);
|
||||
}
|
||||
}
|
||||
canUpgradeTo.add(info.getFormat());
|
||||
|
||||
return canUpgradeTo;
|
||||
}
|
||||
|
||||
private void mergeFrom(@NotNull final WCInfo wcInfo, @NotNull final VirtualFile root, @Nullable final Component mergeLabel) {
|
||||
SelectBranchPopup.showForBranchRoot(myProject, root, new SelectBranchPopup.BranchSelectedCallback() {
|
||||
@Override
|
||||
@@ -338,8 +370,10 @@ public class CopiesPanel {
|
||||
});
|
||||
}
|
||||
|
||||
private void changeFormat(final WCInfo wcInfo) {
|
||||
private void changeFormat(@NotNull final WCInfo wcInfo, @NotNull final List<WorkingCopyFormat> supportedFormats) {
|
||||
ChangeFormatDialog dialog = new ChangeFormatDialog(myProject, new File(wcInfo.getPath()), false, ! wcInfo.isIsWcRoot());
|
||||
|
||||
dialog.setSupported(supportedFormats);
|
||||
dialog.setData(wcInfo.getFormat());
|
||||
dialog.show();
|
||||
if (! dialog.isOK()) {
|
||||
|
||||
@@ -37,7 +37,6 @@ import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
|
||||
import org.tmatesoft.svn.core.wc.SVNEvent;
|
||||
import org.tmatesoft.svn.core.wc.SVNEventAction;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -122,20 +121,7 @@ public class SvnFormatWorker extends Task.Backgroundable {
|
||||
if (supportsChangelists) {
|
||||
myBeforeChangeLists = ChangeListManager.getInstance(myProject).getChangeListsCopy();
|
||||
}
|
||||
final SVNWCClient wcClient = myVcs.createWCClient();
|
||||
wcClient.setEventHandler(new ISVNEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(SVNEvent event, double progress) throws SVNException {
|
||||
if (SVNEventAction.UPGRADED_PATH.equals(event.getAction()) && event.getFile() != null) {
|
||||
indicator.setText2("Upgraded path " + VcsUtil.getPathForProgressPresentation(event.getFile()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCancelled() throws SVNCancelException {
|
||||
indicator.checkCanceled();
|
||||
}
|
||||
});
|
||||
try {
|
||||
for (WCInfo wcInfo : myWcInfos) {
|
||||
File path = new File(wcInfo.getPath());
|
||||
@@ -143,13 +129,13 @@ public class SvnFormatWorker extends Task.Backgroundable {
|
||||
path = SvnUtil.getWorkingCopyRoot(path);
|
||||
}
|
||||
try {
|
||||
if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(myNewFormat)) {
|
||||
indicator.setText(SvnBundle.message("action.Subversion.cleanup.progress.text", path.getAbsolutePath()));
|
||||
wcClient.doCleanup(path);
|
||||
}
|
||||
indicator.setText(SvnBundle.message("action.change.wcopy.format.task.progress.text", path.getAbsolutePath(),
|
||||
SvnUtil.formatRepresentation(wcInfo.getFormat()), SvnUtil.formatRepresentation(myNewFormat)));
|
||||
wcClient.doSetWCFormat(path, myNewFormat.getFormat());
|
||||
String cleanupMessage = SvnBundle.message("action.Subversion.cleanup.progress.text", path.getAbsolutePath());
|
||||
String upgradeMessage = SvnBundle.message("action.change.wcopy.format.task.progress.text", path.getAbsolutePath(),
|
||||
SvnUtil.formatRepresentation(wcInfo.getFormat()),
|
||||
SvnUtil.formatRepresentation(myNewFormat));
|
||||
ISVNEventHandler handler = createUpgradeHandler(indicator, cleanupMessage, upgradeMessage);
|
||||
|
||||
myVcs.getFactory(path).createUpgradeClient().upgrade(path, myNewFormat, handler);
|
||||
} catch (Throwable e) {
|
||||
myExceptions.add(e);
|
||||
}
|
||||
@@ -166,4 +152,32 @@ public class SvnFormatWorker extends Task.Backgroundable {
|
||||
ApplicationManager.getApplication().getMessageBus().syncPublisher(SvnVcs.WC_CONVERTED).run();
|
||||
}
|
||||
}
|
||||
|
||||
private static ISVNEventHandler createUpgradeHandler(@NotNull final ProgressIndicator indicator,
|
||||
@NotNull final String cleanupMessage,
|
||||
@NotNull final String upgradeMessage) {
|
||||
return new ISVNEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(SVNEvent event, double progress) throws SVNException {
|
||||
if (event.getFile() != null) {
|
||||
if (SVNEventAction.UPGRADED_PATH.equals(event.getAction())) {
|
||||
indicator.setText2("Upgraded path " + VcsUtil.getPathForProgressPresentation(event.getFile()));
|
||||
}
|
||||
// fake event indicating cleanup start
|
||||
if (SVNEventAction.UPDATE_STARTED.equals(event.getAction())) {
|
||||
indicator.setText(cleanupMessage);
|
||||
}
|
||||
// fake event indicating upgrade start
|
||||
if (SVNEventAction.UPDATE_COMPLETED.equals(event.getAction())) {
|
||||
indicator.setText(upgradeMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCancelled() throws SVNCancelException {
|
||||
indicator.checkCanceled();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +60,7 @@ public class CmdRevertClient extends BaseSvnClient implements RevertClient {
|
||||
String statusMessage = matcher.group(1);
|
||||
String path = matcher.group(2);
|
||||
|
||||
return new SVNEvent(new File(path), null, null, 0, null, null, null, null, createAction(statusMessage), null, null, null, null, null,
|
||||
null);
|
||||
return createEvent(new File(path), createAction(statusMessage));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.jetbrains.idea.svn.upgrade;
|
||||
|
||||
import com.intellij.execution.process.ProcessOutputTypes;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.WorkingCopyFormat;
|
||||
import org.jetbrains.idea.svn.api.BaseSvnClient;
|
||||
import org.jetbrains.idea.svn.api.FileStatusResultParser;
|
||||
import org.jetbrains.idea.svn.commandLine.CommandUtil;
|
||||
import org.jetbrains.idea.svn.commandLine.LineCommandListener;
|
||||
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
|
||||
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
|
||||
import org.tmatesoft.svn.core.wc.SVNEvent;
|
||||
import org.tmatesoft.svn.core.wc.SVNEventAction;
|
||||
import org.tmatesoft.svn.core.wc2.SvnTarget;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Konstantin Kolosovsky.
|
||||
*/
|
||||
public class CmdUpgradeClient extends BaseSvnClient implements UpgradeClient {
|
||||
|
||||
private static final String STATUS = "\\s*(.+?)\\s*";
|
||||
private static final String PATH = "\\s*\'(.*?)\'\\s*";
|
||||
private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH);
|
||||
|
||||
@Override
|
||||
public void upgrade(@NotNull File path, @NotNull WorkingCopyFormat format, @Nullable ISVNEventHandler handler) throws VcsException {
|
||||
validateFormat(format, getSupportedFormats());
|
||||
|
||||
// fake event indicating upgrade start
|
||||
callHandler(handler, createEvent(path, SVNEventAction.UPDATE_COMPLETED));
|
||||
|
||||
List<String> parameters = new ArrayList<String>();
|
||||
|
||||
CommandUtil.put(parameters, path);
|
||||
|
||||
// TODO: Add general possibility to invoke "handler.checkCancelled" (process should be killed). But currently upgrade process is not
|
||||
// TODO: cancellable from UI - and this makes sense.
|
||||
// for 1.8 - no output
|
||||
// for 1.7 - output in format "Upgraded '<path>'"
|
||||
FileStatusResultParser parser = new FileStatusResultParser(CHANGED_PATH, handler, new UpgradeStatusConvertor());
|
||||
UpgradeLineCommandListener listener = new UpgradeLineCommandListener(parser);
|
||||
|
||||
CommandUtil.execute(myVcs, SvnTarget.fromFile(path), SvnCommandName.upgrade, parameters, listener);
|
||||
listener.throwIfException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkingCopyFormat> getSupportedFormats() throws VcsException {
|
||||
List<WorkingCopyFormat> result = new ArrayList<WorkingCopyFormat>();
|
||||
|
||||
result.add(WorkingCopyFormat.from(myFactory.createVersionClient().getVersion()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class UpgradeStatusConvertor implements Convertor<Matcher, SVNEvent> {
|
||||
|
||||
public SVNEvent convert(@NotNull Matcher matcher) {
|
||||
String statusMessage = matcher.group(1);
|
||||
String path = matcher.group(2);
|
||||
|
||||
return createEvent(new File(path), createAction(statusMessage));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SVNEventAction createAction(@NotNull String code) {
|
||||
SVNEventAction result = null;
|
||||
|
||||
if ("Upgraded".equals(code)) {
|
||||
result = SVNEventAction.UPGRADED_PATH;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class UpgradeLineCommandListener extends LineCommandListener {
|
||||
|
||||
@NotNull private final FileStatusResultParser parser;
|
||||
@NotNull private final AtomicReference<VcsException> exception;
|
||||
|
||||
private UpgradeLineCommandListener(@NotNull FileStatusResultParser parser) {
|
||||
this.parser = parser;
|
||||
exception = new AtomicReference<VcsException>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLineAvailable(String line, Key outputType) {
|
||||
if (ProcessOutputTypes.STDOUT.equals(outputType)) {
|
||||
try {
|
||||
parser.onLine(line);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exception.set(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void throwIfException() throws VcsException {
|
||||
VcsException e = exception.get();
|
||||
|
||||
if (e != null) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.jetbrains.idea.svn.upgrade;
|
||||
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.WorkingCopyFormat;
|
||||
import org.jetbrains.idea.svn.api.BaseSvnClient;
|
||||
import org.jetbrains.idea.svn.checkout.SvnKitCheckoutClient;
|
||||
import org.jetbrains.idea.svn.commandLine.SvnBindException;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
|
||||
import org.tmatesoft.svn.core.wc.SVNEventAction;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Konstantin Kolosovsky.
|
||||
*/
|
||||
public class SvnKitUpgradeClient extends BaseSvnClient implements UpgradeClient {
|
||||
|
||||
@Override
|
||||
public void upgrade(@NotNull File path, @NotNull WorkingCopyFormat format, @Nullable ISVNEventHandler handler) throws VcsException {
|
||||
validateFormat(format, getSupportedFormats());
|
||||
|
||||
SVNWCClient client = myVcs.createWCClient();
|
||||
|
||||
client.setEventHandler(handler);
|
||||
try {
|
||||
cleanupIfNecessary(path, format, client, handler);
|
||||
upgrade(path, format, client, handler);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
throw new SvnBindException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkingCopyFormat> getSupportedFormats() throws VcsException {
|
||||
return SvnKitCheckoutClient.SUPPORTED_FORMATS;
|
||||
}
|
||||
|
||||
private static void cleanupIfNecessary(@NotNull File path,
|
||||
@NotNull WorkingCopyFormat format,
|
||||
@NotNull SVNWCClient client,
|
||||
@Nullable ISVNEventHandler handler) throws SVNException, VcsException {
|
||||
// cleanup is executed only for SVNKit as it could handle both 1.6 and 1.7 formats
|
||||
if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) {
|
||||
// fake event indicating cleanup start
|
||||
callHandler(handler, createEvent(path, SVNEventAction.UPDATE_STARTED));
|
||||
client.doCleanup(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static void upgrade(@NotNull File path,
|
||||
@NotNull WorkingCopyFormat format,
|
||||
@NotNull SVNWCClient client,
|
||||
@Nullable ISVNEventHandler handler) throws SVNException, VcsException {
|
||||
// fake event indicating upgrade start
|
||||
callHandler(handler, createEvent(path, SVNEventAction.UPDATE_COMPLETED));
|
||||
client.doSetWCFormat(path, format.getFormat());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.idea.svn.upgrade;
|
||||
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.WorkingCopyFormat;
|
||||
import org.jetbrains.idea.svn.api.SvnClient;
|
||||
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Konstantin Kolosovsky.
|
||||
*/
|
||||
public interface UpgradeClient extends SvnClient {
|
||||
|
||||
void upgrade(@NotNull File path, @NotNull WorkingCopyFormat format, @Nullable ISVNEventHandler handler) throws VcsException;
|
||||
|
||||
List<WorkingCopyFormat> getSupportedFormats() throws VcsException;
|
||||
}
|
||||
Reference in New Issue
Block a user