introduce field: extract error expression on class level ( IDEA-41570 )

This commit is contained in:
anna
2010-06-01 18:30:49 +04:00
parent 33fdaf1154
commit 941142b346
18 changed files with 140 additions and 14 deletions

View File

@@ -157,6 +157,7 @@ public class CodeInsightUtil {
public static PsiExpression[] findExpressionOccurrences(PsiElement scope, PsiExpression expr) {
List<PsiExpression> array = new ArrayList<PsiExpression>();
addExpressionOccurrences(RefactoringUtil.unparenthesizeExpression(expr), array, scope);
if (!array.contains(expr)) array.add(expr);
return array.toArray(new PsiExpression[array.size()]);
}

View File

@@ -39,6 +39,7 @@ import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.WindowManager;
@@ -164,7 +165,8 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
PsiElement anchor = getNormalizedAnchor(anchorElement);
boolean tempDeleteSelf = false;
final Boolean outOfCodeBlockExtraction = selectedExpr.getUserData(ElementToWorkOn.OUT_OF_CODE_BLOCK);
boolean tempDeleteSelf = outOfCodeBlockExtraction != null;
if (element.getParent() instanceof PsiExpressionStatement && anchor.equals(anchorElement)) {
PsiStatement statement = (PsiStatement)element.getParent();
if (statement.getParent() instanceof PsiCodeBlock) {
@@ -252,7 +254,16 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
if (expr.getParent() instanceof PsiParenthesizedExpression) {
expr = (PsiExpression)expr.getParent();
}
if (deleteSelf) {
if (outOfCodeBlockExtraction != null) {
final int endOffset = selectedExpr.getUserData(ElementToWorkOn.TEXT_RANGE).getEndOffset();
PsiElement endElement = element.getContainingFile().findElementAt(endOffset);
while (true) {
final PsiElement parent = endElement.getParent();
if (parent instanceof PsiClass) break;
endElement = parent;
}
element.getParent().deleteChildRange(element, PsiTreeUtil.skipSiblingsBackward(endElement, PsiWhiteSpace.class));
} else if (deleteSelf) {
element.getParent().delete();
}

View File

@@ -43,6 +43,7 @@ public class ElementToWorkOn {
public static final Key<String> PREFIX = Key.create("prefix");
public static final Key<String> SUFFIX = Key.create("suffix");
public static final Key<RangeMarker> TEXT_RANGE = Key.create("range");
public static final Key<Boolean> OUT_OF_CODE_BLOCK= Key.create("out_of_code_block");
private ElementToWorkOn(PsiLocalVariable localVariable, PsiExpression expr) {
myLocalVariable = localVariable;

View File

@@ -199,8 +199,10 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
if (elementAtEnd == null) return null;
PsiExpression tempExpr;
final PsiElement elementAt = PsiTreeUtil.findCommonParent(elementAtStart, elementAtEnd);
if (PsiTreeUtil.getParentOfType(elementAt, PsiExpression.class, false) == null) return null;
PsiElement elementAt = PsiTreeUtil.findCommonParent(elementAtStart, elementAtEnd);
if (PsiTreeUtil.getParentOfType(elementAt, PsiExpression.class, false) == null) {
elementAt = null;
}
final PsiLiteralExpression literalExpression = PsiTreeUtil.getParentOfType(elementAt, PsiLiteralExpression.class);
final PsiLiteralExpression startLiteralExpression = PsiTreeUtil.getParentOfType(elementAtStart, PsiLiteralExpression.class);
@@ -286,7 +288,19 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
FileDocumentManager.getInstance().getDocument(file.getVirtualFile()).createRangeMarker(startOffset, endOffset);
tempExpr.putUserData(ElementToWorkOn.TEXT_RANGE, rangeMarker);
tempExpr.putUserData(ElementToWorkOn.PARENT, parent);
if (parent != null) {
tempExpr.putUserData(ElementToWorkOn.PARENT, parent);
}
else {
PsiErrorElement errorElement = PsiTreeUtil.getNextSiblingOfType(elementAtStart, PsiErrorElement.class);
if (errorElement == null) {
errorElement = PsiTreeUtil.getParentOfType(elementAtStart, PsiErrorElement.class);
}
if (errorElement == null) return null;
if (!(errorElement.getParent() instanceof PsiClass)) return null;
tempExpr.putUserData(ElementToWorkOn.PARENT, errorElement);
tempExpr.putUserData(ElementToWorkOn.OUT_OF_CODE_BLOCK, Boolean.TRUE);
}
final String fakeInitializer = "intellijidearulezzz";
final int[] refIdx = new int[1];
@@ -567,18 +581,21 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
final String prefix,
final String suffix,
final PsiElement parent, final RangeMarker rangeMarker, int[] refIdx) {
final String allText = parent.getContainingFile().getText();
final TextRange parentRange = parent.getTextRange();
String text = refText;
if (parent != null) {
final String allText = parent.getContainingFile().getText();
final TextRange parentRange = parent.getTextRange();
String beg = allText.substring(parentRange.getStartOffset(), rangeMarker.getStartOffset());
if (StringUtil.stripQuotesAroundValue(beg).trim().length() == 0 && prefix == null) beg = "";
String beg = allText.substring(parentRange.getStartOffset(), rangeMarker.getStartOffset());
if (StringUtil.stripQuotesAroundValue(beg).trim().length() == 0 && prefix == null) beg = "";
String end = allText.substring(rangeMarker.getEndOffset(), parentRange.getEndOffset());
if (StringUtil.stripQuotesAroundValue(end).trim().length() == 0 && suffix == null) end = "";
String end = allText.substring(rangeMarker.getEndOffset(), parentRange.getEndOffset());
if (StringUtil.stripQuotesAroundValue(end).trim().length() == 0 && suffix == null) end = "";
final String start = beg + (prefix != null ? prefix : "");
refIdx[0] = start.length();
final String text = start + refText + (suffix != null ? suffix : "") + end;
final String start = beg + (prefix != null ? prefix : "");
refIdx[0] = start.length();
text = start + refText + (suffix != null ? suffix : "") + end;
}
return JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(text, parent);
}

View File

@@ -307,6 +307,7 @@ public class RefactoringUtil {
public static PsiElement getParentExpressionAnchorElement(PsiElement place) {
PsiElement parent = place.getUserData(ElementToWorkOn.PARENT);
if (place.getUserData(ElementToWorkOn.OUT_OF_CODE_BLOCK) != null) return parent;
if (parent == null) parent = place;
while (true) {
if (isExpressionAnchorElement(parent)) return parent;
@@ -545,6 +546,7 @@ public class RefactoringUtil {
public static PsiElement getAnchorElementForMultipleExpressions(PsiExpression[] occurrences, PsiElement scope) {
PsiElement anchor = null;
for (PsiExpression occurrence : occurrences) {
// if (!occurrence.isPhysical()) continue;
if (scope != null && !PsiTreeUtil.isAncestor(scope, occurrence, false)) {
continue;
}

View File

@@ -0,0 +1,3 @@
class Test {
public final int anInt = 2 + 2;
}

View File

@@ -0,0 +1,7 @@
class Test {
public final Class aClass = Class.forName(Test.class.getName);
void foo() {
Class clazz = aClass;
}
}

View File

@@ -0,0 +1,5 @@
class Test {
public final int anInt = Integer.parseInt("");
void foo() {int i = anInt;}
}

View File

@@ -0,0 +1,4 @@
class Test {
public final int anInt = Integer.parseInt("");
int i = anInt;
}

View File

@@ -0,0 +1,7 @@
class Test {
public final Integer integer = new Integer(0);
void foo() {
Integer i = integer;
}
}

View File

@@ -0,0 +1,3 @@
class Test {
public final int anInt = Integer.parseInt("");
}

View File

@@ -0,0 +1,3 @@
class Test {
2 <caret> + 2
}

View File

@@ -0,0 +1,7 @@
class Test {
<selection>Class.forName(Test.class.getName)</selection>
void foo() {
Class clazz = Class.forName(Test.class.getName);
}
}

View File

@@ -0,0 +1,4 @@
class Test {
Integer.pa<caret>rseInt("")
void foo() {int i = Integer.parseInt("");}
}

View File

@@ -0,0 +1,4 @@
class Test {
int i = Integer.parseInt("");
Integer.pa<caret>rseInt("")
}

View File

@@ -0,0 +1,7 @@
class Test {
<selection>new Integer(0)</selection>
void foo() {
Integer i = new Integer(0);
}
}

View File

@@ -0,0 +1,3 @@
class Test {
Integer.pa<caret>rseInt("")
}

View File

@@ -33,6 +33,43 @@ public class IntroduceFieldInSameClassTest extends LightCodeInsightTestCase {
checkResultByFile("/refactoring/introduceField/afterOuterClass.java");
}
public void testOnClassLevelNoDuplicates() throws Exception {
configureByFile("/refactoring/introduceField/beforeOnClassLevelNoDuplicates.java");
performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, false);
checkResultByFile("/refactoring/introduceField/afterOnClassLevelNoDuplicates.java");
}
public void testOnClassLevelDuplicates() throws Exception {
configureByFile("/refactoring/introduceField/beforeOnClassLevelDuplicates.java");
performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, false);
checkResultByFile("/refactoring/introduceField/afterOnClassLevelDuplicates.java");
}
public void testOnClassLevelDuplicates1() throws Exception {
configureByFile("/refactoring/introduceField/beforeOnClassLevelDuplicates1.java");
performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, false);
checkResultByFile("/refactoring/introduceField/afterOnClassLevelDuplicates1.java");
}
public void testOnClassLevelBinary() throws Exception {
configureByFile("/refactoring/introduceField/beforeOnClassLevelBinary.java");
performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, false);
checkResultByFile("/refactoring/introduceField/afterOnClassLevelBinary.java");
}
//multiple error elements on class level corresponding to the extracted fragment ------------------
public void testOnClassLevelNewExpression() throws Exception {
configureByFile("/refactoring/introduceField/beforeOnClassLevelNewExpression.java");
performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, false);
checkResultByFile("/refactoring/introduceField/afterOnClassLevelNewExpression.java");
}
public void testOnClassLevelClassForName() throws Exception {
configureByFile("/refactoring/introduceField/beforeOnClassLevelClassForName.java");
performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, false);
checkResultByFile("/refactoring/introduceField/afterOnClassLevelClassForName.java");
}
//-------------------------------------------------------------------------------------------------
private static void performRefactoring(final BaseExpressionToFieldHandler.InitializationPlace initializationPlace, final boolean declareStatic) {
new MockIntroduceFieldHandler(initializationPlace, declareStatic).invoke(getProject(), myEditor, myFile, null);
}