diff --git a/java/java-impl/src/com/intellij/codeInspection/miscGenerics/GenericsInspectionToolBase.java b/java/java-impl/src/com/intellij/codeInspection/miscGenerics/GenericsInspectionToolBase.java index 81bfd2dac6e9..ff4361e0d331 100644 --- a/java/java-impl/src/com/intellij/codeInspection/miscGenerics/GenericsInspectionToolBase.java +++ b/java/java-impl/src/com/intellij/codeInspection/miscGenerics/GenericsInspectionToolBase.java @@ -48,6 +48,9 @@ public abstract class GenericsInspectionToolBase extends BaseLocalInspectionTool if (initializer != null) { return getDescriptions(initializer, manager, isOnTheFly); } + if (field instanceof PsiEnumConstant) { + return getDescriptions(field, manager, isOnTheFly); + } return null; } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index aed4ec8201c2..2606eb6d768c 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -1127,17 +1127,41 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo if (parent == null || parent.getElementType() != JavaElementType.METHOD_CALL_EXPRESSION) { return false; } - if (node.getElementType() != JavaElementType.NEW_EXPRESSION) { - return false; - } - ASTNode lastChild = node.getLastChildNode(); - if (lastChild == null || lastChild.getElementType() != JavaElementType.ANONYMOUS_CLASS) { + if (!isAnonymousClass(node)) { return false; } - // Enforce indent only if anonymous class instance expression doesn't start new line. + // Enforce indent only if anonymous class instance expression doesn't start new line and have anonymous class expression sibling. ASTNode prev = node.getTreePrev(); - return prev == null || prev.getElementType() != TokenType.WHITE_SPACE || !StringUtil.containsLineBreak(prev.getChars()); + if (prev == null || (StringUtil.containsLineBreak(prev.getChars()) && prev.getElementType() != TokenType.WHITE_SPACE)) { + return false; + } + + final PsiElement psi = myNode.getPsi(); + if (!(psi instanceof PsiExpressionList)) { + return false; + } + + PsiExpressionList expressionList = (PsiExpressionList)psi; + for (PsiExpression expression : expressionList.getExpressions()) { + final ASTNode argumentNode = expression.getNode(); + if (argumentNode == node) { + continue; + } + + if (isAnonymousClass(argumentNode)) { + return true; + } + } + return false; + } + + private static boolean isAnonymousClass(@Nullable ASTNode node) { + if (node == null || node.getElementType() != JavaElementType.NEW_EXPRESSION) { + return false; + } + ASTNode lastChild = node.getLastChildNode(); + return lastChild != null && lastChild.getElementType() == JavaElementType.ANONYMOUS_CLASS; } @Nullable diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java index a11d8f922556..bef59f62c417 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java @@ -422,6 +422,18 @@ public class JavaFormatterIndentationTest extends AbstractJavaFormatterTest { ");" ); + doMethodTest( + "foo(new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}" + + "}, 1, 2);", + "foo(new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + "}, 1, 2);" + ); } public void testPackagePrivateAnnotation() { diff --git a/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java b/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java index e1e2133dd435..ed7c83a390bc 100644 --- a/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java +++ b/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java @@ -25,10 +25,7 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @author max @@ -42,7 +39,11 @@ public class RedundantCastUtil { @NotNull public static List getRedundantCastsInside(PsiElement where) { MyCollectingVisitor visitor = new MyCollectingVisitor(); - where.acceptChildren(visitor); + if (where instanceof PsiEnumConstant) { + where.accept(visitor); + } else { + where.acceptChildren(visitor); + } return new ArrayList(visitor.myFoundCasts); } @@ -247,11 +248,17 @@ public class RedundantCastUtil { super.visitNewExpression(expression); } + @Override + public void visitEnumConstant(PsiEnumConstant enumConstant) { + processCall(enumConstant); + super.visitEnumConstant(enumConstant); + } + @Override public void visitReferenceExpression(PsiReferenceExpression expression) { //expression.acceptChildren(this); } - private void processCall(PsiCallExpression expression){ + private void processCall(PsiCall expression){ PsiExpressionList argumentList = expression.getArgumentList(); if (argumentList == null) return; PsiExpression[] args = argumentList.getExpressions(); @@ -268,7 +275,7 @@ public class RedundantCastUtil { //do not mark cast to resolve ambiguity for calling varargs method with inexact argument continue; } - PsiCallExpression newCall = (PsiCallExpression) expression.copy(); + PsiCall newCall = (PsiCall) expression.copy(); final PsiExpressionList argList = newCall.getArgumentList(); LOG.assertTrue(argList != null); PsiExpression[] newArgs = argList.getExpressions(); @@ -276,10 +283,22 @@ public class RedundantCastUtil { PsiExpression castOperand = castExpression.getOperand(); if (castOperand == null) return; castExpression.replace(castOperand); - final JavaResolveResult newResult = newCall.resolveMethodGenerics(); - if (oldMethod.equals(newResult.getElement()) && newResult.isValidResult() && - Comparing.equal(newCall.getType(), expression.getType())) { - addToResults(cast); + if (newCall instanceof PsiEnumConstant) { + // do this manually, because PsiEnumConstantImpl.resolveMethodGenerics() will assert (no containing class for the copy) + final PsiEnumConstant enumConstant = (PsiEnumConstant)expression; + PsiClass containingClass = enumConstant.getContainingClass(); + final JavaPsiFacade facade = JavaPsiFacade.getInstance(enumConstant.getProject()); + final PsiClassType type = facade.getElementFactory().createType(containingClass); + final JavaResolveResult newResult = facade.getResolveHelper().resolveConstructor(type, newCall.getArgumentList(), enumConstant); + if (oldMethod.equals(newResult.getElement()) && newResult.isValidResult()) { + addToResults(cast); + } + } else { + final JavaResolveResult newResult = newCall.resolveMethodGenerics(); + if (oldMethod.equals(newResult.getElement()) && newResult.isValidResult() && + Comparing.equal(((PsiCallExpression)newCall).getType(), ((PsiCallExpression)expression).getType())) { + addToResults(cast); + } } } } diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index e382a76fa679..56314ae8291b 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -36,6 +36,7 @@ import com.intellij.openapi.editor.event.SelectionListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.LightColors; @@ -93,6 +94,8 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec private MyLivePreviewController myLivePreviewController; private LivePreview myLivePreview; + private boolean mySupressUpdate = false; + private boolean myListeningSelection = false; private SearchResults mySearchResults; @@ -110,16 +113,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec @Override public void replaceAllPerformed(Editor e) { } - @Override - public void replaceDenied() { - updateReplaceButton(); - } - - @Override - public void replaceAllowed() { - updateReplaceButton(); - } - private void updateReplaceButton() { if (myReplaceButton != null) { myReplaceButton.setEnabled(mySearchResults != null && mySearchResults.getCursor() != null && @@ -650,7 +643,12 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec private void initLivePreview() { myDocumentListener = new DocumentAdapter() { public void documentChanged(final DocumentEvent e) { - updateResults(false); + if (!mySupressUpdate) { + myLivePreview.inSmartUpdate(); + updateResults(false); + } else { + mySupressUpdate = false; + } } }; @@ -787,8 +785,12 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec } public void performReplace() { + mySupressUpdate = true; String replacement = getStringToReplace(myEditor, mySearchResults.getCursor()); - performReplace(mySearchResults.getCursor(), replacement, myEditor); + final TextRange textRange = performReplace(mySearchResults.getCursor(), replacement, myEditor); + if (textRange == null) { + mySupressUpdate = false; + } //getFocusBack(); addTextToRecents(myReplaceField) ; } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java index ae01bf38dc45..b571387e4c1e 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java @@ -50,13 +50,27 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele private static final Key IN_SELECTION_KEY = Key.create("LivePreview.IN_SELECTION_KEY"); private static final Object IN_SELECTION1 = new Object(); private static final Object IN_SELECTION2 = new Object(); + private boolean myListeningSelection = false; + private boolean mySuppressedUpdate = false; + private boolean myInSmartUpdate = false; + + private static final Key MARKER_USED = Key.create("LivePreview.MARKER_USED"); + private static final Object YES = new Object(); @Override public void selectionChanged(SelectionEvent e) { updateInSelectionHighlighters(); } + public void supressUpdate() { + mySuppressedUpdate = true; + } + + public void inSmartUpdate() { + myInSmartUpdate = true; + } + public interface Delegate { @Nullable @@ -120,10 +134,38 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele @Override public void searchResultsUpdated(SearchResults sr) { if (mySearchResults.getProject().isDisposed()) return; - removeFromEditor(mySearchResults.getEditor()); + if (mySuppressedUpdate) { + mySuppressedUpdate = false; + return; + } + if (!myInSmartUpdate) { + removeFromEditor(); + } highlightUsages(); updateCursorHighlighting(false); + if (myInSmartUpdate) { + clearUnusedHightlighters(); + myInSmartUpdate = false; + } + } + + private void clearUnusedHightlighters() { + Set unused = new com.intellij.util.containers.HashSet(); + for (RangeHighlighter highlighter : myHighlighters) { + if (highlighter.getUserData(MARKER_USED) == null) { + unused.add(highlighter); + } else { + highlighter.putUserData(MARKER_USED, null); + } + } + myHighlighters.removeAll(unused); + Project project = mySearchResults.getProject(); + if (!project.isDisposed()) { + for (RangeHighlighter highlighter : unused) { + HighlightManager.getInstance(project).removeSegmentHighlighter(mySearchResults.getEditor(), highlighter); + } + } } @Override @@ -133,7 +175,7 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele } public void editorChanged(SearchResults sr, Editor oldEditor) { - removeFromEditor(mySearchResults.getEditor()); + removeFromEditor(); oldEditor.getDocument().removeDocumentListener(this); mySearchResults.getEditor().getDocument().addDocumentListener(this); } @@ -187,14 +229,15 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele public void cleanUp() { - removeFromEditor(mySearchResults.getEditor()); + removeFromEditor(); } public void dispose() { mySearchResults.removeListener(this); } - private void removeFromEditor(Editor editor) { + private void removeFromEditor() { + Editor editor = mySearchResults.getEditor(); if (myReplacementBalloon != null) { myReplacementBalloon.hide(); } @@ -244,7 +287,7 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele mySearchResults.getEditor().getSelectionModel().addSelectionListener(this); myListeningSelection = true; } - + } private void updateInSelectionHighlighters() { @@ -319,13 +362,42 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele @NotNull private RangeHighlighter highlightRange(TextRange textRange, TextAttributes attributes, Collection highlighters) { + if (myInSmartUpdate) { + for (RangeHighlighter highlighter : myHighlighters) { + if (highlighter.isValid() && highlighter.getStartOffset() == textRange.getStartOffset() && highlighter.getEndOffset() == textRange.getEndOffset()) { + if (attributes.equals(highlighter.getTextAttributes())) { + highlighter.putUserData(MARKER_USED, YES); + if (highlighters != myHighlighters) { + highlighters.add(highlighter); + } + return highlighter; + } + } + } + } + final RangeHighlighter highlighter = doHightlightRange(textRange, attributes, highlighters); + if (myInSmartUpdate) { + highlighter.putUserData(MARKER_USED, YES); + } + return highlighter; + } + + private RangeHighlighter doHightlightRange(TextRange textRange, TextAttributes attributes, Collection highlighters) { HighlightManager highlightManager = HighlightManager.getInstance(mySearchResults.getProject()); final ArrayList dummy = new ArrayList(); highlightManager.addRangeHighlight(mySearchResults.getEditor(), textRange.getStartOffset(), textRange.getEndOffset(), attributes, false, dummy); - highlighters.addAll(dummy); - return dummy.get(0); + + final RangeHighlighter h = dummy.get(0); + for (RangeHighlighter highlighter : highlighters) { + if (h.getStartOffset() == highlighter.getStartOffset() && h.getEndOffset() == highlighter.getEndOffset() && + h.getTextAttributes().equals(highlighter.getTextAttributes())) { + return h; + } + } + highlighters.add(h); + return h; } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java index 2b8861bbf30c..77be7b94990f 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java @@ -64,7 +64,6 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil @Override public void searchResultsUpdated(SearchResults sr) { - setReplaceDenied(false); } @Override @@ -89,24 +88,9 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil return myReplaceDenied; } - public void setReplaceDenied(final boolean replaceDenied) { - boolean changed = replaceDenied != myReplaceDenied; - myReplaceDenied = replaceDenied; - if (changed && myReplaceListener != null) { - if (replaceDenied) { - myReplaceListener.replaceDenied(); - } - else { - myReplaceListener.replaceAllowed(); - } - } - } - public interface ReplaceListener { void replacePerformed(LiveOccurrence occurrence, final String replacement, final Editor editor); void replaceAllPerformed(Editor e); - void replaceDenied(); - void replaceAllowed(); } private ReplaceListener myReplaceListener; @@ -146,17 +130,6 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil Runnable request = new Runnable() { @Override public void run() { - Runnable denyReplace = new Runnable() { - @Override - public void run() { - setReplaceDenied(true); - } - }; - if (unitTestMode) { - denyReplace.run(); - } else { - ApplicationManager.getApplication().invokeAndWait(denyReplace, modalityState); - } mySearchResults.updateThreadSafe(copy, allowedToChangedEditorSelection, null, stamp); } }; @@ -213,7 +186,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil if (myReplaceListener != null) { myReplaceListener.replacePerformed(occurrence, replacement, editor); } - setReplaceDenied(true); + myLivePreview.inSmartUpdate(); mySearchResults.updateThreadSafe(findModel, true, result, mySearchResults.getStamp()); return result; } @@ -249,9 +222,8 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil @Override public boolean shouldReplace(TextRange range, String replace) { - for (LiveOccurrence o : mySearchResults.getExcluded()) { - TextRange primaryRange = o.getPrimaryRange(); - if (primaryRange.equals(range)) { + for (RangeMarker r : mySearchResults.getExcluded()) { + if (r.getStartOffset() == range.getStartOffset() && r.getEndOffset() == range.getEndOffset()) { return false; } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java index dce37e881c9e..d812c1b25b85 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java @@ -7,10 +7,12 @@ import com.intellij.find.FindResult; import com.intellij.find.FindUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.Nullable; import java.awt.*; @@ -34,7 +36,7 @@ public class SearchResults { private List myOccurrences = new ArrayList(); - private Set myExcluded = new HashSet(); + private Set myExcluded = new HashSet(); private Editor myEditor; private FindModel myFindModel; @@ -72,19 +74,32 @@ public class SearchResults { } public boolean isExcluded(LiveOccurrence occurrence) { - return myExcluded.contains(occurrence); + for (RangeMarker rangeMarker : myExcluded) { + if (rangeMarker.getStartOffset() == occurrence.getPrimaryRange().getStartOffset() && rangeMarker.getEndOffset() == occurrence.getPrimaryRange().getEndOffset()) { + return true; + } + } + return false; } public void exclude(LiveOccurrence occurrence) { - if (myExcluded.contains(occurrence)) { - myExcluded.remove(occurrence); - } else { - myExcluded.add(occurrence); + boolean include = false; + final TextRange r = occurrence.getPrimaryRange(); + for (RangeMarker rangeMarker : myExcluded) { + if (rangeMarker.getStartOffset() == r.getStartOffset() && rangeMarker.getEndOffset() == r.getEndOffset()) { + myExcluded.remove(rangeMarker); + rangeMarker.dispose(); + include = true; + break; + } + } + if (!include) { + myExcluded.add(myEditor.getDocument().createRangeMarker(r.getStartOffset(), r.getEndOffset(), true)); } notifyChanged(); } - public Set getExcluded() { + public Set getExcluded() { return myExcluded; } @@ -230,6 +245,7 @@ public class SearchResults { myFindModel = findModel; updateCursor(oldCursorRange, next); + updateExcluded(); myActualFound = size; notifyChanged(); if (oldCursorRange == null || myCursor == null || !myCursor.getPrimaryRange().equals(oldCursorRange)) { @@ -238,6 +254,17 @@ public class SearchResults { } } + private void updateExcluded() { + Set invalid = new HashSet(); + for (RangeMarker marker : myExcluded) { + if (!marker.isValid()) { + invalid.add(marker); + marker.dispose(); + } + } + myExcluded.removeAll(invalid); + } + private void updateCursor(@Nullable TextRange oldCursorRange, @Nullable TextRange next) { boolean justReplaced = next != null; if (justReplaced || !tryToRepairOldCursor(oldCursorRange)) { diff --git a/platform/platform-api/src/com/intellij/openapi/components/ServiceManager.java b/platform/platform-api/src/com/intellij/openapi/components/ServiceManager.java index 4bb06c159655..2e7b6e448670 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/ServiceManager.java +++ b/platform/platform-api/src/com/intellij/openapi/components/ServiceManager.java @@ -32,11 +32,11 @@ public class ServiceManager { private ServiceManager() { } - public static T getService(Class serviceClass) { + public static T getService(@NotNull Class serviceClass) { return (T)ApplicationManager.getApplication().getPicoContainer().getComponentInstance(serviceClass.getName()); } - public static T getService(Project project, Class serviceClass) { + public static T getService(@NotNull Project project, @NotNull Class serviceClass) { return (T)project.getPicoContainer().getComponentInstance(serviceClass.getName()); } @@ -47,7 +47,7 @@ public class ServiceManager { * @param Service class type. * @return Key instance. */ - public static NotNullLazyKey createLazyKey(final Class serviceClass) { + public static NotNullLazyKey createLazyKey(@NotNull final Class serviceClass) { return NotNullLazyKey.create("Service: " + serviceClass.getName(), new NotNullFunction() { @NotNull public T fun(Project project) {