Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2016-04-11 18:06:32 +02:00
13 changed files with 205 additions and 86 deletions
@@ -626,6 +626,13 @@
<option name="EFFECT_TYPE" value="1" />
</value>
</option>
<option name="CTRL_CLICKABLE">
<value>
<option name="FOREGROUND" value="589df6" />
<option name="EFFECT_COLOR" value="589df6" />
<option name="EFFECT_TYPE" value="1" />
</value>
</option>
<option name="First symbol in list">
<value>
<option name="FONT_TYPE" value="1" />
@@ -149,7 +149,7 @@ public class ArtifactEditorContextImpl implements ArtifactEditorContext {
@Override
public List<Artifact> chooseArtifacts(final List<? extends Artifact> artifacts, final String title) {
ChooseArtifactsDialog dialog = new ChooseArtifactsDialog(getProject(), artifacts, title, null);
return dialog.showAndGet() ? dialog.getChosenElements() : Collections.<Artifact>emptyList();
return dialog.showAndGet() ? dialog.getChosenElements() : Collections.emptyList();
}
@@ -201,7 +201,7 @@ public class ArtifactEditorContextImpl implements ArtifactEditorContext {
@Override
public List<Library> chooseLibraries(final String title) {
final ChooseLibrariesFromTablesDialog dialog = ChooseLibrariesFromTablesDialog.createDialog(title, getProject(), false);
return dialog.showAndGet() ? dialog.getSelectedLibraries() : Collections.<Library>emptyList();
return dialog.showAndGet() ? dialog.getSelectedLibraries() : Collections.emptyList();
}
@Override
@@ -26,6 +26,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
@@ -145,34 +146,23 @@ class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool {
PsiDirectory memberDirectory = memberFile.getContainingDirectory();
final PsiPackage memberPackage = memberDirectory == null ? null : JavaDirectoryService.getInstance().getPackage(memberDirectory);
log(member.getName()+ ": checking effective level for "+member);
boolean result =
UnusedSymbolUtil.processUsages(project, memberFile, member, new EmptyProgressIndicator(), null, info -> {
foundUsage.set(true);
PsiFile psiFile = info.getFile();
if (psiFile == null) return true;
if (!(psiFile instanceof PsiJavaFile)) {
log(" refd from " + psiFile.getName() + "; set to public");
maxLevel.set(PsiUtil.ACCESS_LEVEL_PUBLIC);
if (memberClass != null) {
childMembersAreUsedOutsideMyPackage.add(memberClass);
}
return false; // referenced from XML, has to be public
}
//int offset = info.getNavigationOffset();
//if (offset == -1) return true;
PsiElement element = info.getElement();
if (element == null) return true;
@PsiUtil.AccessLevel
int level = getEffectiveLevel(element, psiFile, member, memberFile, memberClass, memberPackage);
log(" ref in file " + psiFile.getName() + "; level = " + PsiUtil.getAccessModifier(level) + "; (" + element + ")");
maxLevel.getAndAccumulate(level, Math::max);
if (level == PsiUtil.ACCESS_LEVEL_PUBLIC && memberClass != null) {
childMembersAreUsedOutsideMyPackage.add(memberClass);
}
return level != PsiUtil.ACCESS_LEVEL_PUBLIC;
UnusedSymbolUtil.processUsages(project, memberFile, member, new EmptyProgressIndicator(), null, info -> {
PsiElement element = info.getElement();
if (element == null) return true;
PsiFile psiFile = info.getFile();
if (psiFile == null) return true;
return handleUsage(member, memberClass, memberFile, maxLevel, memberPackage, element, psiFile, foundUsage);
});
if (member instanceof PsiClass && ((PsiClass)member).isInterface()) {
// there can be lambda implementing this interface implicitly
FunctionalExpressionSearch.search((PsiClass)member).forEach(functionalExpression -> {
PsiFile psiFile = functionalExpression.getContainingFile();
return handleUsage(member, memberClass, memberFile, maxLevel, memberPackage, functionalExpression, psiFile, foundUsage);
});
}
if (!foundUsage.get()) {
log(member.getName() + " unused; ignore");
return; // do not propose private for unused method
@@ -199,6 +189,36 @@ class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool {
}
}
private boolean handleUsage(@NotNull PsiMember member,
@Nullable PsiClass memberClass,
@NotNull PsiFile memberFile,
@NotNull AtomicInteger maxLevel,
@Nullable PsiPackage memberPackage,
@NotNull PsiElement element,
@NotNull PsiFile psiFile,
@NotNull AtomicBoolean foundUsage) {
foundUsage.set(true);
if (!(psiFile instanceof PsiJavaFile)) {
log(" refd from " + psiFile.getName() + "; set to public");
maxLevel.set(PsiUtil.ACCESS_LEVEL_PUBLIC);
if (memberClass != null) {
childMembersAreUsedOutsideMyPackage.add(memberClass);
}
return false; // referenced from XML, has to be public
}
//int offset = info.getNavigationOffset();
//if (offset == -1) return true;
@PsiUtil.AccessLevel
int level = getEffectiveLevel(element, psiFile, member, memberFile, memberClass, memberPackage);
log(" ref in file " + psiFile.getName() + "; level = " + PsiUtil.getAccessModifier(level) + "; (" + element + ")");
maxLevel.getAndAccumulate(level, Math::max);
if (level == PsiUtil.ACCESS_LEVEL_PUBLIC && memberClass != null) {
childMembersAreUsedOutsideMyPackage.add(memberClass);
}
return level != PsiUtil.ACCESS_LEVEL_PUBLIC;
}
@PsiUtil.AccessLevel
private int getEffectiveLevel(@NotNull PsiElement element,
@NotNull PsiFile file,
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -22,7 +22,7 @@ public interface PsiFunctionalExpression extends PsiExpression, Iconable, Naviga
PsiFunctionalExpression[] EMPTY_ARRAY = new PsiFunctionalExpression[0];
/**
* @return SAM type the lambda expression corresponds to
* null when no SAM type could be found
* or null when no SAM type could be found
*/
@Nullable
PsiType getFunctionalInterfaceType();
@@ -38,6 +38,7 @@ import com.intellij.internal.statistic.UsageTrigger;
import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -276,7 +277,7 @@ public abstract class DiffRequestProcessor implements Disposable {
myToolbarStatusPanel.setContent(null);
myToolbarPanel.setContent(null);
myContentPanel.setContent(null);
myMainPanel.putClientProperty(AnAction.ourClientProperty, null);
ActionUtil.clearActions(myMainPanel);
myActiveRequest.onAssigned(false);
myActiveRequest = request;
@@ -27,6 +27,7 @@ import com.intellij.ide.DataManager;
import com.intellij.ide.impl.DataManagerImpl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.BooleanGetter;
@@ -135,7 +136,7 @@ public abstract class MergeRequestProcessor implements Disposable {
private void destroyViewer() {
Disposer.dispose(myViewer);
myMainPanel.putClientProperty(AnAction.ourClientProperty, null);
ActionUtil.clearActions(myMainPanel);
myContentPanel.setContent(null);
myToolbarPanel.setContent(null);
@@ -21,9 +21,10 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.PossiblyDumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.util.SmartList;
import com.intellij.util.ui.UIUtil;
import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -66,15 +67,13 @@ import java.util.List;
public abstract class AnAction implements PossiblyDumbAware {
private static final Logger LOG = Logger.getInstance(AnAction.class);
public static final Key<List<AnAction>> ACTIONS_KEY = Key.create("AnAction.shortcutSet");
public static final AnAction[] EMPTY_ARRAY = new AnAction[0];
@NonNls public static final String ourClientProperty = "AnAction.shortcutSet";
private Presentation myTemplatePresentation;
private ShortcutSet myShortcutSet;
private boolean myEnabledInModalContext;
private static final ShortcutSet ourEmptyShortcutSet = new CustomShortcutSet();
private boolean myIsDefaultIcon = true;
private boolean myWorksInInjected;
private boolean myIsGlobal; // action is registered in ActionManager
@@ -119,7 +118,7 @@ public abstract class AnAction implements PossiblyDumbAware {
* @param icon Action's icon
*/
public AnAction(@Nullable String text, @Nullable String description, @Nullable Icon icon){
myShortcutSet = ourEmptyShortcutSet;
myShortcutSet = CustomShortcutSet.EMPTY;
myEnabledInModalContext = false;
Presentation presentation = getTemplatePresentation();
presentation.setText(text);
@@ -152,37 +151,35 @@ public abstract class AnAction implements PossiblyDumbAware {
registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(keyCode, modifiers)), component);
}
public final void registerCustomShortcutSet(@NotNull ShortcutSet shortcutSet, @Nullable final JComponent component, @Nullable Disposable parentDisposable) {
public final void registerCustomShortcutSet(@NotNull ShortcutSet shortcutSet, @Nullable JComponent component, @Nullable Disposable parentDisposable) {
setShortcutSet(shortcutSet);
if (component != null){
@SuppressWarnings("unchecked")
List<AnAction> actionList = (List<AnAction>)component.getClientProperty(ourClientProperty);
if (actionList == null){
actionList = new SmartList<AnAction>();
component.putClientProperty(ourClientProperty, actionList);
}
if (!actionList.contains(this)){
actionList.add(this);
}
registerCustomShortcutSet(component, parentDisposable);
}
if (parentDisposable != null) {
Disposer.register(parentDisposable, new Disposable() {
@Override
public void dispose() {
unregisterCustomShortcutSet(component);
}
});
}
public final void registerCustomShortcutSet(@Nullable JComponent component, @Nullable Disposable parentDisposable) {
if (component == null) return;
List<AnAction> actionList = UIUtil.getClientProperty(component, ACTIONS_KEY);
if (actionList == null) {
UIUtil.putClientProperty(component, ACTIONS_KEY, actionList = new SmartList<AnAction>());
}
if (!actionList.contains(this)) {
actionList.add(this);
}
if (parentDisposable != null) {
Disposer.register(parentDisposable, new Disposable() {
@Override
public void dispose() {
unregisterCustomShortcutSet(component);
}
});
}
}
public final void unregisterCustomShortcutSet(JComponent component){
if (component != null){
@SuppressWarnings("unchecked")
List<AnAction> actionList = (List<AnAction>)component.getClientProperty(ourClientProperty);
if (actionList != null){
actionList.remove(this);
}
public final void unregisterCustomShortcutSet(@Nullable JComponent component) {
List<AnAction> actionList = UIUtil.getClientProperty(component, ACTIONS_KEY);
if (actionList != null) {
actionList.remove(this);
}
}
@@ -26,6 +26,9 @@ import javax.swing.*;
*/
public final class CustomShortcutSet implements ShortcutSet {
public static final CustomShortcutSet EMPTY = new CustomShortcutSet(Shortcut.EMPTY_ARRAY);
private final Shortcut[] myShortcuts;
/**
@@ -36,10 +39,6 @@ public final class CustomShortcutSet implements ShortcutSet {
this(new KeyboardShortcut(keyStroke, null));
}
public CustomShortcutSet() {
myShortcuts = Shortcut.EMPTY_ARRAY;
}
/**
* Creates <code>CustomShortcutSet</code> which contains specified keyboard and
* mouse shortcuts.
@@ -127,31 +127,33 @@ public class CapturingProcessHandler extends OSProcessHandler {
public ProcessOutput runProcessWithProgressIndicator(@NotNull ProgressIndicator indicator, int timeoutInMilliseconds, boolean destroyOnTimeout) {
final int WAIT_INTERVAL = 100;
int waitingTime = 0;
boolean destroying = false;
boolean setExitCode = true;
startNotify();
while (!waitFor(WAIT_INTERVAL)) {
waitingTime += WAIT_INTERVAL;
boolean timeout = waitingTime >= timeoutInMilliseconds;
boolean canceled = indicator.isCanceled();
if (indicator.isCanceled() || timeout) {
destroying = !timeout || destroyOnTimeout;
if (canceled || timeout) {
boolean destroying = canceled || destroyOnTimeout;
setExitCode = destroying;
if (destroying && !isProcessTerminating() && !isProcessTerminated()) {
destroyProcess();
}
if (timeout) {
myOutput.setTimeout();
if (canceled) {
myOutput.setCancelled();
}
else {
myOutput.setCancelled();
myOutput.setTimeout();
}
break;
}
}
if (destroying) {
if (setExitCode) {
if (waitFor()) {
myOutput.setExitCode(getProcess().exitValue());
}
@@ -62,15 +62,11 @@ public final class EmptyAction extends AnAction {
}
public static void setupAction(@NotNull AnAction action, @NotNull String id, @Nullable JComponent component) {
final AnAction emptyAction = ActionManager.getInstance().getAction(id);
action.copyFrom(emptyAction);
action.registerCustomShortcutSet(action.getShortcutSet(), component);
ActionUtil.mergeFrom(action, id).registerCustomShortcutSet(component, null);
}
public static void registerActionShortcuts(JComponent component, final JComponent fromComponent) {
for (AnAction anAction : ActionUtil.getActions(fromComponent)) {
anAction.registerCustomShortcutSet(anAction.getShortcutSet(), component);
}
public static void registerActionShortcuts(@NotNull JComponent component, @NotNull JComponent fromComponent) {
ActionUtil.copyRegisteredShortcuts(component, fromComponent);
}
/**
@@ -22,7 +22,9 @@ import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PausesStat;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -197,9 +199,17 @@ public class ActionUtil {
@NotNull
public static List<AnAction> getActions(@NotNull JComponent component) {
Object property = component.getClientProperty(AnAction.ourClientProperty);
//noinspection unchecked
return property == null ? Collections.<AnAction>emptyList() : (List<AnAction>)property;
return ObjectUtils.notNull(UIUtil.getClientProperty(component, AnAction.ACTIONS_KEY), Collections.emptyList());
}
public static void clearActions(@NotNull JComponent component) {
UIUtil.putClientProperty(component, AnAction.ACTIONS_KEY, null);
}
public static void copyRegisteredShortcuts(@NotNull JComponent to, @NotNull JComponent from) {
for (AnAction anAction : getActions(from)) {
anAction.registerCustomShortcutSet(anAction.getShortcutSet(), to);
}
}
public static void registerForEveryKeyboardShortcut(@NotNull JComponent component,
@@ -216,4 +226,41 @@ public class ActionUtil {
}
}
}
/**
* Convenience method for copying properties from a registered action
*
* @param actionId action id
*/
public static AnAction copyFrom(@NotNull AnAction action, @NotNull String actionId) {
action.copyFrom(ActionManager.getInstance().getAction(actionId));
return action;
}
/**
* Convenience method for merging not null properties from a registered action
*
* @param action action to merge to
* @param actionId action id to merge from
*/
public static AnAction mergeFrom(@NotNull AnAction action, @NotNull String actionId) {
//noinspection UnnecessaryLocalVariable
AnAction a1 = action;
AnAction a2 = ActionManager.getInstance().getAction(actionId);
Presentation p1 = a1.getTemplatePresentation();
Presentation p2 = a2.getTemplatePresentation();
p1.setIcon(ObjectUtils.chooseNotNull(p1.getIcon(), p2.getIcon()));
p1.setDisabledIcon(ObjectUtils.chooseNotNull(p1.getDisabledIcon(), p2.getDisabledIcon()));
p1.setSelectedIcon(ObjectUtils.chooseNotNull(p1.getSelectedIcon(), p2.getSelectedIcon()));
p1.setHoveredIcon(ObjectUtils.chooseNotNull(p1.getHoveredIcon(), p2.getHoveredIcon()));
if (StringUtil.isEmpty(p1.getText())) {
p1.setText(p2.getTextWithMnemonic(), p2.getDisplayedMnemonicIndex() >= 0);
}
p1.setDescription(ObjectUtils.chooseNotNull(p1.getDescription(), p2.getDescription()));
ShortcutSet ss1 = a1.getShortcutSet();
if (ss1 == null || ss1 == CustomShortcutSet.EMPTY) {
a1.copyShortcutFrom(a2);
}
return a1;
}
}
@@ -1122,8 +1122,10 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
assertNoPsiLock();
if (!myLock.tryWriteLock()) {
Future<?> reportSlowWrite = ourDumpThreadsOnLongWriteActionWaiting > 0 ?
JobScheduler.getScheduler().scheduleWithFixedDelay(() -> PerformanceWatcher.getInstance().dumpThreads("waiting", true),
ourDumpThreadsOnLongWriteActionWaiting, ourDumpThreadsOnLongWriteActionWaiting, TimeUnit.MILLISECONDS) : null;
JobScheduler.getScheduler()
.scheduleWithFixedDelay(() -> PerformanceWatcher.getInstance().dumpThreads("waiting", true),
ourDumpThreadsOnLongWriteActionWaiting,
ourDumpThreadsOnLongWriteActionWaiting, TimeUnit.MILLISECONDS) : null;
myLock.writeLock();
if (reportSlowWrite != null) {
reportSlowWrite.cancel(false);
@@ -128,6 +128,53 @@ public class AccessCanBeTightenedInspectionTest extends LightInspectionTestCase
"}");
}
public void testStupidTwoPublicClassesInTheSamePackage() {
myFixture.allowTreeAccessForAllFiles();
myFixture.addFileToProject("x/Sub.java",
"package x; " +
"public class Sub {\n" +
" Object o = new C();\n" +
"}\n" +
"");
myFixture.addFileToProject("x/C.java",
"package x; \n" +
"<warning descr=\"Access can be package-private\">public</warning> class C {\n" +
"}");
myFixture.configureByFiles("x/C.java", "x/Sub.java");
myFixture.checkHighlighting();
}
public void testInterfaceIsImplementedByLambda() {
myFixture.allowTreeAccessForAllFiles();
myFixture.addFileToProject("x/MyInterface.java",
"package x;\n" +
"public interface MyInterface {\n" +
" void doStuff();\n" +
"}\n" +
"");
myFixture.addFileToProject("x/MyConsumer.java",
"package x;\n" +
"public class MyConsumer {\n" +
" public void doIt(MyInterface i) {\n" +
" i.doStuff();\n" +
" }\n" +
"}" +
"");
myFixture.addFileToProject("y/Test.java",
"package y;\n" +
"\n" +
"import x.MyConsumer;\n" +
"\n" +
"public class Test {\n" +
" void ddd(MyConsumer consumer) {\n" +
" consumer.doIt(() -> {});\n" +
" }\n" +
"}" +
"");
myFixture.configureByFiles("x/MyInterface.java", "y/Test.java", "x/MyConsumer.java");
myFixture.checkHighlighting();
}
@Override
protected LocalInspectionTool getInspection() {
VisibilityInspection inspection = new VisibilityInspection();