Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2016-03-04 10:45:54 +01:00
26 changed files with 345 additions and 143 deletions
@@ -32,7 +32,6 @@ import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.DefUseUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
@@ -78,7 +77,7 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
final String localName = local.getName();
final Query<PsiReference> query = ReferencesSearch.search(local, GlobalSearchScope.allScope(project), false);
final Query<PsiReference> query = ReferencesSearch.search(local, local.getUseScope());
if (query.findFirst() == null){
LOG.assertTrue(refExpr == null);
String message = RefactoringBundle.message("variable.is.never.used", localName);
@@ -42,8 +42,10 @@ import com.intellij.refactoring.util.classMembers.MemberInfoStorage;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
@@ -171,25 +173,26 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
final PsiMethod[] superConstructors = mySuperClass.getConstructors();
for (PsiMethod constructor : targetClass.getConstructors()) {
final PsiCodeBlock constrBody = constructor.getBody();
LOG.assertTrue(constrBody != null);
final PsiStatement[] statements = constrBody.getStatements();
if (statements.length > 0) {
final PsiStatement firstConstrStatement = statements[0];
if (firstConstrStatement instanceof PsiExpressionStatement) {
final PsiExpression expression = ((PsiExpressionStatement)firstConstrStatement).getExpression();
if (expression instanceof PsiMethodCallExpression) {
final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)expression).getMethodExpression();
if (methodExpression.getText().equals(PsiKeyword.SUPER)) {
final PsiMethod superConstructor = ((PsiMethodCallExpression)expression).resolveMethod();
if (superConstructor != null && superConstructor.getBody() != null) {
usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression)expression));
continue;
if (constrBody != null) {
final PsiStatement[] statements = constrBody.getStatements();
if (statements.length > 0) {
final PsiStatement firstConstrStatement = statements[0];
if (firstConstrStatement instanceof PsiExpressionStatement) {
final PsiExpression expression = ((PsiExpressionStatement)firstConstrStatement).getExpression();
if (expression instanceof PsiMethodCallExpression) {
final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)expression).getMethodExpression();
if (methodExpression.getText().equals(PsiKeyword.SUPER)) {
final PsiMethod superConstructor = ((PsiMethodCallExpression)expression).resolveMethod();
if (superConstructor != null && superConstructor.getBody() != null) {
usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression)expression));
continue;
}
}
}
}
}
}
//insert implicit call to super
for (PsiMethod superConstructor : superConstructors) {
if (superConstructor.getParameterList().getParametersCount() == 0) {
@@ -274,50 +277,44 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
}
protected void performRefactoring(@NotNull final UsageInfo[] usages) {
final DocCommentPolicy docPolicy = new DocCommentPolicy(myPolicy);
new PushDownProcessor(mySuperClass, myMemberInfos, docPolicy) {
//push down conflicts are already collected
@Override
protected boolean showConflicts(@NotNull MultiMap<PsiElement, String> conflicts, UsageInfo[] usages) {
return true;
}
try {
final UsageInfo[] infos = ContainerUtil.map2Array(myTargetClasses, UsageInfo.class, new Function<PsiClass, UsageInfo>() {
@Override
public UsageInfo fun(PsiClass psiClass) {
return new UsageInfo(psiClass);
}
});
new PushDownProcessor(mySuperClass, myMemberInfos, new DocCommentPolicy(myPolicy)).pushDownToClasses(infos);
@Override
protected void performRefactoring(@NotNull UsageInfo[] pushDownUsages) {
if (myCurrentInheritor != null) {
pushDownToDedicatedClass(myCurrentInheritor);
} else {
super.performRefactoring(pushDownUsages);
}
CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages);
for (UsageInfo usageInfo : usages) {
if (!(usageInfo instanceof ReplaceExtendsListUsageInfo || usageInfo instanceof RemoveImportUsageInfo)) {
try {
((FixableUsageInfo)usageInfo).fixUsage();
}
catch (IncorrectOperationException e) {
LOG.info(e);
}
}
}
replaceInnerTypeUsages();
//postpone broken hierarchy
for (UsageInfo usage : usages) {
if (usage instanceof ReplaceExtendsListUsageInfo || usage instanceof RemoveImportUsageInfo) {
((FixableUsageInfo)usage).fixUsage();
}
}
if (myCurrentInheritor == null) {
CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages);
for (UsageInfo usageInfo : usages) {
if (!(usageInfo instanceof ReplaceExtendsListUsageInfo || usageInfo instanceof RemoveImportUsageInfo)) {
try {
mySuperClass.delete();
((FixableUsageInfo)usageInfo).fixUsage();
}
catch (IncorrectOperationException e) {
LOG.error(e);
LOG.info(e);
}
}
}
}.run();
replaceInnerTypeUsages();
//postpone broken hierarchy
for (UsageInfo usage : usages) {
if (usage instanceof ReplaceExtendsListUsageInfo || usage instanceof RemoveImportUsageInfo) {
((FixableUsageInfo)usage).fixUsage();
}
}
//delete the class if all refs replaced
if (myCurrentInheritor == null) {
mySuperClass.delete();
}
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
@Nullable
@@ -357,7 +354,7 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
public void visitTypeElement(final PsiTypeElement typeElement) {
super.visitTypeElement(typeElement);
final PsiType superClassType = typeElement.getType();
if (PsiUtil.resolveClassInType(superClassType) == mySuperClass) {
if (PsiUtil.resolveClassInClassTypeOnly(superClassType) == mySuperClass) {
PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass);
replacementMap.put(new UsageInfo(typeElement), elementFactory.createTypeElement(elementFactory.createType(targetClass, subst)));
}
@@ -370,8 +367,11 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori
if (PsiUtil.resolveClassInType(superClassType) == mySuperClass) {
PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass);
try {
replacementMap.put(new UsageInfo(expression), elementFactory.createExpressionFromText("new " + elementFactory.createType(
targetClass, subst).getCanonicalText() + expression.getArgumentList().getText(), expression));
final String typeCanonicalText = elementFactory.createType(targetClass, subst).getCanonicalText();
final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
if (classReference != null) {
replacementMap.put(new UsageInfo(classReference), elementFactory.createReferenceFromText(typeCanonicalText, expression));
}
}
catch (IncorrectOperationException e) {
LOG.error(e);
@@ -0,0 +1,9 @@
class Test {
public static Test[] getArray() {
return new Test[0];
}
public static Test[] getArrayWithInitializer() {
return new Test[]{};
}
}
@@ -0,0 +1,10 @@
class Super {
public static Super[] getArray() {
return new Super[0];
}
public static Super[] getArrayWithInitializer() {
return new Super[]{};
}
}
@@ -0,0 +1 @@
class Test extends Super {}
@@ -2,6 +2,6 @@ class Test {
private final String field;
Test(){
field = "text";
this.field = "text";
}
}
@@ -71,6 +71,7 @@ public class InlineSuperClassTest extends MultiFileTestCase {
public void testInterfaceHierarchyWithSubstitution() { doTest(); }
public void testTypeParameterBound() { doTest();}
public void testInlineInterfaceDoNotChangeConstructor() { doTest(); }
public void testArrayTypeElements() { doTest(); }
private void doTest() {
doTest(false, false);
@@ -16,7 +16,6 @@
package com.intellij.openapi.application;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.progress.ProcessCanceledException;
import org.jetbrains.annotations.NotNull;
@@ -29,7 +28,7 @@ import org.jetbrains.annotations.NotNull;
* and process UI events in other ways: it's guaranteed that no one will be able to sneak in with an unexpected model change using
* {@link javax.swing.SwingUtilities#invokeLater(Runnable)} or analogs.<p/>
*
* Transactions are run on UI thread. They have read access by default.<p/>
* Transactions are run on UI thread. They have read access by default. All write actions should be performed inside a transaction.<p/>
*
* The recommended way to perform a transaction is to invoke {@link #submitTransaction(Runnable)}. It either runs the transaction immediately
* (if on UI thread and there's no other transaction running) or queues it to invoke at some later moment, when it becomes possible.<p/>
@@ -40,31 +39,43 @@ import org.jetbrains.annotations.NotNull;
* the main transaction and executed immediately. Use {@link #acceptNestedTransactions(TransactionKind...)} for that. Inner transactions
* should be given some kind in such circumstances: {@link #submitMergeableTransaction(TransactionKind, Runnable)}.
*
* <p><h1>FAQ</h1></p>
*
* Q: I've got <b>"Write access is allowed from model transactions only"</b> exception, what do I do?<br/>
* A: Add a transaction somewhere into the call stack, to the outermost callee where having read/write model consistency is needed.
* If it's a user action, transaction should be synchronous (see {@link #startSynchronousTransaction(TransactionKind)}. For AnAction
* inheritors, {@link WrapInTransaction} annotation might be handy. Note that not all actions need to be wrapped into transactions, only
* those that require the model to be consistent. For example, actions that display settings dialogs or VCS actions are most likely exempt.
* <p/>
*
* If the exception occurs not inside a user action, it's probably from some kind of "invokeLater".
* Then, replace "invokeLater" with {@link #submitTransaction(Runnable)} or
* {@link #submitMergeableTransaction(TransactionKind, Runnable)} call.<p/>
*
* Q: I've got <b>"Nested transactions are not allowed"</b> exception, what do I do?<br/>
* A: First, find the place in the stack where the outer transaction is started. Then, see if there is any Swing event pumping
* in between two transactions (e.g. a dialog is shown). If not, one of two transactions is superfluous, remove it. If there
* is event pumping, check if the client code (e.g. the one showing the dialog) is prepared to the nested model modifications
* of the specified kinds. For example, refactoring dialogs might be prepared to {@link TransactionKind#TEXT_EDITING} kind
* (for text field editing inside the dialogs) but not
* other model changes, e.g. root changes. The outer transaction code might then specify which kinds it's prepared to (by using
* {@link #acceptNestedTransactions(TransactionKind...)}), and the inner transaction code should have the very same transaction kind
* (by using {@link #submitMergeableTransaction(TransactionKind, Runnable)} or {@link #startSynchronousTransaction(TransactionKind)}).
* If the nested transaction is not expected by the outer code, it must be made asynchronous by using either {@link #submitTransaction(Runnable)}
* or {@link #submitMergeableTransaction(TransactionKind, Runnable)}.
* <p/>
*
* Q: What's the difference between transactions and read/write actions and commands ({@link com.intellij.openapi.command.CommandProcessor})?<br/>
* A: Transactions are more abstract and can contain several write actions and even commands inside. Read/write actions guarantee that no
* one else will modify the model, while transactions allow for some modification, but in a way controlled by transaction kinds. Commands
* are used for tracking document changes for undo/redo functionality, so they're orthogonal to transactions.
*
* @see Application#runReadAction(Runnable)
* @see Application#runWriteAction(Runnable)
* @since 146.*
* @author peter
*/
public abstract class TransactionGuard {
/**
* This kind represents document modifications via editor actions, code completion and document->PSI commit.
* @see com.intellij.psi.PsiDocumentManager#commitDocument(Document)
*/
public static final TransactionKind TEXT_EDITING = new TransactionKind("TEXT_EDITING");
/**
* This kind represents any model modifications:
* <li>PSI or document changes
* <li>Virtual file system changes, e.g. files created/deleted/renamed/content-changed,
* caused by refresh process or explicit operations.
* <li>Project root set change
* <li>Dumb mode (reindexing) start/finish, (see {@link com.intellij.openapi.project.DumbService}).
*/
public static final TransactionKind ANY_CHANGE = new TransactionKind("ANY_CHANGE");
/**
* Transactions of this kind won't be merged into other transactions
*/
public static final TransactionKind NO_MERGE = new TransactionKind("NO_MERGE");
public static TransactionGuard getInstance() {
return ServiceManager.getService(TransactionGuard.class);
@@ -75,12 +86,12 @@ public abstract class TransactionGuard {
* The code will be run on Swing thread immediately or after all other queued transactions (if any) have been completed.<p/>
*
* For more advanced version, see {@link #submitMergeableTransaction(TransactionKind, Runnable)}.
* Transactions submitted via this method use {@link #NO_MERGE} kind.
* Transactions submitted via this method use {@link TransactionKind#NO_MERGE} kind.
*
* @param transaction code to execute inside a transaction.
*/
public static void submitTransaction(@NotNull Runnable transaction) {
getInstance().submitMergeableTransaction(NO_MERGE, transaction);
getInstance().submitMergeableTransaction(TransactionKind.NO_MERGE, transaction);
}
/**
@@ -110,7 +121,7 @@ public abstract class TransactionGuard {
* and executes the provided code immediately. Otherwise
* adds the runnable to a queue. When all transactions scheduled before this one are finished, executes the given
* runnable under a transaction.
* @param kind a kind object to enable transaction merging or {@link #NO_MERGE}, if no merging is required.
* @param kind a kind object to enable transaction merging or {@link TransactionKind#NO_MERGE}, if no merging is required.
* @param transaction code to execute inside a transaction.
*/
public abstract void submitMergeableTransaction(@NotNull TransactionKind kind, @NotNull Runnable transaction);
@@ -126,20 +137,4 @@ public abstract class TransactionGuard {
*/
@NotNull
public abstract AccessToken acceptNestedTransactions(TransactionKind... kinds);
/**
* A kind of transaction used in {@link #acceptNestedTransactions(TransactionKind...)}
*/
public static final class TransactionKind {
private final String myName;
public TransactionKind(@NotNull String name) {
myName = name;
}
@Override
public String toString() {
return myName;
}
}
}
@@ -0,0 +1,66 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.application;
import com.intellij.openapi.editor.Document;
/**
* A kind of transaction used in {@link TransactionGuard#submitMergeableTransaction(TransactionKind, Runnable)}
* and {@link TransactionGuard#acceptNestedTransactions(TransactionKind...)}.
*/
public interface TransactionKind {
/**
* Same as {@link Common#TEXT_EDITING}
*/
TransactionKind TEXT_EDITING = Common.TEXT_EDITING;
/**
* Same as {@link Common#NO_MERGE}
*/
TransactionKind NO_MERGE = Common.NO_MERGE;
/**
* Same as {@link Common#ANY_CHANGE}
*/
TransactionKind ANY_CHANGE = Common.ANY_CHANGE;
/**
* An auxiliary enum to make it possible to use transaction kinds in annotations
*/
enum Common implements TransactionKind {
/**
* This kind represents document modifications via editor actions, code completion and document->PSI commit.
* @see com.intellij.psi.PsiDocumentManager#commitDocument(Document)
*/
TEXT_EDITING,
/**
* This kind represents any model modifications:
* <li>PSI or document changes
* <li>Virtual file system changes, e.g. files created/deleted/renamed/content-changed,
* caused by refresh process or explicit operations.
* <li>Project root set change
* <li>Dumb mode (reindexing) start/finish, (see {@link com.intellij.openapi.project.DumbService}).
*/
ANY_CHANGE,
/**
* Transactions of this kind won't be merged into other transactions
*/
NO_MERGE
}
}
@@ -0,0 +1,22 @@
package com.intellij.openapi.application;
import java.lang.annotation.*;
/**
* Add this annotation to actions (AnAction inheritors) to make them run inside a transaction.
*
* @see TransactionGuard
* @since 146.*
* @author peter
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface WrapInTransaction {
/**
* @return the kind of transaction to wrap the action into. By default, it's {@link TransactionKind#NO_MERGE}.
*/
TransactionKind.Common value() default TransactionKind.Common.NO_MERGE;
}
@@ -39,7 +39,7 @@ public class TransactionGuardImpl extends TransactionGuard {
@NotNull
public AccessToken startSynchronousTransaction(@NotNull TransactionKind kind) throws IllegalStateException {
ApplicationManager.getApplication().assertIsDispatchThread();
if (kind != NO_MERGE && myMergeableKinds.contains(kind)) {
if (kind != TransactionKind.NO_MERGE && myMergeableKinds.contains(kind)) {
return AccessToken.EMPTY_ACCESS_TOKEN;
}
if (myInsideTransaction) {
@@ -68,7 +68,7 @@ public class TransactionGuardImpl extends TransactionGuard {
Runnable next = myQueue.poll();
if (next != null) {
runSyncTransaction(NO_MERGE, next);
runSyncTransaction(TransactionKind.NO_MERGE, next);
}
}
}, app.getDisposed());
@@ -95,7 +95,7 @@ public class TransactionGuardImpl extends TransactionGuard {
Runnable runnable = new Runnable() {
@Override
public void run() {
if (!myInsideTransaction || kind != NO_MERGE && myMergeableKinds.contains(kind)) {
if (!myInsideTransaction || kind != TransactionKind.NO_MERGE && myMergeableKinds.contains(kind)) {
runSyncTransaction(kind, transaction);
}
else {
@@ -35,6 +35,7 @@ import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.application.TransactionKind;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
@@ -476,7 +477,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
void disposeIndicator() {
// our offset map should be disposed under write action, so that duringCompletion (read action) won't access it after disposing
TransactionGuard.getInstance().submitMergeableTransaction(TransactionGuard.TEXT_EDITING, () ->
TransactionGuard.getInstance().submitMergeableTransaction(TransactionKind.TEXT_EDITING, () ->
ApplicationManager.getApplication().runWriteAction(() -> Disposer.dispose(this)));
}
@@ -416,6 +416,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
public abstract DocInfo getInfo();
public abstract boolean isValid(@NotNull Document document);
public abstract boolean isNavigatable();
public abstract void showDocInfo(@NotNull DocumentationManager docManager);
@@ -467,11 +469,15 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
public boolean isValid(@NotNull Document document) {
if (!myTargetElement.isValid()) return false;
if (!myElementAtPointer.isValid()) return false;
if (myTargetElement == myElementAtPointer) return false;
return rangesAreCorrect(document);
}
@Override
public boolean isNavigatable() {
return myTargetElement != myElementAtPointer && myTargetElement != myElementAtPointer.getParent();
}
@Override
public void showDocInfo(@NotNull DocumentationManager docManager) {
docManager.showJavaDocInfo(myTargetElement, myElementAtPointer, null);
@@ -499,6 +505,11 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
return rangesAreCorrect(document);
}
@Override
public boolean isNavigatable() {
return true;
}
@Override
public void showDocInfo(@NotNull DocumentationManager docManager) {
// Do nothing
@@ -612,6 +623,11 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
public boolean isValid(@NotNull Document document) {
return element.isValid();
}
@Override
public boolean isNavigatable() {
return true;
}
};
}
}
@@ -871,7 +887,9 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
}
else {
// highlighter already set
internalComponent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
if (info.isNavigatable()) {
internalComponent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
return;
}
}
@@ -960,11 +978,15 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
internalComponent.addKeyListener(myEditorKeyListener);
editor.getScrollingModel().addVisibleAreaListener(myVisibleAreaListener);
final Cursor cursor = internalComponent.getCursor();
internalComponent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
if (info.isNavigatable()) {
internalComponent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
myFileEditorManager.addFileEditorManagerListener(myFileEditorManagerListener);
List<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>();
TextAttributes attributes = myEditorColorsManager.getGlobalScheme().getAttributes(EditorColors.REFERENCE_HYPERLINK_COLOR);
TextAttributes attributes = info.isNavigatable()
? myEditorColorsManager.getGlobalScheme().getAttributes(EditorColors.REFERENCE_HYPERLINK_COLOR)
: new TextAttributes(null, HintUtil.INFORMATION_COLOR, null, null, Font.PLAIN);
for (TextRange range : info.getRanges()) {
TextAttributes attr = NavigationUtil.patchAttributesColor(attributes, range, editor);
final RangeHighlighter highlighter = editor.getMarkupModel().addRangeHighlighter(range.getStartOffset(), range.getEndOffset(),
@@ -225,6 +225,7 @@ public final class NavigationUtil {
*/
@SuppressWarnings("UseJBColor")
public static TextAttributes patchAttributesColor(TextAttributes attributes, @NotNull TextRange range, @NotNull Editor editor) {
if (attributes.getForegroundColor() == null && attributes.getEffectColor() == null) return attributes;
MarkupModel model = DocumentMarkupModel.forDocument(editor.getDocument(), editor.getProject(), false);
if (model != null) {
if (!((MarkupModelEx)model).processRangeHighlightersOverlappingWith(range.getStartOffset(), range.getEndOffset(),
@@ -159,25 +159,7 @@ public abstract class AbstractPushDownProcessor extends BaseRefactoringProcessor
@Override
protected void performRefactoring(@NotNull UsageInfo[] usages) {
try {
myDelegate.prepareToPush(myPushDownData);
final PsiElement sourceClass = myPushDownData.getSourceClass();
if (mySubClassData != null) {
final PsiElement subClass = myDelegate.createSubClass(sourceClass, mySubClassData);
if (subClass != null) {
myDelegate.pushDownToClass(subClass, myPushDownData);
}
}
else {
for (UsageInfo usage : usages) {
final PsiElement element = usage.getElement();
if (element != null) {
final PushDownDelegate targetDelegate = PushDownDelegate.findDelegateForTarget(sourceClass, element);
if (targetDelegate != null) {
targetDelegate.pushDownToClass(element, myPushDownData);
}
}
}
}
pushDownToClasses(usages);
myDelegate.removeFromSourceClass(myPushDownData);
}
catch (IncorrectOperationException e) {
@@ -185,8 +167,25 @@ public abstract class AbstractPushDownProcessor extends BaseRefactoringProcessor
}
}
protected void pushDownToDedicatedClass(PsiElement currentInheritor) {
public void pushDownToClasses(@NotNull UsageInfo[] usages) {
myDelegate.prepareToPush(myPushDownData);
myDelegate.pushDownToClass(currentInheritor, myPushDownData);
final PsiElement sourceClass = myPushDownData.getSourceClass();
if (mySubClassData != null) {
final PsiElement subClass = myDelegate.createSubClass(sourceClass, mySubClassData);
if (subClass != null) {
myDelegate.pushDownToClass(subClass, myPushDownData);
}
}
else {
for (UsageInfo usage : usages) {
final PsiElement element = usage.getElement();
if (element != null) {
final PushDownDelegate targetDelegate = PushDownDelegate.findDelegateForTarget(sourceClass, element);
if (targetDelegate != null) {
targetDelegate.pushDownToClass(element, myPushDownData);
}
}
}
}
}
}
@@ -15,10 +15,7 @@
*/
package com.intellij.notification;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
@@ -28,6 +25,7 @@ import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.reference.SoftReference;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -41,6 +39,7 @@ import java.util.List;
*/
public class Notification {
private static final Logger LOG = Logger.getInstance("#com.intellij.notification.Notification");
private static final DataKey<Notification> KEY = DataKey.create("Notification");
private final String myGroupId;
private Icon myIcon;
@@ -195,8 +194,20 @@ public class Notification {
return ContainerUtil.notNullize(myActions);
}
public static void fire(@NotNull AnAction action) {
AnActionEvent event = AnActionEvent.createFromAnAction(action, null, ActionPlaces.UNKNOWN, DataContext.EMPTY_CONTEXT);
@NotNull
public static Notification get(@NotNull AnActionEvent e) {
//noinspection ConstantConditions
return e.getData(KEY);
}
public static void fire(@NotNull final Notification notification, @NotNull AnAction action) {
AnActionEvent event = AnActionEvent.createFromAnAction(action, null, ActionPlaces.UNKNOWN, new DataContext() {
@Nullable
@Override
public Object getData(@NonNls String dataId) {
return KEY.getName().equals(dataId) ? notification : null;
}
});
if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) {
ActionUtil.performActionDumbAware(action, event);
}
@@ -0,0 +1,37 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.notification;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Alexander Lobas
*/
public abstract class NotificationAction extends AnAction {
public NotificationAction(@Nullable String text) {
super(text);
}
@Override
public void actionPerformed(AnActionEvent e) {
actionPerformed(e, Notification.get(e));
}
public abstract void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification);
}
@@ -16,7 +16,10 @@
package com.intellij.openapi.actionSystem.ex;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.application.WrapInTransaction;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
@@ -187,12 +190,18 @@ public class ActionUtil {
}
public static void performActionDumbAware(AnAction action, AnActionEvent e) {
WrapInTransaction annotation = action.getClass().getAnnotation(WrapInTransaction.class);
AccessToken token = annotation == null ? AccessToken.EMPTY_ACCESS_TOKEN
: TransactionGuard.getInstance().startSynchronousTransaction(annotation.value());
try {
action.actionPerformed(e);
}
catch (IndexNotReadyException e1) {
showDumbModeWarning(e);
}
finally {
token.finish();
}
}
@NotNull
@@ -134,7 +134,7 @@ public class EventLog {
Notification n = new Notification("", "", ".", NotificationType.INFORMATION, new NotificationListener() {
@Override
public void hyperlinkUpdate(@NotNull Notification n, @NotNull HyperlinkEvent event) {
Notification.fire(notification.getActions().get(Integer.parseInt(event.getDescription())));
Notification.fire(notification, notification.getActions().get(Integer.parseInt(event.getDescription())));
}
});
if (title.length() > 0 || content.length() > 0) {
@@ -729,7 +729,7 @@ public class NotificationsManagerImpl extends NotificationsManager {
return balloon;
}
private static void createActionPanel(@NotNull Notification notification, @NotNull JPanel centerPanel, int gap) {
private static void createActionPanel(@NotNull final Notification notification, @NotNull JPanel centerPanel, int gap) {
JPanel actionPanel = new NonOpaquePanel(new HorizontalLayout(gap, SwingConstants.CENTER));
centerPanel.add(BorderLayout.SOUTH, actionPanel);
@@ -763,7 +763,7 @@ public class NotificationsManagerImpl extends NotificationsManager {
new LinkLabel<AnAction>(presentation.getText(), presentation.getIcon(), new LinkListener<AnAction>() {
@Override
public void linkSelected(LinkLabel aSource, AnAction action) {
Notification.fire(action);
Notification.fire(notification, action);
}
}, action));
}
@@ -23,9 +23,7 @@ import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.actionSystem.impl.PresentationFactory;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.*;
import com.intellij.openapi.keymap.KeyMapBundle;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
@@ -592,7 +590,7 @@ public final class IdeKeyEventDispatcher implements Disposable {
.showInBestPositionFor(ctx);
}
else {
action.actionPerformed(actionEvent);
ActionUtil.performActionDumbAware(action, actionEvent);
}
if (Registry.is("actionSystem.fixLostTyping")) {
@@ -98,6 +98,7 @@ abstract class ShortcutDialog<T extends Shortcut> extends DialogWrapper {
}
}
myConflictsPanel.revalidate();
myConflictsPanel.repaint();
}
myConflictsPanel.setVisible(0 < myConflictsContainer.getComponentCount());
}
@@ -858,7 +858,7 @@ public class PopupFactoryImpl extends JBPopupFactory {
ActionManager.getInstance(), modifiers);
event.setInjectedContext(action.isInInjectedContext());
if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) {
action.actionPerformed(event);
ActionUtil.performActionDumbAware(action, event);
}
}
+16 -1
View File
@@ -139,7 +139,22 @@ public class Patches {
/**
* On Mac OS font ligatures are not supported for natively loaded fonts, font needs to be loaded explicitly by JDK.
*/
public static final boolean JDK_BUG_ID_7162125 = SystemInfo.isMac && !SystemInfo.isJavaVersionAtLeast("1.9");
public static final boolean JDK_BUG_ID_7162125;
static {
boolean value;
if (!SystemInfo.isMac || SystemInfo.isJavaVersionAtLeast("1.9")) value = false;
else if (!SystemInfo.isJetbrainsJvm) value = true;
else {
try {
Class.forName("sun.font.CCompositeFont");
value = Boolean.getBoolean("disable.font.substitution");
}
catch (Throwable e) {
value = true;
}
}
JDK_BUG_ID_7162125 = value;
}
/**
* XToolkit.getScreenInsets() may be very slow.
@@ -45,6 +45,7 @@
<extensionPoints>
<extensionPoint qualifiedName="Edu.CCLanguageManager" beanClass="com.intellij.lang.LanguageExtensionPoint">
<with attribute="implementationClass" implements="com.jetbrains.edu.coursecreator.CCLanguageManager"/>
</extensionPoint>
</extensionPoints>
@@ -30,8 +30,12 @@
</project-components>
<extensionPoints>
<extensionPoint qualifiedName="Edu.StudyExecutor" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint qualifiedName="Edu.StudyLanguageManager" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint qualifiedName="Edu.StudyExecutor" beanClass="com.intellij.lang.LanguageExtensionPoint">
<with attribute="implementationClass" implements="com.jetbrains.edu.learning.checker.StudyExecutor"/>
</extensionPoint>
<extensionPoint qualifiedName="Edu.StudyLanguageManager" beanClass="com.intellij.lang.LanguageExtensionPoint">
<with attribute="implementationClass" implements="com.jetbrains.edu.learning.StudyLanguageManager"/>
</extensionPoint>
<extensionPoint qualifiedName="Edu.studyToolWindowConfigurator" interface="com.jetbrains.edu.learning.StudyToolWindowConfigurator"/>
</extensionPoints>