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:
+3
-1
@@ -195,7 +195,9 @@ public class HighlightMethodUtil {
|
||||
|
||||
if (returnType.equals(substitutedSuperReturnType)) return null;
|
||||
if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType) {
|
||||
if (isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) {
|
||||
if (isJdk15 && LambdaUtil.performWithSubstitutedParameterBounds(methodSignature.getTypeParameters(),
|
||||
methodSignature.getSubstitutor(),
|
||||
() -> TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,22 +16,35 @@
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.HardcodedContracts;
|
||||
import com.intellij.codeInspection.dataFlow.Nullness;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.DefaultJDOMExternalizer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.model.serialization.java.compiler.JpsJavaCompilerNotNullableSerializer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@State(name = "NullableNotNullManager")
|
||||
public class NullableNotNullManagerImpl extends NullableNotNullManager implements PersistentStateComponent<Element> {
|
||||
|
||||
public NullableNotNullManagerImpl() {
|
||||
public static final String TYPE_QUALIFIER_NICKNAME = "javax.annotation.meta.TypeQualifierNickname";
|
||||
|
||||
public NullableNotNullManagerImpl(Project project) {
|
||||
super(project);
|
||||
myNotNulls.addAll(getPredefinedNotNulls());
|
||||
}
|
||||
|
||||
@@ -80,4 +93,64 @@ public class NullableNotNullManagerImpl extends NullableNotNullManager implement
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<PsiClass> getAllNullabilityNickNames() {
|
||||
if (!getNotNulls().contains(JAVAX_ANNOTATION_NONNULL)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return CachedValuesManager.getManager(myProject).getCachedValue(myProject, () -> {
|
||||
List<PsiClass> result = new ArrayList<>();
|
||||
GlobalSearchScope scope = GlobalSearchScope.allScope(myProject);
|
||||
for (PsiClass tqNick : JavaPsiFacade.getInstance(myProject).findClasses(TYPE_QUALIFIER_NICKNAME, scope)) {
|
||||
result.addAll(ContainerUtil.findAll(MetaAnnotationUtil.getChildren(tqNick, scope), candidate -> {
|
||||
String qname = candidate.getQualifiedName();
|
||||
if (qname == null || qname.startsWith("javax.annotation.")) return false;
|
||||
return getNickNamedNullability(candidate) != Nullness.UNKNOWN;
|
||||
}));
|
||||
}
|
||||
return CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
});
|
||||
}
|
||||
|
||||
private static Nullness getNickNamedNullability(@NotNull PsiClass psiClass) {
|
||||
if (AnnotationUtil.findAnnotation(psiClass, TYPE_QUALIFIER_NICKNAME) == null) return Nullness.UNKNOWN;
|
||||
|
||||
PsiAnnotation nonNull = AnnotationUtil.findAnnotation(psiClass, JAVAX_ANNOTATION_NONNULL);
|
||||
return nonNull != null ? extractNullityFromWhenValue(nonNull) : Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Nullness extractNullityFromWhenValue(PsiAnnotation nonNull) {
|
||||
PsiAnnotationMemberValue when = nonNull.findAttributeValue("when");
|
||||
if (when instanceof PsiReferenceExpression) {
|
||||
String refName = ((PsiReferenceExpression)when).getReferenceName();
|
||||
if ("ALWAYS".equals(refName)) {
|
||||
return Nullness.NOT_NULL;
|
||||
}
|
||||
if ("MAYBE".equals(refName) || "NEVER".equals(refName)) {
|
||||
return Nullness.NULLABLE;
|
||||
}
|
||||
}
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
private List<String> filterNickNames(Nullness nullness) {
|
||||
return StreamEx.of(getAllNullabilityNickNames()).filter(c -> getNickNamedNullability(c) == nullness).map(PsiClass::getQualifiedName).toList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<String> getNullablesWithNickNames() {
|
||||
return CachedValuesManager.getManager(myProject).getCachedValue(myProject, () ->
|
||||
CachedValueProvider.Result.create(ContainerUtil.concat(getNullables(), filterNickNames(Nullness.NULLABLE)),
|
||||
PsiModificationTracker.MODIFICATION_COUNT));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<String> getNotNullsWithNickNames() {
|
||||
return CachedValuesManager.getManager(myProject).getCachedValue(myProject, () ->
|
||||
CachedValueProvider.Result.create(ContainerUtil.concat(getNotNulls(), filterNickNames(Nullness.NOT_NULL)),
|
||||
PsiModificationTracker.MODIFICATION_COUNT));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator;
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation;
|
||||
import com.intellij.codeInsight.lookup.TypedLookupItem;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.ClassConditionKey;
|
||||
import com.intellij.openapi.util.Key;
|
||||
@@ -39,19 +38,23 @@ import java.util.Set;
|
||||
*/
|
||||
public class JavaChainLookupElement extends LookupElementDecorator<LookupElement> implements TypedLookupItem {
|
||||
public static final Key<Boolean> CHAIN_QUALIFIER = Key.create("CHAIN_QUALIFIER");
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.JavaChainLookupElement");
|
||||
public static final ClassConditionKey<JavaChainLookupElement> CLASS_CONDITION_KEY = ClassConditionKey.create(JavaChainLookupElement.class);
|
||||
private final LookupElement myQualifier;
|
||||
private final String mySeparator;
|
||||
|
||||
public JavaChainLookupElement(LookupElement qualifier, LookupElement main) {
|
||||
this(qualifier, main, ".");
|
||||
}
|
||||
public JavaChainLookupElement(LookupElement qualifier, LookupElement main, String separator) {
|
||||
super(main);
|
||||
myQualifier = qualifier;
|
||||
mySeparator = separator;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getLookupString() {
|
||||
return maybeAddParentheses(myQualifier.getLookupString()) + "." + getDelegate().getLookupString();
|
||||
return maybeAddParentheses(myQualifier.getLookupString()) + mySeparator + getDelegate().getLookupString();
|
||||
}
|
||||
|
||||
public LookupElement getQualifier() {
|
||||
@@ -70,7 +73,7 @@ public class JavaChainLookupElement extends LookupElementDecorator<LookupElement
|
||||
@NotNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return maybeAddParentheses(myQualifier.toString()) + "." + getDelegate();
|
||||
return maybeAddParentheses(myQualifier.toString()) + mySeparator + getDelegate();
|
||||
}
|
||||
|
||||
private String maybeAddParentheses(String s) {
|
||||
@@ -98,7 +101,7 @@ public class JavaChainLookupElement extends LookupElementDecorator<LookupElement
|
||||
myQualifier.renderElement(qualifierPresentation);
|
||||
String name = maybeAddParentheses(qualifierPresentation.getItemText());
|
||||
final String qualifierText = myQualifier.as(CastingLookupElementDecorator.CLASS_CONDITION_KEY) != null ? "(" + name + ")" : name;
|
||||
presentation.setItemText(qualifierText + "." + presentation.getItemText());
|
||||
presentation.setItemText(qualifierText + mySeparator + presentation.getItemText());
|
||||
|
||||
if (myQualifier instanceof JavaPsiClassReferenceElement) {
|
||||
presentation.appendTailText(((JavaPsiClassReferenceElement)myQualifier).getLocationString(), false);
|
||||
@@ -129,9 +132,9 @@ public class JavaChainLookupElement extends LookupElementDecorator<LookupElement
|
||||
if (atTail != ';') {
|
||||
return;
|
||||
}
|
||||
document.replaceString(qualifierContext.getTailOffset(), qualifierContext.getTailOffset() + 1, ".");
|
||||
document.replaceString(qualifierContext.getTailOffset(), qualifierContext.getTailOffset() + 1, mySeparator);
|
||||
|
||||
CompletionUtil.emulateInsertion(getDelegate(), qualifierContext.getTailOffset() + 1, context);
|
||||
CompletionUtil.emulateInsertion(getDelegate(), qualifierContext.getTailOffset() + mySeparator.length(), context);
|
||||
context.commitDocument();
|
||||
|
||||
int formatStart = context.getOffset(oldStart);
|
||||
|
||||
@@ -145,11 +145,12 @@ public class JavaNoVariantsDelegator extends CompletionContributor {
|
||||
for (LookupElement base : suggestQualifierItems(parameters, (PsiJavaCodeReferenceElement)qualifier, filter)) {
|
||||
PsiType type = JavaCompletionUtil.getLookupElementType(base);
|
||||
if (type != null && !PsiType.VOID.equals(type)) {
|
||||
PsiReferenceExpression ref = ReferenceExpressionCompletionContributor.createMockReference(position, type, base);
|
||||
String separator = parent instanceof PsiMethodReferenceExpression ? "::" : ".";
|
||||
PsiReferenceExpression ref = ReferenceExpressionCompletionContributor.createMockReference(position, type, base, separator);
|
||||
if (ref != null) {
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(position, ref, filter, true, true, parameters,
|
||||
result.getPrefixMatcher())) {
|
||||
qualifiedCollector.addElement(JavaCompletionUtil.highlightIfNeeded(null, new JavaChainLookupElement(base, item), item.getObject(), position));
|
||||
for (LookupElement item : JavaSmartCompletionContributor.completeReference(position, ref, filter, true, true, parameters,
|
||||
result.getPrefixMatcher())) {
|
||||
qualifiedCollector.addElement(JavaCompletionUtil.highlightIfNeeded(null, new JavaChainLookupElement(base, item, separator), item.getObject(), position));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-3
@@ -213,13 +213,18 @@ public class ReferenceExpressionCompletionContributor {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiReferenceExpression createMockReference(final PsiElement place, @NotNull PsiType qualifierType, LookupElement qualifierItem) {
|
||||
static PsiReferenceExpression createMockReference(PsiElement place, @NotNull PsiType qualifierType, LookupElement qualifierItem) {
|
||||
return createMockReference(place, qualifierType, qualifierItem, ".");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static PsiReferenceExpression createMockReference(PsiElement place, @NotNull PsiType qualifierType, LookupElement qualifierItem, String separator) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(place.getProject());
|
||||
if (qualifierItem.getObject() instanceof PsiClass) {
|
||||
final String qname = ((PsiClass)qualifierItem.getObject()).getQualifiedName();
|
||||
if (qname == null) return null;
|
||||
|
||||
final String text = qname + ".xxx";
|
||||
String text = qname + separator + "xxx";
|
||||
try {
|
||||
final PsiExpression expr = factory.createExpressionFromText(text, place);
|
||||
if (expr instanceof PsiReferenceExpression) {
|
||||
@@ -233,7 +238,7 @@ public class ReferenceExpressionCompletionContributor {
|
||||
}
|
||||
}
|
||||
|
||||
return (PsiReferenceExpression) factory.createExpressionFromText("xxx.xxx", JavaCompletionUtil
|
||||
return (PsiReferenceExpression) factory.createExpressionFromText("xxx" + separator + "xxx", JavaCompletionUtil
|
||||
.createContextWithXxxVariable(place, qualifierType));
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -23,6 +23,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
@@ -92,7 +93,7 @@ public class SurroundWithArrayFix extends PsiElementBaseIntentionAction {
|
||||
final PsiType paramType = psiParameters[idx].getType();
|
||||
if (paramType instanceof PsiArrayType) {
|
||||
final PsiType expressionType = TypeConversionUtil.erasure(expression.getType());
|
||||
if (expressionType != null) {
|
||||
if (expressionType != null && PsiTypesUtil.isDenotableType(expressionType) && expressionType != PsiType.NULL) {
|
||||
final PsiType componentType = ((PsiArrayType)paramType).getComponentType();
|
||||
if (TypeConversionUtil.isAssignable(componentType, expressionType)) {
|
||||
return expression;
|
||||
|
||||
+33
-17
@@ -114,7 +114,7 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
|
||||
makeArray();
|
||||
break;
|
||||
case COPY_TO_FINAL:
|
||||
copyToFinal();
|
||||
copyToFinal(myVariable, myContext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -129,7 +129,7 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
|
||||
|
||||
private void makeArray() {
|
||||
for (PsiVariable var : getVariablesToFix()) {
|
||||
makeArray(var);
|
||||
makeArray(var, myContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,11 +165,11 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeArray(PsiVariable variable) throws IncorrectOperationException {
|
||||
private static void makeArray(PsiVariable variable, PsiElement context) throws IncorrectOperationException {
|
||||
variable.normalizeDeclaration();
|
||||
PsiType type = variable.getType();
|
||||
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(myContext.getProject()).getElementFactory();
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
|
||||
PsiType newType = type.createArrayType();
|
||||
|
||||
PsiDeclarationStatement variableDeclarationStatement;
|
||||
@@ -199,22 +199,22 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
|
||||
variable.replace(newVariable);
|
||||
}
|
||||
|
||||
private void copyToFinal() throws IncorrectOperationException {
|
||||
PsiManager psiManager = myContext.getManager();
|
||||
private static void copyToFinal(PsiVariable variable, PsiElement context) throws IncorrectOperationException {
|
||||
PsiManager psiManager = context.getManager();
|
||||
final Project project = psiManager.getProject();
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
PsiExpression initializer = factory.createExpressionFromText(myVariable.getName(), myContext);
|
||||
String newName = suggestNewName(project, myVariable);
|
||||
PsiType type = myVariable.getType();
|
||||
PsiExpression initializer = factory.createExpressionFromText(variable.getName(), context);
|
||||
String newName = suggestNewName(project, variable);
|
||||
PsiType type = variable.getType();
|
||||
PsiDeclarationStatement copyDecl = factory.createVariableDeclarationStatement(newName, type, initializer);
|
||||
PsiVariable newVariable = (PsiVariable)copyDecl.getDeclaredElements()[0];
|
||||
final boolean mustBeFinal =
|
||||
!PsiUtil.isLanguageLevel8OrHigher(myContext) || CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS;
|
||||
!PsiUtil.isLanguageLevel8OrHigher(context) || CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS;
|
||||
PsiUtil.setModifierProperty(newVariable, PsiModifier.FINAL, mustBeFinal);
|
||||
PsiElement statement = getStatementToInsertBefore();
|
||||
PsiElement statement = getStatementToInsertBefore(variable, context);
|
||||
if (statement == null) return;
|
||||
PsiExpression newExpression = factory.createExpressionFromText(newName, myVariable);
|
||||
replaceReferences(myContext, myVariable, newExpression);
|
||||
PsiExpression newExpression = factory.createExpressionFromText(newName, variable);
|
||||
replaceReferences(context, variable, newExpression);
|
||||
if (RefactoringUtil.isLoopOrIf(statement.getParent())) {
|
||||
RefactoringUtil.putStatementInLoopBody(copyDecl, statement.getParent(), statement);
|
||||
} else {
|
||||
@@ -222,12 +222,12 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
|
||||
}
|
||||
}
|
||||
|
||||
private PsiElement getStatementToInsertBefore() {
|
||||
PsiElement declarationScope = myVariable instanceof PsiParameter
|
||||
? ((PsiParameter)myVariable).getDeclarationScope() : PsiUtil.getVariableCodeBlock(myVariable, null);
|
||||
private static PsiElement getStatementToInsertBefore(PsiVariable variable, PsiElement context) {
|
||||
PsiElement declarationScope = variable instanceof PsiParameter
|
||||
? ((PsiParameter)variable).getDeclarationScope() : PsiUtil.getVariableCodeBlock(variable, null);
|
||||
if (declarationScope == null) return null;
|
||||
|
||||
PsiElement statement = myContext;
|
||||
PsiElement statement = context;
|
||||
nextInnerClass:
|
||||
do {
|
||||
statement = RefactoringUtil.getParentStatement(statement, false);
|
||||
@@ -361,4 +361,20 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void fixAccess(@NotNull PsiVariable variable, @NotNull PsiElement context) {
|
||||
int type = getQuickFixType(variable);
|
||||
if (type == -1) return;
|
||||
switch (type) {
|
||||
case MAKE_FINAL:
|
||||
PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, true);
|
||||
break;
|
||||
case MAKE_ARRAY:
|
||||
makeArray(variable, context);
|
||||
break;
|
||||
case COPY_TO_FINAL:
|
||||
copyToFinal(variable, context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class AssignFieldFromParameterAction extends BaseIntentionAction {
|
||||
return false;
|
||||
}
|
||||
final PsiField field = findFieldToAssign(project, myParameter);
|
||||
if (field == null) return false;
|
||||
if (field == null || type == null || !field.getType().isAssignableFrom(type)) return false;
|
||||
if (!field.getLanguage().isKindOf(JavaLanguage.INSTANCE)) return false;
|
||||
setText(CodeInsightBundle.message("intention.assign.field.from.parameter.text", field.getName()));
|
||||
|
||||
|
||||
+13
-20
@@ -33,40 +33,33 @@ public class CreateSwitchIntention extends BaseElementAtCaretIntentionAction {
|
||||
public static final String TEXT = "Create switch statement";
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
|
||||
final PsiExpressionStatement expressionStatement = resolveExpressionStatement(element);
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
PsiSwitchStatement switchStatement = (PsiSwitchStatement)elementFactory
|
||||
.createStatementFromText(String.format("switch (%s) {}", expressionStatement.getExpression().getText()), null);
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
PsiExpressionStatement expressionStatement = PsiTreeUtil.getParentOfType(element, PsiExpressionStatement.class, false);
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
String valueToSwitch = expressionStatement.getExpression().getText();
|
||||
PsiSwitchStatement switchStatement = (PsiSwitchStatement)elementFactory.createStatementFromText("switch (" + valueToSwitch + ") {}", null);
|
||||
switchStatement = (PsiSwitchStatement)expressionStatement.replace(switchStatement);
|
||||
CodeStyleManager.getInstance(project).reformat(switchStatement);
|
||||
|
||||
final PsiJavaToken lBrace = switchStatement.getBody().getLBrace();
|
||||
PsiJavaToken lBrace = switchStatement.getBody().getLBrace();
|
||||
editor.getCaretModel().moveToOffset(lBrace.getTextOffset() + lBrace.getTextLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) {
|
||||
final PsiExpressionStatement expressionStatement = resolveExpressionStatement(element);
|
||||
return expressionStatement != null && isValidTypeForSwitch(expressionStatement.getExpression().getType(), expressionStatement);
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
PsiExpressionStatement expressionStatement = PsiTreeUtil.getParentOfType(element, PsiExpressionStatement.class, false);
|
||||
return expressionStatement != null &&
|
||||
expressionStatement.getParent() instanceof PsiCodeBlock &&
|
||||
isValidTypeForSwitch(expressionStatement.getExpression().getType(), expressionStatement);
|
||||
}
|
||||
|
||||
private static PsiExpressionStatement resolveExpressionStatement(final PsiElement element) {
|
||||
if (element instanceof PsiExpressionStatement) {
|
||||
return (PsiExpressionStatement)element;
|
||||
} else {
|
||||
final PsiStatement psiStatement = PsiTreeUtil.getParentOfType(element, PsiStatement.class);
|
||||
return psiStatement instanceof PsiExpressionStatement ? (PsiExpressionStatement)psiStatement : null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValidTypeForSwitch(@Nullable final PsiType type, final PsiElement context) {
|
||||
private static boolean isValidTypeForSwitch(@Nullable PsiType type, PsiElement context) {
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type instanceof PsiClassType) {
|
||||
final PsiClass resolvedClass = ((PsiClassType)type).resolve();
|
||||
PsiClass resolvedClass = ((PsiClassType)type).resolve();
|
||||
if (resolvedClass == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+3
-3
@@ -112,9 +112,9 @@ public final class FieldFromParameterUtils {
|
||||
for (PsiReference reference : ReferencesSearch.search(parameter, new LocalSearchScope(parameter.getDeclarationScope()), false)) {
|
||||
if (!(reference instanceof PsiReferenceExpression)) continue;
|
||||
final PsiReferenceExpression expression = (PsiReferenceExpression)reference;
|
||||
if (!(expression.getParent() instanceof PsiAssignmentExpression)) continue;
|
||||
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression.getParent();
|
||||
if (assignmentExpression.getRExpression() != expression) continue;
|
||||
PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(expression, PsiAssignmentExpression.class, true, PsiClass.class);
|
||||
if (assignmentExpression == null) continue;
|
||||
if (!PsiTreeUtil.isAncestor(assignmentExpression.getRExpression(), expression, false)) continue;
|
||||
final PsiExpression lExpression = assignmentExpression.getLExpression();
|
||||
if (!(lExpression instanceof PsiReferenceExpression)) continue;
|
||||
final PsiElement element = ((PsiReferenceExpression)lExpression).resolve();
|
||||
|
||||
+1
-1
@@ -309,7 +309,7 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI
|
||||
* from arguments of MethodType.methodType(Class...) and MethodType.genericMethodType(int, boolean?)
|
||||
*/
|
||||
@Nullable
|
||||
private static ReflectiveSignature composeMethodSignature(@Nullable PsiExpression methodTypeExpression) {
|
||||
public static ReflectiveSignature composeMethodSignature(@Nullable PsiExpression methodTypeExpression) {
|
||||
final PsiExpression typeDefinition = findDefinition(methodTypeExpression);
|
||||
if (typeDefinition instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)typeDefinition;
|
||||
|
||||
+24
-11
@@ -20,6 +20,7 @@ import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -131,22 +132,34 @@ public class JavaReflectionInvocationInspection extends BaseJavaBatchLocalInspec
|
||||
if (definition instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression definitionCall = (PsiMethodCallExpression)definition;
|
||||
if (methodPredicate.test(definitionCall)) {
|
||||
final PsiExpression[] arguments = definitionCall.getArgumentList().getExpressions();
|
||||
|
||||
if (arguments.length == argumentOffset + 1) {
|
||||
final PsiExpression[] arrayElements = getVarargAsArray(arguments[argumentOffset]);
|
||||
if (arrayElements != null) {
|
||||
return Arrays.asList(arrayElements);
|
||||
}
|
||||
}
|
||||
if (arguments.length >= argumentOffset) {
|
||||
return Arrays.asList(arguments).subList(argumentOffset, arguments.length);
|
||||
}
|
||||
return getRequiredMethodArguments(definitionCall, argumentOffset);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<PsiExpression> getRequiredMethodArguments(@NotNull PsiMethodCallExpression definitionCall, int argumentOffset) {
|
||||
final PsiExpression[] arguments = definitionCall.getArgumentList().getExpressions();
|
||||
|
||||
if (arguments.length == argumentOffset + 1) {
|
||||
final PsiExpression[] arrayElements = getVarargAsArray(arguments[argumentOffset]);
|
||||
if (arrayElements != null) {
|
||||
return Arrays.asList(arrayElements);
|
||||
}
|
||||
}
|
||||
if (arguments.length >= argumentOffset) {
|
||||
return Arrays.asList(arguments).subList(argumentOffset, arguments.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static List<ReflectiveType> getReflectionMethodParameterTypes(@NotNull PsiMethodCallExpression definitionCall,
|
||||
int argumentOffset) {
|
||||
List<PsiExpression> arguments = getRequiredMethodArguments(definitionCall, argumentOffset);
|
||||
return arguments != null ? ContainerUtil.map(arguments, type -> getReflectiveType(type)) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Arguments getActualMethodArguments(PsiExpression[] arguments, int argumentOffset, boolean allowVarargAsArray) {
|
||||
if (allowVarargAsArray && arguments.length == argumentOffset + 1) {
|
||||
|
||||
+5
@@ -279,6 +279,11 @@ public class JavaReflectionMemberAccessInspection extends BaseJavaBatchLocalInsp
|
||||
final List<ReflectiveType> argumentTypes =
|
||||
ContainerUtil.map(methodArguments.expressions, JavaReflectionReferenceUtil::getReflectiveType);
|
||||
|
||||
return matchMethod(methods, argumentTypes);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod matchMethod(@NotNull PsiMethod[] methods, @NotNull List<ReflectiveType> argumentTypes) {
|
||||
int mismatchCount = Integer.MAX_VALUE;
|
||||
PsiMethod bestGuess = null;
|
||||
for (PsiMethod method : methods) {
|
||||
|
||||
+35
-12
@@ -18,9 +18,11 @@ package com.intellij.psi.impl.source.resolve.reference.impl;
|
||||
import com.intellij.codeInsight.completion.InsertHandler;
|
||||
import com.intellij.codeInsight.completion.InsertionContext;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInspection.reflectiveAccess.JavaReflectionInvocationInspection;
|
||||
import com.intellij.codeInspection.reflectiveAccess.JavaReflectionMemberAccessInspection;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
@@ -28,10 +30,7 @@ import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.*;
|
||||
|
||||
@@ -73,17 +72,29 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
|
||||
}
|
||||
|
||||
case GET_METHOD: {
|
||||
final PsiMethod[] methods = psiClass.findMethodsByName(name, true);
|
||||
final PsiMethod publicMethod = ContainerUtil.find(methods, method -> isRegularMethod(method) && isPublic(method));
|
||||
if (publicMethod != null) {
|
||||
return publicMethod;
|
||||
PsiMethod[] methods = psiClass.findMethodsByName(name, true);
|
||||
if (methods.length > 1) {
|
||||
methods =
|
||||
ContainerUtil.filter(methods, method -> isRegularMethod(method) && isPublic(method))
|
||||
.toArray(PsiMethod.EMPTY_ARRAY);
|
||||
if (methods.length > 1) {
|
||||
return findOverloadedMethod(methods);
|
||||
}
|
||||
}
|
||||
return ContainerUtil.find(methods, method -> isRegularMethod(method));
|
||||
return methods.length != 0 ? methods[0] : null;
|
||||
}
|
||||
|
||||
case GET_DECLARED_METHOD: {
|
||||
final PsiMethod[] methods = psiClass.findMethodsByName(name, false);
|
||||
return ContainerUtil.find(methods, method -> isRegularMethod(method) && isPotentiallyAccessible(method, psiClass));
|
||||
PsiMethod[] methods = psiClass.findMethodsByName(name, false);
|
||||
if (methods.length > 1) {
|
||||
methods =
|
||||
ContainerUtil.filter(methods, method -> isRegularMethod(method) && isPotentiallyAccessible(method, psiClass))
|
||||
.toArray(PsiMethod.EMPTY_ARRAY);
|
||||
if (methods.length > 1) {
|
||||
return findOverloadedMethod(methods);
|
||||
}
|
||||
}
|
||||
return methods.length != 0 ? methods[0] : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,6 +166,18 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
|
||||
return member != null && (member.getContainingClass() == psiClass || isPublic(member));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiElement findOverloadedMethod(PsiMethod[] methods) {
|
||||
final PsiMethodCallExpression definitionCall = PsiTreeUtil.getParentOfType(myElement, PsiMethodCallExpression.class);
|
||||
if (definitionCall != null) {
|
||||
final List<ReflectiveType> parameterTypes = JavaReflectionInvocationInspection.getReflectionMethodParameterTypes(definitionCall, 1);
|
||||
if (parameterTypes != null) {
|
||||
return JavaReflectionMemberAccessInspection.matchMethod(methods, parameterTypes);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
final Object object = item.getObject();
|
||||
|
||||
+22
-3
@@ -19,13 +19,16 @@ import com.intellij.codeInsight.completion.InsertHandler;
|
||||
import com.intellij.codeInsight.completion.InsertionContext;
|
||||
import com.intellij.codeInsight.completion.JavaLookupElementBuilder;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInspection.reflectiveAccess.JavaLangInvokeHandleSignatureInspection;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -97,9 +100,25 @@ public class JavaLangInvokeHandleReference extends PsiReferenceBase<PsiLiteralEx
|
||||
return field != null && filter.value(field) ? field : null;
|
||||
}
|
||||
|
||||
private static PsiElement resolveMethod(@NotNull String name, @NotNull PsiClass psiClass, Condition<? super PsiMethod> filter) {
|
||||
final PsiMethod[] methods = psiClass.findMethodsByName(name, true);
|
||||
return ContainerUtil.find(methods, filter);
|
||||
private PsiElement resolveMethod(@NotNull String name, @NotNull PsiClass psiClass, Condition<? super PsiMethod> filter) {
|
||||
PsiMethod[] methods = psiClass.findMethodsByName(name, true);
|
||||
if (methods.length != 0) {
|
||||
methods = ContainerUtil.filter(methods, filter).toArray(PsiMethod.EMPTY_ARRAY);
|
||||
if (methods.length > 1) {
|
||||
final PsiMethodCallExpression definitionCall = PsiTreeUtil.getParentOfType(myElement, PsiMethodCallExpression.class);
|
||||
if (definitionCall != null) {
|
||||
final PsiExpression[] arguments = definitionCall.getArgumentList().getExpressions();
|
||||
if (arguments.length > 2) {
|
||||
final PsiExpression typeExpression = ParenthesesUtils.stripParentheses(arguments[2]);
|
||||
final ReflectiveSignature expectedSignature = JavaLangInvokeHandleSignatureInspection.composeMethodSignature(typeExpression);
|
||||
if (expectedSignature != null) {
|
||||
return ContainerUtil.find(methods, method -> expectedSignature.equals(getMethodSignature(method)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return methods.length != 0 ? methods[0] : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.util.*;
|
||||
*/
|
||||
public abstract class NullableNotNullManager {
|
||||
protected static final Logger LOG = Logger.getInstance(NullableNotNullManager.class);
|
||||
protected final Project myProject;
|
||||
|
||||
public String myDefaultNullable = AnnotationUtil.NULLABLE;
|
||||
public String myDefaultNotNull = AnnotationUtil.NOT_NULL;
|
||||
@@ -41,7 +42,7 @@ public abstract class NullableNotNullManager {
|
||||
public final JDOMExternalizableStringList myNotNulls = new JDOMExternalizableStringList();
|
||||
|
||||
private static final String JAVAX_ANNOTATION_NULLABLE = "javax.annotation.Nullable";
|
||||
private static final String JAVAX_ANNOTATION_NONNULL = "javax.annotation.Nonnull";
|
||||
protected static final String JAVAX_ANNOTATION_NONNULL = "javax.annotation.Nonnull";
|
||||
|
||||
static final String[] DEFAULT_NULLABLES = {AnnotationUtil.NULLABLE,
|
||||
JAVAX_ANNOTATION_NULLABLE, "javax.annotation.CheckForNull",
|
||||
@@ -49,7 +50,8 @@ public abstract class NullableNotNullManager {
|
||||
"edu.umd.cs.findbugs.annotations.Nullable", "android.support.annotation.Nullable"
|
||||
};
|
||||
|
||||
public NullableNotNullManager() {
|
||||
public NullableNotNullManager(Project project) {
|
||||
myProject = project;
|
||||
Collections.addAll(myNullables, DEFAULT_NULLABLES);
|
||||
}
|
||||
|
||||
@@ -202,7 +204,7 @@ public abstract class NullableNotNullManager {
|
||||
String qName = annotation.getQualifiedName();
|
||||
if (qName == null) return null;
|
||||
|
||||
List<String> contradictory = nullable ? getNotNulls() : getNullables();
|
||||
List<String> contradictory = nullable ? getNotNullsWithNickNames() : getNullablesWithNickNames();
|
||||
if (contradictory.contains(qName)) return null;
|
||||
|
||||
return annotation;
|
||||
@@ -241,13 +243,24 @@ public abstract class NullableNotNullManager {
|
||||
}
|
||||
|
||||
private PsiAnnotation findPlainNullabilityAnnotation(@NotNull PsiModifierListOwner owner, boolean checkBases) {
|
||||
Set<String> qNames = ContainerUtil.newHashSet(getNullables());
|
||||
qNames.addAll(getNotNulls());
|
||||
Set<String> qNames = ContainerUtil.newHashSet(getNullablesWithNickNames());
|
||||
qNames.addAll(getNotNullsWithNickNames());
|
||||
return checkBases && owner instanceof PsiMethod
|
||||
? AnnotationUtil.findAnnotationInHierarchy(owner, qNames)
|
||||
: AnnotationUtil.findAnnotation(owner, qNames);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
protected List<String> getNullablesWithNickNames() {
|
||||
return getNullables();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected List<String> getNotNullsWithNickNames() {
|
||||
return getNotNulls();
|
||||
}
|
||||
|
||||
protected boolean hasHardcodedContracts(PsiElement element) {
|
||||
return false;
|
||||
}
|
||||
@@ -360,10 +373,10 @@ public abstract class NullableNotNullManager {
|
||||
public abstract List<String> getPredefinedNotNulls();
|
||||
|
||||
public static boolean isNullableAnnotation(@NotNull PsiAnnotation annotation) {
|
||||
return getInstance(annotation.getProject()).getNullables().contains(annotation.getQualifiedName());
|
||||
return getInstance(annotation.getProject()).getNullablesWithNickNames().contains(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
public static boolean isNotNullAnnotation(@NotNull PsiAnnotation annotation) {
|
||||
return getInstance(annotation.getProject()).getNotNulls().contains(annotation.getQualifiedName());
|
||||
return getInstance(annotation.getProject()).getNotNullsWithNickNames().contains(annotation.getQualifiedName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class Test {
|
||||
void m(int[] array) {
|
||||
for (int i = 1; i < array.length; <caret>i++) { }
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class ListA<Ta> {
|
||||
public <R extends Ta> Ta foo() { throw new Error(); }
|
||||
}
|
||||
|
||||
class ListB<Tb> extends ListA<Tb> {
|
||||
public <Rb extends Tb> Rb foo() { throw new Error(); }
|
||||
}
|
||||
|
||||
class ListC<Tc> extends ListB<Tc> {
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class A {
|
||||
{
|
||||
Runnable r = Syst::setOu<caret>
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class A {
|
||||
{
|
||||
Runnable r = System::setOut;<caret>
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Assign Parameter to Field 'myA'" "false"
|
||||
|
||||
class Person {
|
||||
int myA;
|
||||
int myId;
|
||||
void f(int <caret>a, String id) {
|
||||
this.myA = foo(a);
|
||||
}
|
||||
int foo(int a) {return a;}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Assign Parameter to Field 'myId'" "false"
|
||||
|
||||
class Person {
|
||||
int a;
|
||||
int myId;
|
||||
void f(int a, String id<caret>) {
|
||||
this.a = foo(a);
|
||||
}
|
||||
int foo(int a) {return a;}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Surround with array initialization" "false"
|
||||
class A {
|
||||
void m1(String[] s,
|
||||
String[] s2,
|
||||
String[] s3) {}
|
||||
{
|
||||
m1( <caret>null, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import javax.annotation.meta.*;
|
||||
|
||||
@TypeQualifierNickname()
|
||||
@javax.annotation.Nonnull(when = When.MAYBE)
|
||||
@interface NullableNick {}
|
||||
|
||||
interface UnknownInterface {
|
||||
void foo(String s);
|
||||
}
|
||||
|
||||
class ImplWithNotNull implements UnknownInterface {
|
||||
public void foo(@NullableNick String s) {
|
||||
System.out.println(s.<warning descr="Method invocation 'hashCode' may produce 'java.lang.NullPointerException'">hashCode</warning>());
|
||||
}
|
||||
}
|
||||
+18
-10
@@ -212,37 +212,37 @@ class Test88 {
|
||||
void testCollectorsToList() {
|
||||
configureByTestName()
|
||||
selectItem(myItems.find { it.lookupString.contains('toList') })
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testStaticallyImportedCollectorsToList() {
|
||||
configureByTestName()
|
||||
selectItem(myItems.find { it.lookupString.contains('collect(toList())') })
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testAllCollectors() {
|
||||
configureByTestName()
|
||||
myFixture.assertPreferredCompletionItems 0, 'collect', 'collect', 'collect(Collectors.toCollection())', 'collect(Collectors.toList())', 'collect(Collectors.toSet())'
|
||||
selectItem(myItems.find { it.lookupString.contains('toCollection') })
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testCollectorsToSet() {
|
||||
configureByTestName()
|
||||
selectItem(myItems.find { it.lookupString.contains('toSet') })
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testNoExplicitTypeArgsInTernary() {
|
||||
configureByTestName()
|
||||
selectItem(myItems.find { it.lookupString.contains('empty') })
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testCallBeforeLambda() {
|
||||
configureByTestName()
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testLambdaInAmbiguousCall() {
|
||||
@@ -264,13 +264,13 @@ class Test88 {
|
||||
void testNoSemicolonAfterVoidMethodInLambda() {
|
||||
configureByTestName()
|
||||
myFixture.type('l\t')
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testFinishMethodReferenceWithColon() {
|
||||
configureByTestName()
|
||||
myFixture.type(':')
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testPreferLocalsOverMethodRefs() {
|
||||
@@ -286,14 +286,22 @@ class Test88 {
|
||||
"}")
|
||||
configureByTestName()
|
||||
myFixture.type('\n')
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testOverrideMethodAsDefault() {
|
||||
configureByTestName()
|
||||
assert LookupElementPresentation.renderElement(myFixture.lookupElements[0]).itemText == 'default void run'
|
||||
myFixture.type('\t')
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testChainedMethodReference() {
|
||||
configureByTestName()
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
private checkResultByFileName() {
|
||||
checkResultByFile(getTestName(false) + "_after.java")
|
||||
}
|
||||
}
|
||||
+2
@@ -180,6 +180,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testInaccessibleThroughWildcard() { doTest7Incompatibility(false);}
|
||||
public void testInconvertibleTypes() { doTest5(false); }
|
||||
public void testIncompatibleReturnType() { doTest5(false); }
|
||||
|
||||
public void testContinueInferenceAfterFirstRawResult() { doTest5(false); }
|
||||
public void testDoNotAcceptLowerBoundIfRaw() { doTest5(false); }
|
||||
public void testStaticOverride() { doTest5(false); }
|
||||
@@ -342,6 +343,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testIDEA71582() { doTest5(false); }
|
||||
public void testIDEA65377() { doTest5(false); }
|
||||
public void testIDEA113526() { doTest5(true); }
|
||||
public void testIncompatibleReturnTypeBounds() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
|
||||
public void testIDEA116493() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
|
||||
public void testIDEA117827() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
|
||||
public void testIDEA118037() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
|
||||
|
||||
@@ -55,6 +55,10 @@ public class CreateSwitchTest extends JavaCodeInsightFixtureTestCase {
|
||||
doTestNotAvailable();
|
||||
}
|
||||
|
||||
public void testNotAvailableInForUpdate() {
|
||||
doTestNotAvailable();
|
||||
}
|
||||
|
||||
private void doTestString() {
|
||||
final LanguageLevelProjectExtension languageLevelProjectExtension = LanguageLevelProjectExtension.getInstance(getProject());
|
||||
final LanguageLevel oldLanguageLevel = languageLevelProjectExtension.getLanguageLevel();
|
||||
|
||||
+63
-1
@@ -16,10 +16,13 @@
|
||||
package com.intellij.java.codeInsight.navigation
|
||||
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import junit.framework.TestCase
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.intellij.lang.annotations.MagicConstant
|
||||
import org.jetbrains.annotations.NonNls
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
@@ -74,6 +77,64 @@ class JavaLangInvokeHandleNavigationTest : LightCodeInsightFixtureTestCase() {
|
||||
fun testStaticSetter6() = doNegativeTest("pf1", STATIC_SETTER)
|
||||
fun testStaticSetter7() = doNegativeTest("m1", STATIC_SETTER)
|
||||
|
||||
fun testOverloadedBothPublic() = doTestOverloaded(
|
||||
"""public class Overloaded {
|
||||
public void foo(int n) {}
|
||||
public void foo(String s) {}
|
||||
}""", VIRTUAL, "java.lang.String")
|
||||
|
||||
fun testOverloadedFirstPublic() = doTestOverloaded(
|
||||
"""public class Overloaded {
|
||||
public void foo(int n) {}
|
||||
void foo(String s) {}
|
||||
}""", VIRTUAL, "int")
|
||||
|
||||
fun testOverloadedSecondPublic() = doTestOverloaded(
|
||||
"""public class Overloaded {
|
||||
void foo(int n) {}
|
||||
public void foo(String s) {}
|
||||
}""", VIRTUAL, "java.lang.String")
|
||||
|
||||
fun testOverloadedInherited() {
|
||||
myFixture.addClass("""public class OverloadedParent {
|
||||
public static void foo(String s) {}
|
||||
}""")
|
||||
|
||||
doTestOverloaded(
|
||||
"""public class Overloaded extends OverloadedParent {
|
||||
public static void foo(int n) {}
|
||||
}""", STATIC, "java.lang.String")
|
||||
}
|
||||
|
||||
fun testOverloadedStatic() = doTestOverloaded(
|
||||
"""public class Overloaded {
|
||||
public static void foo(int n) {}
|
||||
public static void foo(String s) {}
|
||||
}""", STATIC, "java.lang.String")
|
||||
|
||||
|
||||
private fun doTestOverloaded(@NonNls @Language("JAVA") classText: String, function: String, vararg expectedParameterTypes: String) {
|
||||
myFixture.addClass(classText)
|
||||
|
||||
val methodType = arrayOf("void", *expectedParameterTypes).map { "$it.class" }.joinToString(", ")
|
||||
val member = doTestImpl("foo", """
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
class Main {
|
||||
void foo() throws ReflectiveOperationException {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
lookup.$function(Overloaded.class, "<caret>foo", MethodType.methodType($methodType));
|
||||
}
|
||||
}""")
|
||||
|
||||
TestCase.assertTrue("Is method", member is PsiMethod)
|
||||
val parameters = (member as PsiMethod).parameterList.parameters
|
||||
TestCase.assertEquals("Parameter count", expectedParameterTypes.size, parameters.size)
|
||||
for (i in 0 until expectedParameterTypes.size) {
|
||||
TestCase.assertEquals("Parameter $i", expectedParameterTypes[i], parameters[i].type.canonicalText)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun doTest(name: String,
|
||||
@MagicConstant(stringValues = arrayOf(VIRTUAL, STATIC, SPECIAL,
|
||||
@@ -83,7 +144,7 @@ class JavaLangInvokeHandleNavigationTest : LightCodeInsightFixtureTestCase() {
|
||||
doTestImpl(name, getMainClassText(name, function))
|
||||
}
|
||||
|
||||
private fun doTestImpl(name: String, mainClassText: String) {
|
||||
private fun doTestImpl(name: String, mainClassText: String): PsiMember {
|
||||
val reference = getReference(mainClassText)
|
||||
TestCase.assertEquals("Reference text", name, reference.canonicalText)
|
||||
val resolved = reference.resolve()
|
||||
@@ -91,6 +152,7 @@ class JavaLangInvokeHandleNavigationTest : LightCodeInsightFixtureTestCase() {
|
||||
TestCase.assertTrue("Target is a member", resolved is PsiMember)
|
||||
val member = resolved as PsiMember?
|
||||
TestCase.assertEquals("Target name", name, member!!.name)
|
||||
return member
|
||||
}
|
||||
|
||||
private fun doNegativeTest(name: String,
|
||||
|
||||
+67
-4
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package com.intellij.java.codeInsight.navigation;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMember;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.intellij.lang.annotations.MagicConstant;
|
||||
@@ -93,6 +91,70 @@ public class JavaReflectionNavigationTest extends LightCodeInsightFixtureTestCas
|
||||
"}");
|
||||
}
|
||||
|
||||
public void testOverloadedMethodBothPublic() {
|
||||
doTestOverloadedMethod("foo",
|
||||
"class Overloaded {\n" +
|
||||
" public void foo() {}\n" +
|
||||
" public void foo(String s) {}\n" +
|
||||
"}", false, "java.lang.String");
|
||||
}
|
||||
|
||||
public void testOverloadedMethodPublicFirst() {
|
||||
doTestOverloadedMethod("foo",
|
||||
"class Overloaded {\n" +
|
||||
" public void foo() {}\n" +
|
||||
" void foo(String s) {}\n" +
|
||||
"}", false);
|
||||
}
|
||||
|
||||
public void testOverloadedMethodPublicSecond() {
|
||||
doTestOverloadedMethod("foo",
|
||||
"class Overloaded {\n" +
|
||||
" void foo() {}\n" +
|
||||
" public void foo(String s) {}\n" +
|
||||
"}", false, "java.lang.String");
|
||||
}
|
||||
|
||||
public void testOverloadedDeclaredMethod() {
|
||||
doTestOverloadedMethod("foo",
|
||||
"class Overloaded {\n" +
|
||||
" public void foo() {}\n" +
|
||||
" public void foo(String s) {}\n" +
|
||||
"}", true, "java.lang.String");
|
||||
}
|
||||
|
||||
public void testOverloadedInheritedMethod() {
|
||||
doTestOverloadedMethod("bar",
|
||||
"class OverloadedParent {" +
|
||||
" public void bar(String s) {}\n" +
|
||||
"}" +
|
||||
"" +
|
||||
"class Overloaded extends OverloadedParent {\n" +
|
||||
" public void bar() {}\n" +
|
||||
"}", false, "java.lang.String");
|
||||
}
|
||||
|
||||
private void doTestOverloadedMethod(String name,
|
||||
@NotNull @NonNls @Language("JAVA") String classText,
|
||||
boolean isDeclared,
|
||||
String... expectedParameterTypes) {
|
||||
myFixture.addClass(classText);
|
||||
|
||||
PsiMember member = doTestImpl(name,
|
||||
"class Main {" +
|
||||
" void main() {" +
|
||||
" Overloaded.class.get" + (isDeclared?"Declared":"") + "Method(\"<caret>"+name+"\", String.class);" +
|
||||
" }" +
|
||||
"}");
|
||||
assertTrue("Target is a method", member instanceof PsiMethod);
|
||||
PsiMethod method = (PsiMethod)member;
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
assertEquals("Parameter count", expectedParameterTypes.length, parameters.length);
|
||||
for (int i = 0; i < expectedParameterTypes.length; i++) {
|
||||
assertEquals("Parameter type " + i, expectedParameterTypes[i], parameters[0].getType().getCanonicalText());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void doTest(String name,
|
||||
@MagicConstant(stringValues = {FIELD, METHOD, DF, DM}) String type) {
|
||||
@@ -104,7 +166,7 @@ public class JavaReflectionNavigationTest extends LightCodeInsightFixtureTestCas
|
||||
doTestImpl(name, mainClassText);
|
||||
}
|
||||
|
||||
private void doTestImpl(String name, String mainClassText) {
|
||||
private PsiMember doTestImpl(String name, @NotNull @NonNls @Language("JAVA") String mainClassText) {
|
||||
PsiReference reference = getReference(mainClassText);
|
||||
assertEquals("Reference text", name, reference.getCanonicalText());
|
||||
PsiElement resolved = reference.resolve();
|
||||
@@ -112,6 +174,7 @@ public class JavaReflectionNavigationTest extends LightCodeInsightFixtureTestCas
|
||||
assertTrue("Target is a member", resolved instanceof PsiMember);
|
||||
PsiMember member = (PsiMember)resolved;
|
||||
assertEquals("Target name", name, member.getName());
|
||||
return member;
|
||||
}
|
||||
|
||||
private void doNegativeTest(String name,
|
||||
|
||||
+26
-4
@@ -360,6 +360,17 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
|
||||
myFixture.enableInspections(inspection);
|
||||
myFixture.testHighlighting(true, false, true, getTestName(false) + ".java");
|
||||
}
|
||||
|
||||
public void testTypeQualifierNickname() {
|
||||
addJavaxNullabilityAnnotations(myFixture);
|
||||
|
||||
myFixture.addClass("package bar;" +
|
||||
"import javax.annotation.meta.*;" +
|
||||
"@TypeQualifierNickname() @javax.annotation.NonNull(when = Maybe.MAYBE) " +
|
||||
"public @interface NullableNick {}");
|
||||
|
||||
doTest();
|
||||
}
|
||||
|
||||
public static void addJavaxDefaultNullabilityAnnotations(final JavaCodeInsightTestFixture fixture) {
|
||||
fixture.addClass("package javax.annotation;" +
|
||||
@@ -371,12 +382,23 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
|
||||
}
|
||||
|
||||
public static void addJavaxNullabilityAnnotations(final JavaCodeInsightTestFixture fixture) {
|
||||
fixture.addClass("package javax.annotation;" +
|
||||
"public @interface Nonnull {}");
|
||||
fixture.addClass("package javax.annotation;" +
|
||||
"public @interface Nullable {}");
|
||||
fixture.addClass("package javax.annotation.meta;" +
|
||||
"public @interface TypeQualifierDefault { java.lang.annotation.ElementType[] value() default {};}");
|
||||
fixture.addClass("package javax.annotation.meta;" +
|
||||
"public enum When { ALWAYS, UNKNOWN, MAYBE, NEVER }");
|
||||
fixture.addClass("package javax.annotation.meta;" +
|
||||
"public @interface TypeQualifierNickname {}");
|
||||
|
||||
fixture.addClass("package javax.annotation;" +
|
||||
"import javax.annotation.meta.*;" +
|
||||
"public @interface Nonnull {" +
|
||||
" When when() default When.ALWAYS;" +
|
||||
"}");
|
||||
fixture.addClass("package javax.annotation;" +
|
||||
"import javax.annotation.meta.*;" +
|
||||
"@TypeQualifierNickname " +
|
||||
"@Nonnull(when = When.UNKNOWN) " +
|
||||
"public @interface Nullable {}");
|
||||
}
|
||||
|
||||
public void testCustomTypeQualifierDefault() {
|
||||
|
||||
+3
-1
@@ -115,7 +115,9 @@ public class ConvertFieldToThreadLocalIntention extends PsiElementBaseIntentionA
|
||||
}
|
||||
|
||||
PsiExpression initializer = psiField.getInitializer();
|
||||
if (initializer == null) {
|
||||
|
||||
if (initializer == null &&
|
||||
!psiField.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
final PsiType type = psiField.getType();
|
||||
String initializerText = null;
|
||||
if (PsiType.BOOLEAN.equals(type)) {
|
||||
|
||||
+14
@@ -12,6 +12,8 @@ import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
|
||||
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
|
||||
import com.intellij.refactoring.typeMigration.TypeEvaluator;
|
||||
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.siyeh.HardcodedMethodConstants;
|
||||
import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -342,6 +344,9 @@ public class AtomicConversionRule extends TypeConversionRule {
|
||||
if (context instanceof PsiArrayAccessExpression) {
|
||||
return new TypeConversionDescriptor("$qualifier$[$idx$]", "$qualifier$.get($idx$)", (PsiExpression)context);
|
||||
}
|
||||
if (parent instanceof PsiReferenceExpression && isReferenceToLengthField((PsiReferenceExpression)parent)) {
|
||||
return new TypeConversionDescriptor("$qualifier$.length", "$qualifier$.length()", (PsiExpression)parent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -438,4 +443,13 @@ public class AtomicConversionRule extends TypeConversionRule {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isReferenceToLengthField(@NotNull PsiReferenceExpression refExpr) {
|
||||
if (!"length".equals(refExpr.getReferenceName())) {
|
||||
return false;
|
||||
}
|
||||
PsiClass aClass = JavaPsiFacade.getElementFactory(refExpr.getProject()).getArrayClass(PsiUtil.getLanguageLevel(refExpr));
|
||||
PsiField lengthField = ObjectUtils.notNull(aClass.findFieldByName(HardcodedMethodConstants.LENGTH, false));
|
||||
return refExpr.isReferenceTo(lengthField);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+61
-18
@@ -1,5 +1,7 @@
|
||||
package com.intellij.refactoring.typeMigration.rules;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.VariableAccessFromInnerClassFix;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.*;
|
||||
@@ -8,10 +10,14 @@ import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
|
||||
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
|
||||
import com.intellij.refactoring.typeMigration.TypeEvaluator;
|
||||
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ThreadLocalConversionRule extends TypeConversionRule {
|
||||
private static final Logger LOG = Logger.getInstance(ThreadLocalConversionRule.class);
|
||||
|
||||
@@ -150,24 +156,39 @@ public class ThreadLocalConversionRule extends TypeConversionRule {
|
||||
|
||||
public static TypeConversionDescriptor wrapWithNewExpression(PsiType to, PsiType from, PsiExpression initializer) {
|
||||
final String boxedTypeName = from instanceof PsiPrimitiveType ? ((PsiPrimitiveType)from).getBoxedTypeName() : from.getCanonicalText();
|
||||
return new TypeConversionDescriptor("$qualifier$", "new " +
|
||||
to.getCanonicalText() +
|
||||
"() {\n" +
|
||||
"@Override \n" +
|
||||
"protected " +
|
||||
boxedTypeName +
|
||||
" initialValue() {\n" +
|
||||
" return " +
|
||||
(PsiUtil.isLanguageLevel5OrHigher(initializer)
|
||||
? initializer.getText()
|
||||
: (from instanceof PsiPrimitiveType ? "new " +
|
||||
((PsiPrimitiveType)from).getBoxedTypeName() +
|
||||
"(" +
|
||||
initializer.getText() +
|
||||
")" : initializer.getText())) +
|
||||
";\n" +
|
||||
"}\n" +
|
||||
"}", initializer);
|
||||
List<PsiVariable> toMakeFinal = TypeConversionRuleUtil.getVariablesToMakeFinal(initializer);
|
||||
if (toMakeFinal == null) return null;
|
||||
return new WrappingWithInnerClassOrLambdaDescriptor("$qualifier$",
|
||||
createThreadLocalInitializerReplacement(to, from, initializer, boxedTypeName),
|
||||
initializer,
|
||||
toMakeFinal);
|
||||
}
|
||||
|
||||
private static String createThreadLocalInitializerReplacement(PsiType to,
|
||||
PsiType from,
|
||||
PsiExpression initializer,
|
||||
String boxedTypeName) {
|
||||
if (PsiUtil.isLanguageLevel8OrHigher(initializer)) {
|
||||
return "java.lang.ThreadLocal.withInitial(() -> " + initializer.getText() + ")";
|
||||
}
|
||||
return "new " +
|
||||
to.getCanonicalText() +
|
||||
"() {\n" +
|
||||
"@Override \n" +
|
||||
"protected " +
|
||||
boxedTypeName +
|
||||
" initialValue() {\n" +
|
||||
" return " +
|
||||
(PsiUtil.isLanguageLevel5OrHigher(initializer)
|
||||
? initializer.getText()
|
||||
: (from instanceof PsiPrimitiveType ? "new " +
|
||||
((PsiPrimitiveType)from).getBoxedTypeName() +
|
||||
"(" +
|
||||
initializer.getText() +
|
||||
")" : initializer.getText())) +
|
||||
";\n" +
|
||||
"}\n" +
|
||||
"}";
|
||||
}
|
||||
|
||||
private static String toPrimitive(String replaceByArg, PsiType from, PsiElement context) {
|
||||
@@ -221,5 +242,27 @@ public class ThreadLocalConversionRule extends TypeConversionRule {
|
||||
return toBoxed(arg, from, context);
|
||||
}
|
||||
|
||||
private static class WrappingWithInnerClassOrLambdaDescriptor extends TypeConversionDescriptor {
|
||||
private final List<PsiVariable> myVariablesToMakeFinal;
|
||||
|
||||
private WrappingWithInnerClassOrLambdaDescriptor(@NonNls final String stringToReplace,
|
||||
@NonNls final String replaceByString,
|
||||
final PsiExpression expression,
|
||||
@NotNull List<PsiVariable> toMakeFinal) {
|
||||
super(stringToReplace, replaceByString, expression);
|
||||
myVariablesToMakeFinal = toMakeFinal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
|
||||
PsiExpression replaced = super.replace(expression, evaluator);
|
||||
boolean atLeastJava8 = PsiUtil.isLanguageLevel8OrHigher(replaced);
|
||||
for (PsiVariable var : myVariablesToMakeFinal) {
|
||||
if (!atLeastJava8 || !HighlightControlFlowUtil.isEffectivelyFinal(var, replaced, null)) {
|
||||
VariableAccessFromInnerClassFix.fixAccess(var, replaced);
|
||||
}
|
||||
}
|
||||
return replaced;
|
||||
}
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.refactoring.typeMigration.rules;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class TypeConversionRuleUtil {
|
||||
static List<PsiVariable> getVariablesToMakeFinal(@NotNull PsiExpression expression) {
|
||||
final ControlFlow controlFlow;
|
||||
try {
|
||||
controlFlow = ControlFlowFactory.getInstance(expression.getProject()).getControlFlow(expression, new MyControlFlowPolicy(expression), false, false);
|
||||
}
|
||||
catch (AnalysisCanceledException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<PsiVariable> writtenVariables = ControlFlowUtil.getWrittenVariables(controlFlow, 0, controlFlow.getSize(), false);
|
||||
if (!writtenVariables.isEmpty()) return null;
|
||||
|
||||
return ControlFlowUtil.getUsedVariables(controlFlow, 0, controlFlow.getSize())
|
||||
.stream()
|
||||
.filter(v -> !v.hasModifierProperty(PsiModifier.FINAL))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static class MyControlFlowPolicy implements ControlFlowPolicy {
|
||||
private final PsiElement myElement;
|
||||
|
||||
public MyControlFlowPolicy(PsiElement element) {myElement = element;}
|
||||
|
||||
@Override
|
||||
public PsiVariable getUsedVariable(@NotNull PsiReferenceExpression refExpr) {
|
||||
if (refExpr.isQualified()) return null;
|
||||
|
||||
PsiElement refElement = refExpr.resolve();
|
||||
if ((refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) &&
|
||||
!PsiTreeUtil.isAncestor(myElement, refElement, true)) {
|
||||
return (PsiVariable) refElement;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParameterAccepted(@NotNull PsiParameter psiParameter) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocalVariableAccepted(@NotNull PsiLocalVariable psiVariable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
-5
@@ -8,11 +8,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author anna
|
||||
*/
|
||||
public class ConvertToThreadLocalIntentionTest extends LightQuickFixParameterizedTestCase {
|
||||
@Override
|
||||
protected boolean shouldBeAvailableAfterExecution() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/intentions/threadLocal";
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||
|
||||
// "Convert to atomic" "true"
|
||||
class Test {
|
||||
final AtomicIntegerArray ii = new AtomicIntegerArray(new int[12]);
|
||||
|
||||
void m() {
|
||||
int k = ii.length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Convert to atomic" "true"
|
||||
class Test {
|
||||
int[] i<caret>i = new int[12];
|
||||
|
||||
void m() {
|
||||
int k = ii.length;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Test {
|
||||
final ThreadLocal<Integer> field = new ThreadLocal<Integer>() {
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
final ThreadLocal<Integer> field = ThreadLocal.withInitial(() -> 0);
|
||||
void foo() {
|
||||
field.set(field.get() + 1);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Test {
|
||||
final ThreadLocal<String> field = new ThreadLocal<String>() {
|
||||
@Override
|
||||
protected String initialValue() {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
final ThreadLocal<String> field = ThreadLocal.withInitial(() -> "");
|
||||
void foo() {
|
||||
System.out.println(field.get());
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Test {
|
||||
final ThreadLocal<Integer> field = new ThreadLocal<Integer>() {
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return new Integer(0);
|
||||
}
|
||||
};
|
||||
final ThreadLocal<Integer> field = ThreadLocal.withInitial(() -> new Integer(0));
|
||||
void foo() {
|
||||
if (field.get() == null) return;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Test {
|
||||
final ThreadLocal<String> field = new ThreadLocal<String>() {
|
||||
@Override
|
||||
protected String initialValue() {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
final ThreadLocal<String> field = ThreadLocal.withInitial(() -> "");
|
||||
void foo() {
|
||||
if (field.get().indexOf("a") == -1) return;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Test {
|
||||
final ThreadLocal<Integer> field = new ThreadLocal<Integer>() {
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return new Integer(0);
|
||||
}
|
||||
};
|
||||
final ThreadLocal<Integer> field = ThreadLocal.withInitial(() -> new Integer(0));
|
||||
void foo(Test t) {
|
||||
if (t.field.get() == null) return;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
class Test {
|
||||
static final ThreadLocal<Integer> field;
|
||||
static {
|
||||
field = new ThreadLocal<Integer>() {
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return new Integer(0);
|
||||
}
|
||||
};
|
||||
field = ThreadLocal.withInitial(() -> new Integer(0));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class X {
|
||||
private final ThreadLocal<byte[]> bytes = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[10];
|
||||
}
|
||||
};
|
||||
private final ThreadLocal<byte[]> bytes = ThreadLocal.withInitial(() -> new byte[10]);
|
||||
|
||||
byte foo(byte b) {
|
||||
bytes.get()[0] = 1;
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class X {
|
||||
final ThreadLocal<Integer> i = new ThreadLocal<Integer>() {
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
final ThreadLocal<Integer> i = ThreadLocal.withInitial(() -> 0);
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Test {
|
||||
final ThreadLocal<String[]> field = new ThreadLocal<String[]>() {
|
||||
@Override
|
||||
protected String[] initialValue() {
|
||||
return new String[]{};
|
||||
}
|
||||
};
|
||||
final ThreadLocal<String[]> field = ThreadLocal.withInitial(() -> new String[]{});
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Main {
|
||||
private final ThreadLocal<Boolean> property;
|
||||
|
||||
Main3(boolean property) {
|
||||
if (property) {
|
||||
property = false;
|
||||
}
|
||||
boolean finalProperty = property;
|
||||
this.property = ThreadLocal.withInitial(() -> finalProperty);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Foo {
|
||||
private final ThreadLocal<Boolean> property;
|
||||
|
||||
Foo(boolean property) {
|
||||
this.property = ThreadLocal.withInitial(() -> property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Main {
|
||||
private final ThreadLocal<Boolean> property;
|
||||
|
||||
Main3(final boolean property) {
|
||||
this.property = new ThreadLocal<Boolean>() {
|
||||
@Override
|
||||
protected Boolean initialValue() {
|
||||
return property;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class X {
|
||||
private final ThreadLocal<String> s = new ThreadLocal<String>() {
|
||||
@Override
|
||||
protected String initialValue() {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
private final ThreadLocal<String> s = ThreadLocal.withInitial(() -> "");
|
||||
private String t;
|
||||
private String u;
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Test {
|
||||
final ThreadLocal<Integer> field = new ThreadLocal<Integer>() {
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
final ThreadLocal<Integer> field = ThreadLocal.withInitial(() -> 0);
|
||||
}
|
||||
@@ -5,10 +5,5 @@ import java.lang.annotation.*;
|
||||
public @interface TA { int value(); }
|
||||
|
||||
class Test {
|
||||
final ThreadLocal<@TA(42) Integer> field = new ThreadLocal<Integer>() {
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
final ThreadLocal<@TA(42) Integer> field = ThreadLocal.withInitial(() -> 0);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Main {
|
||||
private final boolean propert<caret>y;
|
||||
|
||||
Main3(boolean property) {
|
||||
if (property) {
|
||||
property = false;
|
||||
}
|
||||
this.property = property;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Foo {
|
||||
private final boolean prope<caret>rty;
|
||||
|
||||
Foo(boolean property) {
|
||||
this.property = property;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Main {
|
||||
private final boolean propert<caret>y;
|
||||
|
||||
Main3(boolean property) {
|
||||
this.property = property;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.util.List;
|
||||
|
||||
@@ -65,7 +64,6 @@ public abstract class DvcsBranchPopup<Repo extends Repository> {
|
||||
? " in " + DvcsUtil.getShortRepositoryName(currentRepository) : "";
|
||||
myPopup = new BranchActionGroupPopup(title + myRepoTitleInfo, myProject, preselectActionCondition, createActions(), dimensionKey);
|
||||
initBranchSyncPolicyIfNotInitialized();
|
||||
setCurrentBranchInfo();
|
||||
warnThatBranchesDivergedIfNeeded();
|
||||
}
|
||||
|
||||
@@ -86,11 +84,6 @@ public abstract class DvcsBranchPopup<Repo extends Repository> {
|
||||
}
|
||||
}
|
||||
|
||||
protected void setCurrentBranchInfo() {
|
||||
String branchText = "Current branch : ";
|
||||
myPopup.setAdText(branchText + myCurrentRepository.getCurrentBranchName(), SwingConstants.CENTER);
|
||||
}
|
||||
|
||||
private void notifyAboutSyncedBranches() {
|
||||
String description =
|
||||
"You have several " + myVcs.getDisplayName() + " roots in the project and they all are checked out at the same branch. " +
|
||||
@@ -144,11 +137,15 @@ public abstract class DvcsBranchPopup<Repo extends Repository> {
|
||||
}
|
||||
|
||||
private void warnThatBranchesDivergedIfNeeded() {
|
||||
if (myRepositoryManager.moreThanOneRoot() && myMultiRootBranchConfig.diverged() && userWantsSyncControl()) {
|
||||
if (isBranchesDiverged()) {
|
||||
myPopup.setWarning("Branches have diverged");
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isBranchesDiverged() {
|
||||
return myRepositoryManager.moreThanOneRoot() && myMultiRootBranchConfig.diverged() && userWantsSyncControl();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract DefaultActionGroup createRepositoriesActions();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class DvcsMultiRootBranchConfig<Repo extends Repository> {
|
||||
@NotNull protected final Collection<Repo> myRepositories;
|
||||
@@ -34,9 +35,14 @@ public abstract class DvcsMultiRootBranchConfig<Repo extends Repository> {
|
||||
|
||||
@Nullable
|
||||
public String getCurrentBranch() {
|
||||
return getCommonName(Repository::getCurrentBranchName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getCommonName(@NotNull Function<Repo, String> nameSupplier) {
|
||||
String commonBranch = null;
|
||||
for (Repo repository : myRepositories) {
|
||||
String branchName = repository.getCurrentBranchName();
|
||||
String branchName = nameSupplier.apply(repository);
|
||||
if (branchName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.dvcs.ui;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
@@ -28,10 +29,7 @@ import com.intellij.openapi.ui.popup.PopupStep;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.WindowStateService;
|
||||
import com.intellij.openapi.vcs.ui.FlatSpeedSearchPopup;
|
||||
import com.intellij.ui.ErrorLabel;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.ScrollingUtil;
|
||||
import com.intellij.ui.SeparatorWithText;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.panels.OpaquePanel;
|
||||
import com.intellij.ui.popup.KeepingPopupOpenAction;
|
||||
import com.intellij.ui.popup.PopupFactoryImpl;
|
||||
@@ -40,6 +38,7 @@ import com.intellij.ui.popup.list.IconListPopupRenderer;
|
||||
import com.intellij.ui.popup.list.ListPopupImpl;
|
||||
import com.intellij.ui.popup.list.ListPopupModel;
|
||||
import com.intellij.ui.popup.list.PopupListElementRenderer;
|
||||
import com.intellij.util.FontUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
@@ -60,11 +59,14 @@ import static com.intellij.util.ui.UIUtil.DEFAULT_VGAP;
|
||||
|
||||
public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
private static final DataKey<ListPopupModel> POPUP_MODEL = DataKey.create("VcsPopupModel");
|
||||
private Project myProject;
|
||||
private MyPopupListElementRenderer myListElementRenderer;
|
||||
private boolean myShown;
|
||||
@NotNull private Dimension myPrevSize = JBUI.emptySize();
|
||||
private boolean myUserSizeChanged;
|
||||
private Project myProject;
|
||||
private boolean myInternalSizeChanged;
|
||||
private int myMeanRowHeight;
|
||||
@Nullable private final String myKey;
|
||||
@NotNull private Dimension myPrevSize = JBUI.emptySize();
|
||||
|
||||
public BranchActionGroupPopup(@NotNull String title,
|
||||
@NotNull Project project,
|
||||
@@ -76,27 +78,62 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
myProject = project;
|
||||
DataManager.registerDataProvider(getList(), dataId -> POPUP_MODEL.is(dataId) ? getListModel() : null);
|
||||
installOnHoverIconsSupport(getListElementRenderer());
|
||||
if (dimensionKey != null) {
|
||||
Dimension storedSize = WindowStateService.getInstance(myProject).getSizeFor(myProject, dimensionKey);
|
||||
myKey = dimensionKey;
|
||||
if (myKey != null) {
|
||||
Dimension storedSize = WindowStateService.getInstance(myProject).getSizeFor(myProject, myKey);
|
||||
if (storedSize != null) {
|
||||
//set forced size before component is shown
|
||||
setSize(storedSize);
|
||||
}
|
||||
createTitlePanelToolbar(myKey);
|
||||
}
|
||||
trackDimensions(dimensionKey);
|
||||
myMeanRowHeight = getList().getCellBounds(0, 0).height + UIUtil.getListCellVPadding() * 2;
|
||||
}
|
||||
|
||||
void createTitlePanelToolbar(@NotNull String dimensionKey) {
|
||||
AnAction restoreDefaultSizeAction =
|
||||
new DumbAwareAction("Restore Size", "Restore default size for widget", AllIcons.Vcs.RestoreDefaultSize) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
WindowStateService.getInstance(myProject).putSizeFor(myProject, dimensionKey, null);
|
||||
myInternalSizeChanged = true;
|
||||
pack(true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabledAndVisible(myUserSizeChanged ||
|
||||
WindowStateService.getInstance(myProject).getSizeFor(myProject, dimensionKey) != null);
|
||||
}
|
||||
};
|
||||
final ActionToolbar popupTitleToolbar = ActionManager.getInstance()
|
||||
.createActionToolbar("BranchWidget", new DefaultActionGroup(restoreDefaultSizeAction), true);
|
||||
final JComponent toolbarComponent = popupTitleToolbar.getComponent();
|
||||
popupTitleToolbar.setReservePlaceAutoPopupIcon(false);
|
||||
toolbarComponent.setBorder(JBUI.Borders.emptyRight(2));
|
||||
toolbarComponent.setOpaque(false);
|
||||
|
||||
getTitle().setButtonComponent(new ActiveComponent.Adapter() {
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return toolbarComponent;
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
//for child popups only
|
||||
private BranchActionGroupPopup(@Nullable WizardPopup aParent, @NotNull ListPopupStep aStep, @Nullable Object parentValue) {
|
||||
super(aParent, aStep, DataContext.EMPTY_CONTEXT, parentValue);
|
||||
// don't store children popup userSize;
|
||||
myKey = null;
|
||||
DataManager.registerDataProvider(getList(), dataId -> POPUP_MODEL.is(dataId) ? getListModel() : null);
|
||||
installOnHoverIconsSupport(getListElementRenderer());
|
||||
// don't store children popup userSize;
|
||||
trackDimensions(null);
|
||||
}
|
||||
|
||||
private void trackDimensions(@Nullable String dimensionKey) {
|
||||
getComponent().addComponentListener(new ComponentAdapter() {
|
||||
Window popupWindow = getPopupWindow();
|
||||
if (popupWindow == null) return;
|
||||
popupWindow.addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
if (myShown) {
|
||||
@@ -118,7 +155,11 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
|
||||
private void processOnSizeChanged() {
|
||||
Dimension newSize = ObjectUtils.assertNotNull(getSize());
|
||||
if (myPrevSize.height < newSize.height) {
|
||||
int preferredHeight = getComponent().getPreferredSize().height;
|
||||
int realHeight = getComponent().getHeight();
|
||||
boolean shouldExpand = preferredHeight + myMeanRowHeight < realHeight;
|
||||
boolean sizeWasIncreased = myPrevSize.height < newSize.height;
|
||||
if (!myInternalSizeChanged && sizeWasIncreased && shouldExpand) {
|
||||
List<MoreAction> mores = getMoreActions();
|
||||
for (MoreAction more : mores) {
|
||||
if (!getList().getScrollableTracksViewportHeight()) break;
|
||||
@@ -129,7 +170,9 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
}
|
||||
}
|
||||
myPrevSize = newSize;
|
||||
myUserSizeChanged = true;
|
||||
//ugly properties to distinguish user size changed from pack method call after Restore Size action performed
|
||||
myUserSizeChanged = !myInternalSizeChanged;
|
||||
myInternalSizeChanged = false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -165,6 +208,7 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
if (size != null) {
|
||||
myPrevSize = size;
|
||||
}
|
||||
trackDimensions(myKey);
|
||||
}
|
||||
|
||||
private static void createSpeedSearchActions(@NotNull ActionGroup actionGroup,
|
||||
@@ -246,12 +290,7 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
|
||||
@Override
|
||||
protected WizardPopup createPopup(WizardPopup parent, PopupStep step, Object parentValue) {
|
||||
WizardPopup popup = createListPopupStep(parent, step, parentValue);
|
||||
RootAction rootAction = getRootAction(parentValue);
|
||||
if (rootAction != null) {
|
||||
popup.setAdText((rootAction).getCaption());
|
||||
}
|
||||
return popup;
|
||||
return createListPopupStep(parent, step, parentValue);
|
||||
}
|
||||
|
||||
private WizardPopup createListPopupStep(WizardPopup parent, PopupStep step, Object parentValue) {
|
||||
@@ -261,11 +300,6 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
return super.createPopup(parent, step, parentValue);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static RootAction getRootAction(Object value) {
|
||||
return getSpecificAction(value, RootAction.class);
|
||||
}
|
||||
|
||||
private static <T> T getSpecificAction(Object value, @NotNull Class<T> clazz) {
|
||||
if (value instanceof PopupFactoryImpl.ActionItem) {
|
||||
AnAction action = ((PopupFactoryImpl.ActionItem)value).getAction();
|
||||
@@ -290,6 +324,7 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
|
||||
private class MyPopupListElementRenderer extends PopupListElementRenderer<Object> implements IconListPopupRenderer {
|
||||
|
||||
private ErrorLabel myPrefixLabel;
|
||||
private ErrorLabel myInfoLabel;
|
||||
private IconComponent myIconLabel;
|
||||
|
||||
@@ -328,26 +363,36 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
}
|
||||
myIconLabel.setIcon(myDescriptor.getIconFor(value));
|
||||
PopupElementWithAdditionalInfo additionalInfoAction = getSpecificAction(value, PopupElementWithAdditionalInfo.class);
|
||||
String infoText = additionalInfoAction != null ? additionalInfoAction.getInfoText() : null;
|
||||
updateInfoComponent(myPrefixLabel, additionalInfoAction != null ? additionalInfoAction.getPrefixInfo() : null, isSelected);
|
||||
updateInfoComponent(myInfoLabel, additionalInfoAction != null ? additionalInfoAction.getInfoText() : null, isSelected);
|
||||
}
|
||||
|
||||
private void updateInfoComponent(@NotNull ErrorLabel infoLabel, @Nullable String infoText, boolean isSelected) {
|
||||
if (infoText != null) {
|
||||
myInfoLabel.setVisible(true);
|
||||
myInfoLabel.setText(infoText);
|
||||
infoLabel.setVisible(true);
|
||||
infoLabel.setText(infoText);
|
||||
|
||||
if (isSelected) {
|
||||
setSelected(myInfoLabel);
|
||||
setSelected(infoLabel);
|
||||
}
|
||||
else {
|
||||
myInfoLabel.setBackground(getBackground());
|
||||
myInfoLabel.setForeground(JBColor.GRAY); // different foreground than for other elements
|
||||
infoLabel.setBackground(getBackground());
|
||||
infoLabel.setForeground(JBColor.GRAY); // different foreground than for other elements
|
||||
}
|
||||
}
|
||||
else {
|
||||
myInfoLabel.setVisible(false);
|
||||
infoLabel.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createItemComponent() {
|
||||
myPrefixLabel = new ErrorLabel();
|
||||
myPrefixLabel.setOpaque(true);
|
||||
myPrefixLabel.setBorder(JBUI.Borders.empty(1, 1, 1, DEFAULT_HGAP));
|
||||
Font minusOneFont = FontUtil.minusOne(myPrefixLabel.getFont());
|
||||
myPrefixLabel.setFont(minusOneFont);
|
||||
|
||||
myTextLabel = new ErrorLabel();
|
||||
myTextLabel.setOpaque(true);
|
||||
myTextLabel.setBorder(JBUI.Borders.empty(1));
|
||||
@@ -355,15 +400,19 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
|
||||
myInfoLabel = new ErrorLabel();
|
||||
myInfoLabel.setOpaque(true);
|
||||
myInfoLabel.setBorder(JBUI.Borders.empty(1, DEFAULT_HGAP, 1, 1));
|
||||
myInfoLabel.setFont(minusOneFont);
|
||||
|
||||
JPanel compoundPanel = new OpaquePanel(new BorderLayout(), JBColor.WHITE);
|
||||
myIconLabel = new IconComponent();
|
||||
myInfoLabel.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
JPanel compoundTextPanel = new OpaquePanel(new BorderLayout(), compoundPanel.getBackground());
|
||||
JPanel textPanel = new OpaquePanel(new BorderLayout(), compoundPanel.getBackground());
|
||||
compoundPanel.add(myIconLabel, BorderLayout.WEST);
|
||||
textPanel.add(myTextLabel, BorderLayout.WEST);
|
||||
textPanel.add(myInfoLabel, BorderLayout.CENTER);
|
||||
compoundPanel.add(textPanel, BorderLayout.CENTER);
|
||||
compoundTextPanel.add(myPrefixLabel, BorderLayout.WEST);
|
||||
compoundTextPanel.add(textPanel, BorderLayout.CENTER);
|
||||
compoundPanel.add(compoundTextPanel, BorderLayout.CENTER);
|
||||
return layoutComponent(compoundPanel);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,5 +19,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface PopupElementWithAdditionalInfo {
|
||||
@Nullable
|
||||
String getInfoText();
|
||||
default String getInfoText() {return null;}
|
||||
|
||||
@Nullable
|
||||
default String getPrefixInfo() {return null;}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ public class RootAction<T extends Repository> extends ActionGroup implements Pop
|
||||
|
||||
@NotNull protected final T myRepository;
|
||||
@NotNull private final ActionGroup myGroup;
|
||||
@NotNull private final String myBranchText;
|
||||
@Nullable private final String myBranchText;
|
||||
|
||||
public RootAction(@NotNull T repository, @NotNull ActionGroup actionsGroup, @NotNull String branchText) {
|
||||
public RootAction(@NotNull T repository, @NotNull ActionGroup actionsGroup, @Nullable String branchText) {
|
||||
super("", true);
|
||||
myRepository = repository;
|
||||
myGroup = actionsGroup;
|
||||
@@ -41,18 +41,13 @@ public class RootAction<T extends Repository> extends ActionGroup implements Pop
|
||||
getTemplatePresentation().setText(DvcsUtil.getShortRepositoryName(repository), false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getCaption() {
|
||||
return "Current branch in " + DvcsUtil.getShortRepositoryName(myRepository) + ": " + getInfoText();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnAction[] getChildren(@Nullable AnActionEvent e) {
|
||||
return myGroup.getChildren(e);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nullable
|
||||
@Override
|
||||
public String getInfoText() {
|
||||
return myBranchText;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 143 B |
Binary file not shown.
|
After Width: | Height: | Size: 216 B |
Binary file not shown.
|
After Width: | Height: | Size: 217 B |
Binary file not shown.
|
After Width: | Height: | Size: 143 B |
+62
-29
@@ -23,7 +23,6 @@ import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.FontPreferences;
|
||||
import com.intellij.openapi.editor.colors.ModifiableFontPreferences;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.FontComboBox;
|
||||
@@ -32,7 +31,6 @@ import com.intellij.ui.TooltipWithClickableLinks;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -61,9 +59,8 @@ public abstract class AbstractFontOptionsPanel extends JPanel implements Options
|
||||
@NotNull private final JTextField myEditorFontSizeField = new JTextField(4);
|
||||
@NotNull private final JTextField myLineSpacingField = new JTextField(4);
|
||||
private final FontComboBox myPrimaryCombo = new FontComboBox();
|
||||
private final JCheckBox myUseSecondaryFontCheckbox = new JCheckBox(ApplicationBundle.message("secondary.font"));
|
||||
private final JCheckBox myEnableLigaturesCheckbox = new JCheckBox(ApplicationBundle.message("use.ligatures"));
|
||||
private final FontComboBox mySecondaryCombo = new FontComboBox(false, false);
|
||||
private final FontComboBox mySecondaryCombo = new FontComboBox(false, false, true);
|
||||
|
||||
@NotNull private final JBCheckBox myOnlyMonospacedCheckBox =
|
||||
new JBCheckBox(ApplicationBundle.message("checkbox.show.only.monospaced.fonts"));
|
||||
@@ -72,30 +69,67 @@ public abstract class AbstractFontOptionsPanel extends JPanel implements Options
|
||||
private JLabel myPrimaryLabel;
|
||||
private JLabel mySizeLabel;
|
||||
|
||||
protected final static int ADDITIONAL_VERTICAL_GAP = 12;
|
||||
protected final static int BASE_INSET = 5;
|
||||
private JLabel mySecondaryFontLabel;
|
||||
private JLabel myLineSpacingLabel;
|
||||
|
||||
protected AbstractFontOptionsPanel() {
|
||||
setLayout(new MigLayout("ins 0, gap 5, flowx"));
|
||||
initControls();
|
||||
setLayout(new FlowLayout(FlowLayout.LEFT));
|
||||
add(createControls());
|
||||
}
|
||||
|
||||
protected JComponent createControls() {
|
||||
return createFontSettingsPanel();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void initControls() {
|
||||
add(myOnlyMonospacedCheckBox, "newline 10, sgx b, sx 2");
|
||||
protected final JPanel createFontSettingsPanel() {
|
||||
JPanel fontPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
c.insets = JBUI.insets(BASE_INSET, BASE_INSET, 0, 0);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
myPrimaryLabel = new JLabel(ApplicationBundle.message("primary.font"));
|
||||
add(myPrimaryLabel, "newline, ax right");
|
||||
add(myPrimaryCombo, "sgx b");
|
||||
fontPanel.add(myPrimaryLabel, c);
|
||||
|
||||
c.gridx = 1;
|
||||
fontPanel.add(myPrimaryCombo, c);
|
||||
|
||||
c.gridx = 2;
|
||||
fontPanel.add(myOnlyMonospacedCheckBox, c);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 1;
|
||||
mySizeLabel = new JLabel(ApplicationBundle.message("editbox.font.size"));
|
||||
add(mySizeLabel, "gapleft 20");
|
||||
add(myEditorFontSizeField);
|
||||
add(new JLabel(ApplicationBundle.message("editbox.line.spacing")), "gapleft 20");
|
||||
add(myLineSpacingField);
|
||||
fontPanel.add(mySizeLabel, c);
|
||||
|
||||
c.gridx = 1;
|
||||
fontPanel.add(myEditorFontSizeField, c);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 2;
|
||||
myLineSpacingLabel = new JLabel(ApplicationBundle.message("editbox.line.spacing"));
|
||||
myLineSpacingLabel.setLabelFor(myLineSpacingField);
|
||||
fontPanel.add(myLineSpacingLabel, c);
|
||||
c.gridx = 1;
|
||||
fontPanel.add(myLineSpacingField,c);
|
||||
|
||||
c.gridy = 3;
|
||||
c.gridx = 0;
|
||||
c.insets = JBUI.insets(BASE_INSET + ADDITIONAL_VERTICAL_GAP, BASE_INSET, 0, 0);
|
||||
mySecondaryFontLabel = new JLabel(ApplicationBundle.message("secondary.font"));
|
||||
mySecondaryFontLabel.setLabelFor(mySecondaryCombo);
|
||||
fontPanel.add(mySecondaryFontLabel, c);
|
||||
c.gridx = 1;
|
||||
fontPanel.add(mySecondaryCombo, c);
|
||||
c.gridx = 2;
|
||||
JLabel fallbackLabel = new JLabel(ApplicationBundle.message("label.fallback.fonts.list.description"));
|
||||
fallbackLabel.setEnabled(false);
|
||||
fontPanel.add(fallbackLabel, c);
|
||||
|
||||
add(new JLabel(ApplicationBundle.message("label.fallback.fonts.list.description"),
|
||||
MessageType.INFO.getDefaultIcon(),
|
||||
SwingConstants.LEFT), "newline, sx 5");
|
||||
add(myUseSecondaryFontCheckbox, "newline, ax right");
|
||||
add(mySecondaryCombo, "sgx b");
|
||||
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||
myEnableLigaturesCheckbox.setBorder(null);
|
||||
panel.add(myEnableLigaturesCheckbox);
|
||||
@@ -108,10 +142,12 @@ public abstract class AbstractFontOptionsPanel extends JPanel implements Options
|
||||
warningIcon.setBorder(JBUI.Borders.emptyLeft(5));
|
||||
warningIcon.setVisible(!SystemInfo.isJetBrainsJvm);
|
||||
panel.add(warningIcon);
|
||||
add(panel, "newline, sx 2");
|
||||
c.gridx = 0;
|
||||
c.gridy = 4;
|
||||
c.gridwidth = 2;
|
||||
fontPanel.add(panel, c);
|
||||
|
||||
myOnlyMonospacedCheckBox.setBorder(null);
|
||||
myUseSecondaryFontCheckbox.setBorder(null);
|
||||
mySecondaryCombo.setEnabled(false);
|
||||
|
||||
myOnlyMonospacedCheckBox.setSelected(EditorColorsManager.getInstance().isUseOnlyMonospacedFonts());
|
||||
@@ -126,10 +162,6 @@ public abstract class AbstractFontOptionsPanel extends JPanel implements Options
|
||||
mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
|
||||
mySecondaryCombo.setRenderer(RENDERER);
|
||||
|
||||
myUseSecondaryFontCheckbox.addActionListener(e -> {
|
||||
mySecondaryCombo.setEnabled(myUseSecondaryFontCheckbox.isSelected());
|
||||
syncFontFamilies();
|
||||
});
|
||||
ItemListener itemListener = this::syncFontFamilies;
|
||||
myPrimaryCombo.addItemListener(itemListener);
|
||||
mySecondaryCombo.addItemListener(itemListener);
|
||||
@@ -198,6 +230,7 @@ public abstract class AbstractFontOptionsPanel extends JPanel implements Options
|
||||
updateDescription(true);
|
||||
}
|
||||
});
|
||||
return fontPanel;
|
||||
}
|
||||
|
||||
protected void setDelegatingPreferences(boolean isDelegating) {
|
||||
@@ -249,7 +282,7 @@ public abstract class AbstractFontOptionsPanel extends JPanel implements Options
|
||||
modifiableFontPreferences.clearFonts();
|
||||
modifiableFontPreferences.setUseLigatures(myEnableLigaturesCheckbox.isSelected());
|
||||
String primaryFontFamily = myPrimaryCombo.getFontName();
|
||||
String secondaryFontFamily = mySecondaryCombo.isEnabled() ? mySecondaryCombo.getFontName() : null;
|
||||
String secondaryFontFamily = mySecondaryCombo.isNoFontSelected() ? null : mySecondaryCombo.getFontName();
|
||||
int fontSize = getFontSizeFromField();
|
||||
if (primaryFontFamily != null) {
|
||||
if (!FontPreferences.DEFAULT_FONT_NAME.equals(primaryFontFamily)) {
|
||||
@@ -276,7 +309,6 @@ public abstract class AbstractFontOptionsPanel extends JPanel implements Options
|
||||
List<String> fontFamilies = fontPreferences.getEffectiveFontFamilies();
|
||||
myPrimaryCombo.setFontName(fontPreferences.getFontFamily());
|
||||
boolean isThereSecondaryFont = fontFamilies.size() > 1;
|
||||
myUseSecondaryFontCheckbox.setSelected(isThereSecondaryFont);
|
||||
mySecondaryCombo.setFontName(isThereSecondaryFont ? fontFamilies.get(1) : null);
|
||||
myEditorFontSizeField.setText(String.valueOf(fontPreferences.getSize(fontPreferences.getFontFamily())));
|
||||
|
||||
@@ -285,12 +317,13 @@ public abstract class AbstractFontOptionsPanel extends JPanel implements Options
|
||||
boolean readOnly = isReadOnlyColorScheme || !(getFontPreferences() instanceof ModifiableFontPreferences);
|
||||
myPrimaryCombo.setEnabled(!readOnly);
|
||||
myPrimaryLabel.setEnabled(!readOnly);
|
||||
mySecondaryCombo.setEnabled(isThereSecondaryFont && !readOnly);
|
||||
mySecondaryCombo.setEnabled(!readOnly);
|
||||
mySecondaryFontLabel.setEnabled(!readOnly);
|
||||
myOnlyMonospacedCheckBox.setEnabled(!readOnly);
|
||||
myLineSpacingField.setEnabled(!readOnly);
|
||||
myLineSpacingLabel.setEnabled(!readOnly);
|
||||
myEditorFontSizeField.setEnabled(!readOnly);
|
||||
mySizeLabel.setEnabled(!readOnly);
|
||||
myUseSecondaryFontCheckbox.setEnabled(!readOnly);
|
||||
|
||||
myEnableLigaturesCheckbox.setEnabled(!readOnly && SystemInfo.isJetBrainsJvm);
|
||||
myEnableLigaturesCheckbox.setSelected(fontPreferences.useLigatures());
|
||||
|
||||
+12
-2
@@ -31,8 +31,13 @@ public class ConsoleFontOptions extends FontOptions {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getInheritFontTitle() {
|
||||
return "editor font";
|
||||
protected String getInheritedFontTitle() {
|
||||
return "Scheme font";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getOverwriteFontTitle() {
|
||||
return "Set console font for color scheme";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,6 +60,11 @@ public class ConsoleFontOptions extends FontOptions {
|
||||
return getCurrentScheme().getConsoleFontPreferences();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FontPreferences getBaseFontPreferences() {
|
||||
return getCurrentScheme().getFontPreferences();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDelegatingPreferences(boolean isDelegating) {
|
||||
FontPreferences currPrefs = getCurrentScheme().getConsoleFontPreferences();
|
||||
|
||||
@@ -21,9 +21,13 @@ import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.editor.colors.DelegatingFontPreferences;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.colors.FontPreferences;
|
||||
import com.intellij.openapi.editor.colors.impl.AppEditorFontOptions;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ex.Settings;
|
||||
import com.intellij.ui.HoverHyperlinkLabel;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -39,24 +43,53 @@ public class FontOptions extends AbstractFontOptionsPanel {
|
||||
@NotNull private final ColorAndFontOptions myOptions;
|
||||
|
||||
private @Nullable JCheckBox myInheritFontCheckbox;
|
||||
private @Nullable JLabel myBaseFontInfoLabel;
|
||||
|
||||
private final static int FONT_PANEL_LEFT_OFFSET = 15;
|
||||
|
||||
public FontOptions(@NotNull ColorAndFontOptions options) {
|
||||
myOptions = options;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String getInheritFontTitle() {
|
||||
return "default font";
|
||||
protected String getInheritedFontTitle() {
|
||||
return "Default font";
|
||||
}
|
||||
|
||||
protected String getOverwriteFontTitle() {
|
||||
return "Set font for color scheme";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initControls() {
|
||||
createInheritCheckBox();
|
||||
super.initControls();
|
||||
protected JComponent createControls() {
|
||||
Component inheritBox = createInheritCheckBox();
|
||||
if (inheritBox != null) {
|
||||
JPanel topPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
c.gridwidth = 2;
|
||||
c.insets = JBUI.insets(BASE_INSET, BASE_INSET, ADDITIONAL_VERTICAL_GAP, 0);
|
||||
c.anchor = GridBagConstraints.LINE_START;
|
||||
topPanel.add(inheritBox, c);
|
||||
c.gridy = 1;
|
||||
c.gridx = 0;
|
||||
c.gridwidth = 1;
|
||||
c.insets = JBUI.emptyInsets();
|
||||
topPanel.add(Box.createRigidArea(JBDimension.create(new Dimension(FONT_PANEL_LEFT_OFFSET, 0))), c);
|
||||
c.gridx = 1;
|
||||
c.anchor = GridBagConstraints.NORTHWEST;
|
||||
topPanel.add(createFontSettingsPanel(), c);
|
||||
return topPanel;
|
||||
}
|
||||
else {
|
||||
return super.createControls();
|
||||
}
|
||||
}
|
||||
|
||||
private void createInheritCheckBox() {
|
||||
if (getInheritFontTitle() != null) {
|
||||
@Nullable
|
||||
private Component createInheritCheckBox() {
|
||||
if (getInheritedFontTitle() != null) {
|
||||
JPanel inheritPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0,0 ));
|
||||
inheritPanel.setBorder(BorderFactory.createEmptyBorder());
|
||||
myInheritFontCheckbox = new JCheckBox();
|
||||
@@ -68,17 +101,40 @@ public class FontOptions extends AbstractFontOptionsPanel {
|
||||
}
|
||||
});
|
||||
inheritPanel.add(myInheritFontCheckbox);
|
||||
inheritPanel.add(new JLabel("Use "));
|
||||
inheritPanel.add(createHyperlinkLabel());
|
||||
|
||||
add(inheritPanel, "newline, span");
|
||||
add(new JSeparator(), "newline, growx, span");
|
||||
inheritPanel.add(new JLabel(getOverwriteFontTitle()));
|
||||
inheritPanel.add(Box.createRigidArea(JBDimension.create(new Dimension(5,0))));
|
||||
inheritPanel.add(grayed(new JLabel("(")));
|
||||
inheritPanel.add(grayed(createHyperlinkLabel()));
|
||||
inheritPanel.add(grayed(new JLabel(": ")));
|
||||
myBaseFontInfoLabel = grayed(new JLabel("?"));
|
||||
inheritPanel.add(myBaseFontInfoLabel);
|
||||
inheritPanel.add(grayed(new JLabel(")")));
|
||||
return inheritPanel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static JLabel grayed(JLabel label) {
|
||||
label.setForeground(JBColor.GRAY);
|
||||
return label;
|
||||
}
|
||||
|
||||
private String getBaseFontInfo() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
FontPreferences basePrefs = getBaseFontPreferences();
|
||||
sb.append(basePrefs.getFontFamily());
|
||||
sb.append(',');
|
||||
sb.append(basePrefs.getSize(basePrefs.getFontFamily()));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected FontPreferences getBaseFontPreferences() {
|
||||
return AppEditorFontOptions.getInstance().getFontPreferences();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JLabel createHyperlinkLabel() {
|
||||
HoverHyperlinkLabel label = new HoverHyperlinkLabel(getInheritFontTitle());
|
||||
HoverHyperlinkLabel label = new HoverHyperlinkLabel(getInheritedFontTitle());
|
||||
label.addHyperlinkListener(new HyperlinkListener() {
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent e) {
|
||||
@@ -154,6 +210,9 @@ public class FontOptions extends AbstractFontOptionsPanel {
|
||||
myInheritFontCheckbox.setEnabled(!isReadOnly());
|
||||
myInheritFontCheckbox.setSelected(isDelegating());
|
||||
}
|
||||
if (myBaseFontInfoLabel != null) {
|
||||
myBaseFontInfoLabel.setText(getBaseFontInfo());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.codeInspection.ui;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionContextImpl;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
|
||||
class CloseAction extends AnAction implements DumbAware {
|
||||
private GlobalInspectionContextImpl myContext;
|
||||
|
||||
CloseAction(GlobalInspectionContextImpl context) {
|
||||
super(CommonBundle.message("action.close"), null, AllIcons.Actions.Cancel);
|
||||
myContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myContext.close(true);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.ReviseWhenPortedToJDK;
|
||||
import com.intellij.analysis.AnalysisScope;
|
||||
import com.intellij.analysis.AnalysisUIOptions;
|
||||
@@ -30,7 +29,6 @@ import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.ui.actions.ExportHTMLAction;
|
||||
import com.intellij.codeInspection.ui.actions.InvokeQuickFixAction;
|
||||
import com.intellij.diff.util.DiffUtil;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.*;
|
||||
import com.intellij.ide.actions.ContextHelpAction;
|
||||
import com.intellij.ide.actions.exclusion.ExclusionHandler;
|
||||
@@ -46,7 +44,6 @@ import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
@@ -93,19 +90,14 @@ import java.util.List;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class InspectionResultsView extends JPanel implements Disposable, OccurenceNavigator, DataProvider {
|
||||
public class InspectionResultsView extends JPanel implements Disposable, DataProvider {
|
||||
private static final Logger LOG = Logger.getInstance(InspectionResultsView.class);
|
||||
|
||||
public static final DataKey<InspectionResultsView> DATA_KEY = DataKey.create("inspectionView");
|
||||
private static final Key<Boolean> PREVIEW_EDITOR_IS_REUSED_KEY = Key.create("inspection.tool.window.preview.editor.is.reused");
|
||||
|
||||
private final Project myProject;
|
||||
private final InspectionTree myTree;
|
||||
private final ConcurrentMap<HighlightDisplayLevel, ConcurrentMap<String, InspectionGroupNode>> myGroups =
|
||||
ContainerUtil.newConcurrentMap();
|
||||
private final ConcurrentMap<HighlightDisplayLevel, ConcurrentMap<String, InspectionGroupNode>> myGroups = ContainerUtil.newConcurrentMap();
|
||||
private final OccurenceNavigator myOccurenceNavigator;
|
||||
private volatile InspectionProfileImpl myInspectionProfile;
|
||||
private final boolean mySettingsEnabled;
|
||||
@@ -144,7 +136,6 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
public InspectionResultsView(@NotNull GlobalInspectionContextImpl globalInspectionContext,
|
||||
@NotNull InspectionRVContentProvider provider) {
|
||||
setLayout(new BorderLayout());
|
||||
myProject = globalInspectionContext.getProject();
|
||||
myInspectionProfile = globalInspectionContext.getCurrentProfile();
|
||||
myScope = globalInspectionContext.getCurrentScope();
|
||||
myGlobalInspectionContext = globalInspectionContext;
|
||||
@@ -152,12 +143,12 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
myExcludedInspectionTreeNodesManager = new ExcludedInspectionTreeNodesManager(provider instanceof OfflineInspectionRVContentProvider,
|
||||
isSingleInspectionRun());
|
||||
|
||||
myTree = new InspectionTree(myProject, globalInspectionContext, this);
|
||||
myTree = new InspectionTree(globalInspectionContext, this);
|
||||
initTreeListeners();
|
||||
|
||||
myOccurenceNavigator = initOccurenceNavigator();
|
||||
|
||||
mySplitter = new OnePixelSplitter(false, AnalysisUIOptions.getInstance(myProject).SPLITTER_PROPORTION);
|
||||
mySplitter = new OnePixelSplitter(false, AnalysisUIOptions.getInstance(globalInspectionContext.getProject()).SPLITTER_PROPORTION);
|
||||
mySplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree, SideBorder.LEFT));
|
||||
mySplitter.setHonorComponentsMinimumSize(false);
|
||||
|
||||
@@ -251,9 +242,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
}
|
||||
};
|
||||
createActionsToolbar();
|
||||
PsiManager.getInstance(myProject).addPsiTreeChangeListener(new InspectionViewPsiTreeChangeAdapter(this), this);
|
||||
PsiManager.getInstance(getProject()).addPsiTreeChangeListener(new InspectionViewPsiTreeChangeAdapter(this), this);
|
||||
|
||||
ProjectInspectionProfileManager profileManager = ProjectInspectionProfileManager.getInstance(myProject);
|
||||
ProjectInspectionProfileManager profileManager = ProjectInspectionProfileManager.getInstance(getProject());
|
||||
profileManager.addProfileChangeListener(new ProfileChangeAdapter() {
|
||||
@Override
|
||||
public void profileChanged(InspectionProfile profile) {
|
||||
@@ -364,12 +355,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
}
|
||||
|
||||
private void createActionsToolbar() {
|
||||
final JComponent leftActionsToolbar = createLeftActionsToolbar();
|
||||
final JComponent rightActionsToolbar = createRightActionsToolbar();
|
||||
|
||||
JPanel westPanel = new JPanel(new BorderLayout());
|
||||
westPanel.add(leftActionsToolbar, BorderLayout.WEST);
|
||||
westPanel.add(rightActionsToolbar, BorderLayout.EAST);
|
||||
westPanel.add(createLeftActionsToolbar(), BorderLayout.WEST);
|
||||
westPanel.add(createRightActionsToolbar(), BorderLayout.EAST);
|
||||
add(westPanel, BorderLayout.WEST);
|
||||
}
|
||||
|
||||
@@ -389,8 +377,8 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
private JComponent createLeftActionsToolbar() {
|
||||
final CommonActionsManager actionsManager = CommonActionsManager.getInstance();
|
||||
DefaultActionGroup group = new DefaultActionGroup();
|
||||
group.add(new RerunAction(this));
|
||||
group.add(new CloseAction());
|
||||
group.add(new RerunAction(this, this));
|
||||
group.add(new CloseAction(myGlobalInspectionContext));
|
||||
final TreeExpander treeExpander = new DefaultTreeExpander(myTree);
|
||||
group.add(actionsManager.createExpandAllAction(treeExpander, myTree));
|
||||
group.add(actionsManager.createCollapseAllAction(treeExpander, myTree));
|
||||
@@ -419,9 +407,8 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean isAutoScrollMode() {
|
||||
String activeToolWindowId = ToolWindowManager.getInstance(myProject).getActiveToolWindowId();
|
||||
String activeToolWindowId = ToolWindowManager.getInstance(getProject()).getActiveToolWindowId();
|
||||
return myGlobalInspectionContext.getUIOptions().AUTOSCROLL_TO_SOURCE &&
|
||||
(activeToolWindowId == null || activeToolWindowId.equals(ToolWindowId.INSPECTION));
|
||||
}
|
||||
@@ -436,27 +423,13 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
|
||||
@Nullable
|
||||
private static OpenFileDescriptor getOpenFileDescriptor(final RefElement refElement) {
|
||||
final VirtualFile[] file = new VirtualFile[1];
|
||||
final int[] offset = new int[1];
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
PsiElement psiElement = refElement.getElement();
|
||||
if (psiElement != null) {
|
||||
final PsiFile containingFile = psiElement.getContainingFile();
|
||||
if (containingFile != null) {
|
||||
file[0] = containingFile.getVirtualFile();
|
||||
offset[0] = psiElement.getTextOffset();
|
||||
}
|
||||
}
|
||||
else {
|
||||
file[0] = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (file[0] != null && file[0].isValid()) {
|
||||
return new OpenFileDescriptor(refElement.getRefManager().getProject(), file[0], offset[0]);
|
||||
}
|
||||
return null;
|
||||
PsiElement psiElement = refElement.getElement();
|
||||
if (psiElement == null) return null;
|
||||
final PsiFile containingFile = psiElement.getContainingFile();
|
||||
if (containingFile == null) return null;
|
||||
VirtualFile file = containingFile.getVirtualFile();
|
||||
if (file == null) return null;
|
||||
return new OpenFileDescriptor(refElement.getRefManager().getProject(), file, psiElement.getTextOffset());
|
||||
}
|
||||
|
||||
public void setApplyingFix(boolean applyingFix) {
|
||||
@@ -601,7 +574,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
myPreviewEditor.getMarkupModel().removeAllHighlighters();
|
||||
}
|
||||
else {
|
||||
myPreviewEditor = (EditorEx)EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true);
|
||||
myPreviewEditor = (EditorEx)EditorFactory.getInstance().createEditor(document, getProject(), file.getVirtualFile(), true);
|
||||
DiffUtil.setFoldingModelSupport(myPreviewEditor);
|
||||
final EditorSettings settings = myPreviewEditor.getSettings();
|
||||
settings.setLineNumbersShown(false);
|
||||
@@ -621,7 +594,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
return Pair.create(myPreviewEditor.getComponent(), myPreviewEditor);
|
||||
}
|
||||
if (selectedEntity == null) {
|
||||
return Pair.create(new InspectionNodeInfo(myTree, myProject), null);
|
||||
return Pair.create(new InspectionNodeInfo(myTree, getProject()), null);
|
||||
}
|
||||
if (selectedEntity.isValid()) {
|
||||
return Pair.create(InspectionResultsViewUtil.getPreviewIsNotAvailable(selectedEntity), null);
|
||||
@@ -790,7 +763,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
InspectionToolWrapper toolWrapper = state.getTool();
|
||||
if (ReadAction.compute(() -> myProvider.checkReportedProblems(myGlobalInspectionContext, toolWrapper))) {
|
||||
addTool(toolWrapper,
|
||||
profile.getErrorLevel(key, state.getScope(myProject), myProject),
|
||||
profile.getErrorLevel(key, state.getScope(getProject()), getProject()),
|
||||
isGroupedBySeverity,
|
||||
singleInspectionRun);
|
||||
}
|
||||
@@ -849,7 +822,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
if (isGroupedBySeverity) {
|
||||
InspectionSeverityGroupNode severityGroupNode = mySeverityGroupNodes.get(level);
|
||||
if (severityGroupNode == null) {
|
||||
InspectionSeverityGroupNode newNode = new InspectionSeverityGroupNode(myProject, level);
|
||||
InspectionSeverityGroupNode newNode = new InspectionSeverityGroupNode(getProject(), level);
|
||||
severityGroupNode = ConcurrencyUtil.cacheOrGet(mySeverityGroupNodes, level, newNode);
|
||||
if (severityGroupNode == newNode) {
|
||||
InspectionTreeNode root = myTree.getRoot();
|
||||
@@ -865,39 +838,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
return myOccurenceNavigator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNextOccurence() {
|
||||
return myOccurenceNavigator != null && myOccurenceNavigator.hasNextOccurence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPreviousOccurence() {
|
||||
return myOccurenceNavigator != null && myOccurenceNavigator.hasPreviousOccurence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OccurenceInfo goNextOccurence() {
|
||||
return myOccurenceNavigator != null ? myOccurenceNavigator.goNextOccurence() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OccurenceInfo goPreviousOccurence() {
|
||||
return myOccurenceNavigator != null ? myOccurenceNavigator.goPreviousOccurence() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNextOccurenceActionName() {
|
||||
return myOccurenceNavigator != null ? myOccurenceNavigator.getNextOccurenceActionName() : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreviousOccurenceActionName() {
|
||||
return myOccurenceNavigator != null ? myOccurenceNavigator.getPreviousOccurenceActionName() : "";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
return myGlobalInspectionContext.getProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1008,7 +951,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
startOffset = textRange.getStartOffset();
|
||||
}
|
||||
}
|
||||
return new OpenFileDescriptor(myProject, virtualFile, startOffset);
|
||||
return new OpenFileDescriptor(getProject(), virtualFile, startOffset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1107,44 +1050,11 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
return myDisposed;
|
||||
}
|
||||
|
||||
private class CloseAction extends AnAction implements DumbAware {
|
||||
private CloseAction() {
|
||||
super(CommonBundle.message("action.close"), null, AllIcons.Actions.Cancel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myGlobalInspectionContext.close(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCurrentProfile() {
|
||||
final String name = myInspectionProfile.getName();
|
||||
myInspectionProfile = myInspectionProfile.getProfileManager().getProfile(name);
|
||||
}
|
||||
|
||||
private class RerunAction extends AnAction {
|
||||
RerunAction(JComponent comp) {
|
||||
super(InspectionsBundle.message("inspection.action.rerun"), InspectionsBundle.message("inspection.action.rerun"),
|
||||
AllIcons.Actions.Rerun);
|
||||
registerCustomShortcutSet(CommonShortcuts.getRerun(), comp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(isRerunAvailable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
rerun();
|
||||
}
|
||||
|
||||
private void rerun() {
|
||||
InspectionResultsView.this.rerun();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRerunAvailable() {
|
||||
return !(myProvider instanceof OfflineInspectionRVContentProvider) && myScope.isValid();
|
||||
}
|
||||
@@ -1152,7 +1062,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
public void rerun() {
|
||||
myRerun = true;
|
||||
if (myScope.isValid()) {
|
||||
AnalysisUIOptions.getInstance(myProject).save(myGlobalInspectionContext.getUIOptions());
|
||||
AnalysisUIOptions.getInstance(getProject()).save(myGlobalInspectionContext.getUIOptions());
|
||||
myGlobalInspectionContext.setTreeState(getTree().getTreeState());
|
||||
myGlobalInspectionContext.doInspections(myScope);
|
||||
}
|
||||
|
||||
@@ -56,9 +56,9 @@ public class InspectionTree extends Tree {
|
||||
@NotNull private InspectionTreeState myState = new InspectionTreeState();
|
||||
private boolean myQueueUpdate;
|
||||
|
||||
public InspectionTree(@NotNull Project project,
|
||||
@NotNull GlobalInspectionContextImpl context,
|
||||
public InspectionTree(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionResultsView view) {
|
||||
Project project = context.getProject();
|
||||
setModel(new DefaultTreeModel(new InspectionRootNode(project, new InspectionTreeUpdater(view))));
|
||||
myContext = context;
|
||||
myExcludedManager = view.getExcludedManager();
|
||||
|
||||
@@ -63,14 +63,14 @@ public class InspectionTreeState {
|
||||
|
||||
private static class InspectionTreeSelectionPath {
|
||||
private final Object[] myPath;
|
||||
private final int[] myIndicies;
|
||||
private final int[] myIndices;
|
||||
|
||||
public InspectionTreeSelectionPath(TreePath path) {
|
||||
myPath = path.getPath();
|
||||
myIndicies = new int[myPath.length];
|
||||
myIndices = new int[myPath.length];
|
||||
for (int i = 0; i < myPath.length - 1; i++) {
|
||||
InspectionTreeNode node = (InspectionTreeNode)myPath[i];
|
||||
myIndicies[i + 1] = getChildIndex(node, (InspectionTreeNode)myPath[i + 1]);
|
||||
myIndices[i + 1] = getChildIndex(node, (InspectionTreeNode)myPath[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,8 +116,8 @@ public class InspectionTreeState {
|
||||
// Exactly same element not found. Trying to select somewhat near.
|
||||
int count = newRoot.getChildCount();
|
||||
if (count > 0) {
|
||||
if (myIndicies[idx] < count) {
|
||||
newPath.add(newRoot.getChildAt(myIndicies[idx]));
|
||||
if (myIndices[idx] < count) {
|
||||
newPath.add(newRoot.getChildAt(myIndices[idx]));
|
||||
}
|
||||
else {
|
||||
newPath.add(newRoot.getChildAt(count - 1));
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonShortcuts;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
class RerunAction extends AnAction {
|
||||
private final InspectionResultsView myView;
|
||||
|
||||
RerunAction(InspectionResultsView view, JComponent comp) {
|
||||
super(InspectionsBundle.message("inspection.action.rerun"), InspectionsBundle.message("inspection.action.rerun"),
|
||||
AllIcons.Actions.Rerun);
|
||||
myView = view;
|
||||
registerCustomShortcutSet(CommonShortcuts.getRerun(), comp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(myView.isRerunAvailable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
rerun();
|
||||
}
|
||||
|
||||
private void rerun() {
|
||||
myView.rerun();
|
||||
}
|
||||
}
|
||||
@@ -289,7 +289,7 @@ public class ScratchFileServiceImpl extends ScratchFileService implements Persis
|
||||
return VfsUtil.createChildSequent(LocalFileSystem.getInstance(), dir, fileName, StringUtil.notNullize(ext));
|
||||
}
|
||||
else {
|
||||
return dir.createChildData(LocalFileSystem.getInstance(), fileNameExt);
|
||||
return dir.findOrCreateChildData(LocalFileSystem.getInstance(), fileNameExt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ public class IOExceptionDialog extends DialogWrapper {
|
||||
myErrorLabel = new JTextArea();
|
||||
myErrorLabel.setEditable(false);
|
||||
myErrorLabel.setText(errorText);
|
||||
myErrorLabel.setColumns(120);
|
||||
myErrorLabel.setLineWrap(true);
|
||||
myErrorLabel.setWrapStyleWord(true);
|
||||
myErrorLabel.setFont(UIManager.getFont("Label.font"));
|
||||
|
||||
@@ -26,11 +26,13 @@ import com.intellij.util.ui.UIUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author Sergey.Malenkov
|
||||
@@ -219,9 +221,32 @@ abstract class WindowStateServiceImpl extends WindowStateService implements Pers
|
||||
|
||||
private <T> T getFor(Object object, @NotNull String key, @NotNull Class<T> type) {
|
||||
GraphicsDevice screen = getScreen(object);
|
||||
T state = get(getKey(screen, key), type);
|
||||
float scale = getSysScale(screen);
|
||||
|
||||
Function<String, T> getState = (myKey) -> {
|
||||
WindowState state = myStateMap.get(myKey);
|
||||
if (state == null) return null;
|
||||
state = state.copy().scaleDown(scale);
|
||||
if (isVisible(state)) {
|
||||
if (type == WindowState.class) {
|
||||
return (T)state;
|
||||
}
|
||||
if (type == Point.class) {
|
||||
return (T)state.getLocation();
|
||||
}
|
||||
if (type == Dimension.class) {
|
||||
return (T)state.getSize();
|
||||
}
|
||||
if (type == Rectangle.class) {
|
||||
return (T)state.getBounds();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
T state = getState.apply(getKey(screen, key));
|
||||
if (state == null) {
|
||||
state = get(getOldKey(screen, key), type);
|
||||
state = getState.apply(getOldKey(screen, key));
|
||||
}
|
||||
if (state != null) {
|
||||
return state;
|
||||
@@ -229,29 +254,7 @@ abstract class WindowStateServiceImpl extends WindowStateService implements Pers
|
||||
if (object != null) {
|
||||
return getFor(null, key, type);
|
||||
}
|
||||
return get(new KeyPair(key, 1f), type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T get(@NotNull KeyPair keyPair, @NotNull Class<T> type) {
|
||||
WindowState state = myStateMap.get(keyPair.first);
|
||||
if (state == null) return null;
|
||||
state = state.copy().scaleDown(keyPair.second);
|
||||
if (isVisible(state)) {
|
||||
if (type == WindowState.class) {
|
||||
return (T)state;
|
||||
}
|
||||
if (type == Point.class) {
|
||||
return (T)state.getLocation();
|
||||
}
|
||||
if (type == Dimension.class) {
|
||||
return (T)state.getSize();
|
||||
}
|
||||
if (type == Rectangle.class) {
|
||||
return (T)state.getBounds();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return getState.apply(key);
|
||||
}
|
||||
|
||||
private void putFor(Object object, @NotNull String key,
|
||||
@@ -261,63 +264,64 @@ abstract class WindowStateServiceImpl extends WindowStateService implements Pers
|
||||
boolean fullScreen, boolean fullScreenSet) {
|
||||
synchronized (myStateMap) {
|
||||
GraphicsDevice screen = getScreen(object);
|
||||
KeyPair oldKeyPair = getOldKey(screen, key);
|
||||
float scale = getSysScale(screen);
|
||||
|
||||
putImpl(getKey(screen, key), oldKeyPair, location, locationSet, size, sizeSet, maximized, maximizedSet, fullScreen, fullScreenSet);
|
||||
BiFunction<String, String, Void> putState = (myNewKey, myOldKey) -> {
|
||||
// remove & migrate the old key state
|
||||
WindowState oldState = myOldKey != null ? myStateMap.remove(myOldKey) : null;
|
||||
if (oldState != null) {
|
||||
oldState.scaleDown(scale);
|
||||
WindowState newState = myStateMap.get(myNewKey);
|
||||
if (newState != null) {
|
||||
newState.merge(oldState);
|
||||
} else {
|
||||
myStateMap.put(myNewKey, oldState);
|
||||
}
|
||||
}
|
||||
// put the new key state
|
||||
WindowState state = myStateMap.get(myNewKey);
|
||||
if (state != null) {
|
||||
if (state.set(location, locationSet, size, sizeSet, maximized, maximizedSet, fullScreen, fullScreenSet)) {
|
||||
state.scaleUp(scale);
|
||||
} else {
|
||||
myStateMap.remove(myNewKey);
|
||||
}
|
||||
}
|
||||
else {
|
||||
state = new WindowState();
|
||||
if (state.set(location, locationSet, size, sizeSet, maximized, maximizedSet, fullScreen, fullScreenSet)) {
|
||||
state.scaleUp(scale);
|
||||
myStateMap.put(myNewKey, state);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
putState.apply(getKey(screen, key), getOldKey(screen, key));
|
||||
if (screen != null) {
|
||||
putImpl(getKey(null, key), oldKeyPair, location, locationSet, size, sizeSet, maximized, maximizedSet, fullScreen, fullScreenSet);
|
||||
putState.apply(getKey(null, key), getOldKey(null, key));
|
||||
}
|
||||
putImpl(new KeyPair(key, 1f), oldKeyPair, location, locationSet, size, sizeSet, maximized, maximizedSet, fullScreen, fullScreenSet);
|
||||
putState.apply(key, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void putImpl(@NotNull KeyPair keyPair,
|
||||
@NotNull KeyPair oldKeyPair,
|
||||
Point location, boolean locationSet,
|
||||
Dimension size, boolean sizeSet,
|
||||
boolean maximized, boolean maximizedSet,
|
||||
boolean fullScreen, boolean fullScreenSet) {
|
||||
WindowState state = myStateMap.get(keyPair.first);
|
||||
|
||||
// may be convert the old key state to the new key
|
||||
WindowState oldState = myStateMap.remove(oldKeyPair.first);
|
||||
if (oldState != null) {
|
||||
oldState.scaleDown(oldKeyPair.second);
|
||||
if (state != null) {
|
||||
state.merge(oldState);
|
||||
} else {
|
||||
myStateMap.put(keyPair.first, state = oldState);
|
||||
}
|
||||
}
|
||||
if (state != null) {
|
||||
if (state.set(location, locationSet, size, sizeSet, maximized, maximizedSet, fullScreen, fullScreenSet)) {
|
||||
state.scaleUp(keyPair.second);
|
||||
} else {
|
||||
myStateMap.remove(keyPair.first);
|
||||
}
|
||||
}
|
||||
else {
|
||||
state = new WindowState();
|
||||
if (state.set(location, locationSet, size, sizeSet, maximized, maximizedSet, fullScreen, fullScreenSet)) {
|
||||
state.scaleUp(keyPair.second);
|
||||
myStateMap.put(keyPair.first, state);
|
||||
}
|
||||
}
|
||||
private static float getSysScale(GraphicsDevice screen) {
|
||||
return UIUtil.isJreHiDPIEnabled() && screen != null ? JBUI.sysScale(screen.getDefaultConfiguration()) : 1f;
|
||||
}
|
||||
|
||||
/*
|
||||
* todo: old hidpi-unaware key; to be removed
|
||||
*/
|
||||
@NotNull
|
||||
private static KeyPair getOldKey(GraphicsDevice screen, String key) {
|
||||
private static String getOldKey(@Nullable GraphicsDevice screen, String key) {
|
||||
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
if (environment.isHeadlessInstance()) {
|
||||
return new KeyPair(key + ".headless", 1f);
|
||||
return key + ".headless";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(key);
|
||||
float scale = 1f;
|
||||
for (GraphicsDevice device : environment.getScreenDevices()) {
|
||||
Rectangle bounds = device.getDefaultConfiguration().getBounds();
|
||||
normalizeSize(device, bounds);
|
||||
sb.append('/').append(bounds.x);
|
||||
sb.append('.').append(bounds.y);
|
||||
sb.append('.').append(bounds.width);
|
||||
@@ -325,25 +329,22 @@ abstract class WindowStateServiceImpl extends WindowStateService implements Pers
|
||||
}
|
||||
if (screen != null) {
|
||||
Rectangle bounds = screen.getDefaultConfiguration().getBounds();
|
||||
normalizeSize(screen, bounds);
|
||||
sb.append('@').append(bounds.x);
|
||||
sb.append('.').append(bounds.y);
|
||||
sb.append('.').append(bounds.width);
|
||||
sb.append('.').append(bounds.height);
|
||||
if (UIUtil.isJreHiDPIEnabled()) {
|
||||
scale = JBUI.sysScale(screen.getDefaultConfiguration());
|
||||
}
|
||||
}
|
||||
return new KeyPair(sb.toString(), scale);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static KeyPair getKey(GraphicsDevice screen, String key) {
|
||||
private static String getKey(@Nullable GraphicsDevice screen, String key) {
|
||||
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
if (environment.isHeadlessInstance()) {
|
||||
return new KeyPair(key + ".headless", 1f);
|
||||
return key + ".headless";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(key);
|
||||
float scale = 1f;
|
||||
// not storing screen x,y due to relying on isVisible(state) on key retrieval
|
||||
if (screen == null) {
|
||||
for (GraphicsDevice device : environment.getScreenDevices()) {
|
||||
@@ -360,13 +361,10 @@ abstract class WindowStateServiceImpl extends WindowStateService implements Pers
|
||||
sb.append('.').append(bounds.height);
|
||||
if (JBUI.isPixHiDPI(screen.getDefaultConfiguration())) {
|
||||
int dpi = ((int)(96 * JBUI.pixScale(screen.getDefaultConfiguration())));
|
||||
sb.append("@" + dpi + "dpi");
|
||||
}
|
||||
if (UIUtil.isJreHiDPIEnabled()) {
|
||||
scale = JBUI.sysScale(screen.getDefaultConfiguration());
|
||||
sb.append("@").append(dpi).append("dpi");
|
||||
}
|
||||
}
|
||||
return new KeyPair(sb.toString(), scale);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void normalizeSize(GraphicsDevice screen, Rectangle bounds) {
|
||||
@@ -390,15 +388,13 @@ abstract class WindowStateServiceImpl extends WindowStateService implements Pers
|
||||
}
|
||||
if (object instanceof Window) {
|
||||
Window window = (Window)object;
|
||||
object = ScreenUtil.getScreenDevice(window.getBounds());
|
||||
if (object == null) {
|
||||
LOG.warn("cannot find a screen for " + window);
|
||||
return null;
|
||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||
GraphicsDevice device = gc != null ?
|
||||
window.getGraphicsConfiguration().getDevice() : ScreenUtil.getScreenDevice(window.getBounds());
|
||||
if (device != null) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
if (object instanceof GraphicsDevice) {
|
||||
return (GraphicsDevice)object;
|
||||
}
|
||||
LOG.warn("cannot find a screen for " + object);
|
||||
return null;
|
||||
}
|
||||
@@ -492,10 +488,4 @@ abstract class WindowStateServiceImpl extends WindowStateService implements Pers
|
||||
}
|
||||
return ScreenUtil.isVisible(new Rectangle(location, size));
|
||||
}
|
||||
|
||||
private static class KeyPair extends Pair<String, Float> {
|
||||
public KeyPair(String key, Float scale) {
|
||||
super(key, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
package com.intellij.ui;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationBundle;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.util.ui.FontInfo;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.util.ArrayList;
|
||||
@@ -40,11 +42,11 @@ public final class FontComboBox extends ComboBox {
|
||||
}
|
||||
|
||||
public FontComboBox(boolean withAllStyles) {
|
||||
this(withAllStyles, true);
|
||||
this(withAllStyles, true, false);
|
||||
}
|
||||
|
||||
public FontComboBox(boolean withAllStyles, boolean filterNonLatin) {
|
||||
super(new Model(withAllStyles, filterNonLatin));
|
||||
public FontComboBox(boolean withAllStyles, boolean filterNonLatin, boolean noFontItem) {
|
||||
super(new Model(withAllStyles, filterNonLatin, noFontItem));
|
||||
Dimension size = getPreferredSize();
|
||||
size.width = size.height * 8;
|
||||
setPreferredSize(size);
|
||||
@@ -68,10 +70,14 @@ public final class FontComboBox extends ComboBox {
|
||||
return item == null ? null : item.toString();
|
||||
}
|
||||
|
||||
public void setFontName(String item) {
|
||||
public void setFontName(@Nullable String item) {
|
||||
myModel.setSelectedItem(item);
|
||||
}
|
||||
|
||||
public boolean isNoFontSelected() {
|
||||
return myModel.isNoFontSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModel(ComboBoxModel model) {
|
||||
if (model instanceof Model) {
|
||||
@@ -84,12 +90,14 @@ public final class FontComboBox extends ComboBox {
|
||||
}
|
||||
|
||||
private static final class Model extends AbstractListModel implements ComboBoxModel {
|
||||
private final NoFontItem NO_FONT_ITEM;
|
||||
private volatile List<FontInfo> myAllFonts = Collections.emptyList();
|
||||
private volatile List<FontInfo> myMonoFonts = Collections.emptyList();
|
||||
private boolean myMonospacedOnly;
|
||||
private Object mySelectedItem;
|
||||
|
||||
private Model(boolean withAllStyles, boolean filterNonLatin) {
|
||||
private Model(boolean withAllStyles, boolean filterNonLatin, boolean noFontItem) {
|
||||
NO_FONT_ITEM = noFontItem ? new NoFontItem() : null;
|
||||
Application application = ApplicationManager.getApplication();
|
||||
if (application == null || application.isUnitTestMode()) {
|
||||
setFonts(FontInfo.getAll(withAllStyles), filterNonLatin);
|
||||
@@ -132,17 +140,22 @@ public final class FontComboBox extends ComboBox {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedItem(Object item) {
|
||||
if (item instanceof FontInfo) {
|
||||
FontInfo info = getInfo(item);
|
||||
if (info == null) {
|
||||
List<FontInfo> list = myMonospacedOnly ? myMonoFonts : myAllFonts;
|
||||
item = list.isEmpty() ? null : list.get(0);
|
||||
}
|
||||
public void setSelectedItem(@Nullable Object item) {
|
||||
if (item == null && NO_FONT_ITEM != null) {
|
||||
item = NO_FONT_ITEM;
|
||||
}
|
||||
if (item instanceof String) {
|
||||
FontInfo info = getInfo(item);
|
||||
if (info != null) item = info;
|
||||
else {
|
||||
if (item instanceof FontInfo) {
|
||||
FontInfo info = getInfo(item);
|
||||
if (info == null) {
|
||||
List<FontInfo> list = myMonospacedOnly ? myMonoFonts : myAllFonts;
|
||||
item = list.isEmpty() ? null : list.get(0);
|
||||
}
|
||||
}
|
||||
if (item instanceof String) {
|
||||
FontInfo info = getInfo(item);
|
||||
if (info != null) item = info;
|
||||
}
|
||||
}
|
||||
if (!(mySelectedItem == null ? item == null : mySelectedItem.equals(item))) {
|
||||
mySelectedItem = item;
|
||||
@@ -150,16 +163,28 @@ public final class FontComboBox extends ComboBox {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNoFontSelected() {
|
||||
return getSelectedItem() == NO_FONT_ITEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
List<FontInfo> list = myMonospacedOnly ? myMonoFonts : myAllFonts;
|
||||
return mySelectedItem instanceof String ? 1 + list.size() : list.size();
|
||||
int size = list.size();
|
||||
if (mySelectedItem instanceof String) size ++;
|
||||
if (NO_FONT_ITEM != null) size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
int i = index;
|
||||
if (NO_FONT_ITEM != null) {
|
||||
if (index == 0) return NO_FONT_ITEM;
|
||||
i --;
|
||||
}
|
||||
List<FontInfo> list = myMonospacedOnly ? myMonoFonts : myAllFonts;
|
||||
return 0 <= index && index < list.size() ? list.get(index) : mySelectedItem;
|
||||
return 0 <= i && i < list.size() ? list.get(i) : mySelectedItem;
|
||||
}
|
||||
|
||||
private FontInfo getInfo(Object item) {
|
||||
@@ -170,5 +195,12 @@ public final class FontComboBox extends ComboBox {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final static class NoFontItem {
|
||||
@Override
|
||||
public String toString() {
|
||||
return ApplicationBundle.message("settings.editor.font.none");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,7 @@ import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.SyntaxTraverser;
|
||||
import com.intellij.psi.impl.PsiManagerEx;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.CachedValue;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
@@ -39,9 +35,7 @@ public class PsiErrorElementUtil {
|
||||
public static boolean hasErrors(@NotNull Project project, @NotNull VirtualFile virtualFile) {
|
||||
return ReadAction.compute(() -> {
|
||||
if (project.isDisposed() || !virtualFile.isValid()) return false;
|
||||
|
||||
PsiManagerEx psiManager = PsiManagerEx.getInstanceEx(project);
|
||||
PsiFile psiFile = psiManager.getFileManager().findFile(virtualFile);
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
|
||||
return psiFile != null && hasErrors(psiFile);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -542,10 +542,11 @@ error.a.scheme.with.this.name.already.exists.or.was.deleted.without.applying.the
|
||||
title.select.font=Select Font
|
||||
action.apply.editor.font.settings=Apply editor font settings
|
||||
checkbox.show.only.monospaced.fonts=Show only monospaced fonts
|
||||
primary.font=Primary font:
|
||||
secondary.font=Secondary font:
|
||||
primary.font=Font:
|
||||
secondary.font=Fallback font:
|
||||
use.ligatures=Enable font ligatures
|
||||
ligatures.jre.warning=<html>The JRE you are running {0} with<br>is known to have performance issues<br>related to ligatures support.<br>Use <a href="https://confluence.jetbrains.com/display/IDEADEV/JetBrains+Runtime+Environment">JetBrains Runtime</a> instead to enable ligatures.
|
||||
settings.editor.font.none=<None>
|
||||
editbox.enter.tag.name=Enter tag name:
|
||||
title.tag.name=Tag Name
|
||||
title.xml=XML
|
||||
@@ -574,7 +575,7 @@ title.scope.based=By Scope
|
||||
title.colors.and.fonts=Colors \\& Fonts
|
||||
progress.analysing.font=Analysing font: {0}
|
||||
group.editor.font=Editor Font
|
||||
label.fallback.fonts.list.description=If primary font fails, IDE tries to use the secondary one
|
||||
label.fallback.fonts.list.description=For symbols not supported by the main font
|
||||
quickdoc.tooltip.font.size.by.wheel=Slider or Ctrl+Wheel change font size
|
||||
label.font.size=Font size:
|
||||
label.font.name=Name:
|
||||
|
||||
@@ -1289,6 +1289,7 @@ public class AllIcons {
|
||||
public static final Icon Push = IconLoader.getIcon("/vcs/push.png"); // 16x16
|
||||
public static final Icon Remove = IconLoader.getIcon("/vcs/remove.png"); // 16x16
|
||||
public static final Icon ResetStrip = IconLoader.getIcon("/vcs/resetStrip.png"); // 16x16
|
||||
public static final Icon RestoreDefaultSize = IconLoader.getIcon("/vcs/restoreDefaultSize.png"); // 16x16
|
||||
public static final Icon Shelve = IconLoader.getIcon("/vcs/Shelve.png"); // 16x16
|
||||
public static final Icon ShelveSilent = IconLoader.getIcon("/vcs/shelveSilent.png"); // 16x16
|
||||
public static final Icon ShowUnversionedFiles = IconLoader.getIcon("/vcs/ShowUnversionedFiles.png"); // 16x16
|
||||
|
||||
+1
-7
@@ -31,7 +31,6 @@ import com.intellij.vcs.log.util.PersistentUtil;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@@ -130,11 +129,6 @@ public class VcsLogFullDetailsIndex<T> implements Disposable {
|
||||
if (myDisposed) throw new ProcessCanceledException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File getStorageFile(@NotNull String kind, @NotNull String id) {
|
||||
return PersistentUtil.getStorageFile(INDEX, kind, id, getVersion(), false);
|
||||
}
|
||||
|
||||
private class MyMapReduceIndex extends MapReduceIndex<Integer, T, VcsFullCommitDetails> {
|
||||
public MyMapReduceIndex(@NotNull DataIndexer<Integer, T, VcsFullCommitDetails> indexer,
|
||||
@NotNull DataExternalizer<T> externalizer,
|
||||
@@ -157,7 +151,7 @@ public class VcsLogFullDetailsIndex<T> implements Disposable {
|
||||
private static class MyMapIndexStorage<T> extends MapIndexStorage<Integer, T> {
|
||||
public MyMapIndexStorage(@NotNull String name, @NotNull String logId, @NotNull DataExternalizer<T> externalizer)
|
||||
throws IOException {
|
||||
super(VcsLogFullDetailsIndex.getStorageFile(name, logId), EnumeratorIntegerDescriptor.INSTANCE, externalizer, 5000, false);
|
||||
super(PersistentUtil.getStorageFile(INDEX, name, logId, getVersion()), EnumeratorIntegerDescriptor.INSTANCE, externalizer, 5000, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -71,7 +71,7 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex<List<VcsLogPathsInd
|
||||
|
||||
@NotNull
|
||||
private static PersistentEnumeratorBase<String> createPathsEnumerator(@NotNull String logId) throws IOException {
|
||||
File storageFile = PersistentUtil.getStorageFile(INDEX, INDEX_PATHS_IDS, logId, getVersion(), true);
|
||||
File storageFile = PersistentUtil.getStorageFile(INDEX, INDEX_PATHS_IDS, logId, getVersion());
|
||||
return new PersistentBTreeEnumerator<>(storageFile, SystemInfo.isFileSystemCaseSensitive ? EnumeratorStringDescriptor.INSTANCE
|
||||
: new ToLowerCaseStringDescriptor(),
|
||||
Page.PAGE_SIZE, null, getVersion());
|
||||
@@ -309,7 +309,8 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex<List<VcsLogPathsInd
|
||||
// case only rename in case insensitive file system
|
||||
// since ids for before and after paths are the same we just treating this rename as a modification
|
||||
data.add(new ChangeData(ChangeKind.MODIFIED, -1));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
data.add(new ChangeData(ChangeKind.RENAMED_TO, beforeId));
|
||||
List<ChangeData> beforeData = fillDataWithNulls(result, parent, beforeId);
|
||||
beforeData.add(new ChangeData(ChangeKind.RENAMED_FROM, afterId));
|
||||
|
||||
+4
-4
@@ -415,11 +415,11 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
|
||||
try {
|
||||
int version = getVersion();
|
||||
|
||||
File commitsStorage = getStorageFile(INDEX, COMMITS, logId, version, true);
|
||||
File commitsStorage = getStorageFile(INDEX, COMMITS, logId, version);
|
||||
commits = new PersistentSetImpl<>(commitsStorage, EnumeratorIntegerDescriptor.INSTANCE, Page.PAGE_SIZE, null, version);
|
||||
Disposer.register(disposable, () -> catchAndWarn(commits::close));
|
||||
|
||||
File messagesStorage = getStorageFile(INDEX, MESSAGES, logId, VcsLogStorageImpl.VERSION + MESSAGES_VERSION, true);
|
||||
File messagesStorage = getStorageFile(INDEX, MESSAGES, logId, VcsLogStorageImpl.VERSION + MESSAGES_VERSION);
|
||||
messages = new PersistentHashMap<>(messagesStorage, new IntInlineKeyDescriptor(), EnumeratorStringDescriptor.INSTANCE,
|
||||
Page.PAGE_SIZE);
|
||||
Disposer.register(disposable, () -> catchAndWarn(messages::close));
|
||||
@@ -428,9 +428,9 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
|
||||
users = new VcsLogUserIndex(logId, userRegistry, fatalErrorHandler, disposable);
|
||||
paths = new VcsLogPathsIndex(logId, roots, fatalErrorHandler, disposable);
|
||||
|
||||
File parentsStorage = getStorageFile(INDEX, PARENTS, logId, getVersion(), true);
|
||||
File parentsStorage = getStorageFile(INDEX, PARENTS, logId, version);
|
||||
parents = new PersistentHashMap<>(parentsStorage, EnumeratorIntegerDescriptor.INSTANCE,
|
||||
new IntListDataExternalizer(), Page.PAGE_SIZE, getVersion());
|
||||
new IntListDataExternalizer(), Page.PAGE_SIZE, version);
|
||||
Disposer.register(disposable, () -> catchAndWarn(parents::close));
|
||||
}
|
||||
catch (Throwable t) {
|
||||
|
||||
@@ -110,17 +110,23 @@ public class PersistentUtil {
|
||||
public static File getStorageFile(@NotNull String subdirName,
|
||||
@NotNull String kind,
|
||||
@NotNull String id,
|
||||
int version,
|
||||
boolean cleanupOldVersions) {
|
||||
int version) {
|
||||
File subdir = new File(LOG_CACHE, subdirName);
|
||||
String safeLogId = PathUtilRt.suggestFileName(id, true, true);
|
||||
File file = new File(subdir, safeLogId + "." + kind + "." + version);
|
||||
if (cleanupOldVersions && !file.exists()) {
|
||||
IOUtil.deleteAllFilesStartingWith(new File(subdir, safeLogId + "." + kind));
|
||||
File file = getFileName(kind, subdir, safeLogId, version);
|
||||
if (!file.exists()) {
|
||||
for (int oldVersion = 0; oldVersion < version; oldVersion++) {
|
||||
IOUtil.deleteAllFilesStartingWith(getFileName(kind, subdir, safeLogId, oldVersion));
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File getFileName(@NotNull String kind, @NotNull File subdir, @NotNull String safeLogId, int version) {
|
||||
return new File(subdir, safeLogId + "." + kind + "." + version);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File getCorruptionMarkerFile() {
|
||||
return new File(LOG_CACHE, CORRUPTION_MARKER);
|
||||
|
||||
+2
-2
@@ -19,7 +19,6 @@ import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameterList;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.LibraryUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ParametersPerMethodInspection extends MethodMetricInspection {
|
||||
@@ -76,7 +75,8 @@ public class ParametersPerMethodInspection extends MethodMetricInspection {
|
||||
if (parametersCount <= getLimit()) {
|
||||
return;
|
||||
}
|
||||
if (LibraryUtil.isOverrideOfLibraryMethod(method)) {
|
||||
//skip all derivatives
|
||||
if (method.findDeepestSuperMethods().length > 0) {
|
||||
return;
|
||||
}
|
||||
registerMethodError(method, Integer.valueOf(parametersCount));
|
||||
|
||||
@@ -709,7 +709,7 @@ public class InjectionsSettingsUI extends SearchableConfigurable.Parent.Abstract
|
||||
}
|
||||
|
||||
private void doImportAction(final DataContext dataContext) {
|
||||
final FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, true, false, true, false) {
|
||||
final FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, false, false, true, false) {
|
||||
@Override
|
||||
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
|
||||
return super.isFileVisible(file, showHiddenFiles) &&
|
||||
|
||||
+4
-1
@@ -16,7 +16,9 @@
|
||||
package com.siyeh.ipp.concatenation;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.psi.PsiAnnotationMethod;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ipp.base.PsiElementPredicate;
|
||||
|
||||
@@ -33,6 +35,7 @@ class SimpleStringConcatenationPredicate implements PsiElementPredicate {
|
||||
if (!ExpressionUtils.isConcatenation(element)) {
|
||||
return false;
|
||||
}
|
||||
return !(excludeConcatenationsInsideAnnotations && AnnotationUtil.isInsideAnnotation(element));
|
||||
return !(excludeConcatenationsInsideAnnotations && (AnnotationUtil.isInsideAnnotation(element) ||
|
||||
PsiTreeUtil.getParentOfType(element, PsiAnnotationMethod.class) != null));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -130,7 +130,7 @@ public class ExtractToMethodReferenceIntention extends BaseElementAtCaretIntenti
|
||||
targetMethodName + parameters, targetClass);
|
||||
PsiCodeBlock targetMethodBody = emptyMethod.getBody();
|
||||
LOG.assertTrue(targetMethodBody != null);
|
||||
targetMethodBody.addRange(elements[0], elements[elements.length - 1]);
|
||||
if (elements.length > 0) targetMethodBody.addRange(elements[0], elements[elements.length - 1]);
|
||||
|
||||
PsiMethod method = (PsiMethod)CodeStyleManager.getInstance(project).reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(targetClass.add(emptyMethod)));
|
||||
PsiMethodReferenceExpression methodReference =
|
||||
|
||||
+28
-26
@@ -16,8 +16,11 @@
|
||||
package com.siyeh.ipp.initialization;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.siyeh.IntentionPowerPackBundle;
|
||||
import com.siyeh.ipp.base.Intention;
|
||||
@@ -26,6 +29,8 @@ import com.siyeh.ipp.psiutils.HighlightUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class SplitDeclarationAndInitializationIntention extends Intention {
|
||||
|
||||
@Override
|
||||
@@ -46,58 +51,55 @@ public class SplitDeclarationAndInitializationIntention extends Intention {
|
||||
if (containingClass == null) {
|
||||
return;
|
||||
}
|
||||
final boolean fieldIsStatic =
|
||||
field.hasModifierProperty(PsiModifier.STATIC);
|
||||
final PsiClassInitializer[] classInitializers =
|
||||
containingClass.getInitializers();
|
||||
final boolean fieldIsStatic = field.hasModifierProperty(PsiModifier.STATIC);
|
||||
final PsiClassInitializer[] classInitializers = containingClass.getInitializers();
|
||||
PsiClassInitializer classInitializer = null;
|
||||
final int fieldOffset = field.getTextOffset();
|
||||
for (PsiClassInitializer existingClassInitializer : classInitializers) {
|
||||
final int initializerOffset =
|
||||
existingClassInitializer.getTextOffset();
|
||||
final int initializerOffset = existingClassInitializer.getTextOffset();
|
||||
if (initializerOffset <= fieldOffset) {
|
||||
continue;
|
||||
}
|
||||
final boolean initializerIsStatic =
|
||||
existingClassInitializer.hasModifierProperty(
|
||||
PsiModifier.STATIC);
|
||||
final boolean initializerIsStatic = existingClassInitializer.hasModifierProperty(PsiModifier.STATIC);
|
||||
if (initializerIsStatic == fieldIsStatic) {
|
||||
classInitializer = existingClassInitializer;
|
||||
break;
|
||||
Predicate<PsiReference> usedBeforeInitializer = ref -> {
|
||||
PsiElement refElement = ref.getElement();
|
||||
if (refElement == null) {
|
||||
return true;
|
||||
}
|
||||
TextRange textRange = refElement.getTextRange();
|
||||
return textRange == null || textRange.getStartOffset() < initializerOffset;
|
||||
};
|
||||
if (ReferencesSearch.search(field, new LocalSearchScope(containingClass)).findAll().stream().noneMatch(usedBeforeInitializer)) {
|
||||
classInitializer = existingClassInitializer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiManager manager = field.getManager();
|
||||
final Project project = manager.getProject();
|
||||
final PsiElementFactory elementFactory =
|
||||
JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
if (classInitializer == null) {
|
||||
classInitializer = elementFactory.createClassInitializer();
|
||||
classInitializer = (PsiClassInitializer)
|
||||
containingClass.addAfter(classInitializer, field);
|
||||
classInitializer = (PsiClassInitializer)containingClass.addAfter(classInitializer, field);
|
||||
|
||||
// add some whitespace between the field and the class initializer
|
||||
final PsiElement whitespace =
|
||||
PsiParserFacade.SERVICE.getInstance(project).createWhiteSpaceFromText("\n");
|
||||
final PsiElement whitespace = PsiParserFacade.SERVICE.getInstance(project).createWhiteSpaceFromText("\n");
|
||||
containingClass.addAfter(whitespace, field);
|
||||
}
|
||||
final PsiCodeBlock body = classInitializer.getBody();
|
||||
@NonNls final String initializationStatementText =
|
||||
field.getName() + " = " + initializerText + ';';
|
||||
final PsiExpressionStatement statement =
|
||||
(PsiExpressionStatement)elementFactory.createStatementFromText(
|
||||
initializationStatementText, body);
|
||||
@NonNls final String initializationStatementText = field.getName() + " = " + initializerText + ';';
|
||||
final PsiExpressionStatement statement = (PsiExpressionStatement)elementFactory.createStatementFromText(initializationStatementText, body);
|
||||
final PsiElement addedElement = body.add(statement);
|
||||
if (fieldIsStatic) {
|
||||
final PsiModifierList modifierList =
|
||||
classInitializer.getModifierList();
|
||||
final PsiModifierList modifierList = classInitializer.getModifierList();
|
||||
if (modifierList != null) {
|
||||
modifierList.setModifierProperty(PsiModifier.STATIC, true);
|
||||
}
|
||||
}
|
||||
initializer.delete();
|
||||
CodeStyleManager.getInstance(manager.getProject()).reformat(classInitializer);
|
||||
HighlightUtil.highlightElement(addedElement,
|
||||
IntentionPowerPackBundle.message(
|
||||
HighlightUtil.highlightElement(addedElement, IntentionPowerPackBundle.message(
|
||||
"press.escape.to.remove.highlighting.message"));
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package com.siyeh.ipp.varargs;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.ipp.base.PsiElementPredicate;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -48,29 +50,22 @@ class VarargArgumentsPredicate implements PsiElementPredicate {
|
||||
// "Unnecessarily qualified static usage" inspection
|
||||
// the psi gets into a bad state, this guards against that.
|
||||
// http://www.jetbrains.net/jira/browse/IDEADEV-40124
|
||||
final PsiReferenceExpression methodExpression =
|
||||
methodCallExpression.getMethodExpression();
|
||||
final PsiExpression qualifier =
|
||||
methodExpression.getQualifierExpression();
|
||||
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
|
||||
final PsiExpression qualifier = methodExpression.getQualifierExpression();
|
||||
if (qualifier == null) {
|
||||
final PsiReferenceParameterList typeParameterList =
|
||||
methodExpression.getParameterList();
|
||||
final PsiReferenceParameterList typeParameterList = methodExpression.getParameterList();
|
||||
if (typeParameterList != null) {
|
||||
final PsiTypeElement[] typeParameterElements =
|
||||
typeParameterList.getTypeParameterElements();
|
||||
final PsiTypeElement[] typeParameterElements = typeParameterList.getTypeParameterElements();
|
||||
if (typeParameterElements.length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
final PsiParameter lastParameter = parameters[parameters.length - 1];
|
||||
final PsiEllipsisType lastParameterType = (PsiEllipsisType)lastParameter.getType();
|
||||
final PsiType lastType = lastParameterType.getComponentType();
|
||||
final JavaResolveResult resolveResult = methodCallExpression.resolveMethodGenerics();
|
||||
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
|
||||
final PsiType substitutedType = substitutor.substitute(lastType);
|
||||
PsiType lastParameterType = PsiTypesUtil.getParameterType(parameterList.getParameters(), parametersCount - 1, true);
|
||||
final PsiType substitutedType = substitutor.substitute(lastParameterType);
|
||||
if (substitutedType instanceof PsiCapturedWildcardType) {
|
||||
final PsiCapturedWildcardType capturedWildcardType = (PsiCapturedWildcardType)substitutedType;
|
||||
if (!capturedWildcardType.getWildcard().isSuper()) {
|
||||
@@ -78,13 +73,15 @@ class VarargArgumentsPredicate implements PsiElementPredicate {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!JavaGenericsUtil.isReifiableType(substitutedType)) {
|
||||
return false;
|
||||
}
|
||||
if (arguments.length != parametersCount) {
|
||||
return true;
|
||||
}
|
||||
final PsiExpression lastExpression =
|
||||
arguments[arguments.length - 1];
|
||||
final PsiExpression expression = PsiUtil.deparenthesizeExpression(
|
||||
lastExpression);
|
||||
final PsiExpression lastExpression = arguments[arguments.length - 1];
|
||||
final PsiExpression expression = PsiUtil.deparenthesizeExpression(lastExpression);
|
||||
if (expression instanceof PsiLiteralExpression) {
|
||||
final String text = expression.getText();
|
||||
if ("null".equals(text)) {
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.siyeh.ipp.concatenation.string_builder;
|
||||
|
||||
public @interface ConstantRequiredInsideAnnotationMethod {
|
||||
String val() default "hey," <caret>+ "";
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class B {
|
||||
{
|
||||
Runnable r = () <caret>-> {} ;
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class B {
|
||||
{
|
||||
Runnable r = B::run;
|
||||
}
|
||||
|
||||
private static void run() {
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class Foo {
|
||||
static final int f<caret>1 = 2;
|
||||
static final int f2 = f1 + 1;
|
||||
|
||||
static {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
class Foo {
|
||||
static final int f1;
|
||||
|
||||
static {
|
||||
f1 = 2;
|
||||
}
|
||||
|
||||
static final int f2 = f1 + 1;
|
||||
|
||||
static {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
+1
@@ -10,6 +10,7 @@ public class ReplaceConcatenationWithStringBufferIntentionTest extends IPPTestCa
|
||||
|
||||
public void testNonStringConcatenationStart() { doTest(); }
|
||||
public void testConcatenationInsideAppend() { doTest(); }
|
||||
public void testConstantRequiredInsideAnnotationMethod() { assertIntentionNotAvailable(); }
|
||||
|
||||
@Override
|
||||
protected String getIntentionName() {
|
||||
|
||||
+4
@@ -54,6 +54,10 @@ public class ExtractToMethodReferenceTest extends IPPTestCase {
|
||||
assertIntentionNotAvailable();
|
||||
}
|
||||
|
||||
public void testEmptyCodeBlock() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testUsedLocalVariables() throws Exception {
|
||||
assertIntentionNotAvailable();
|
||||
}
|
||||
|
||||
+1
@@ -26,6 +26,7 @@ public class SplitDeclarationAndInitializationIntentionTest extends IPPTestCase
|
||||
|
||||
public void testArrayInitializer() { doTest(); }
|
||||
public void testArray() { doTest(); }
|
||||
public void testFieldUsedBeforeInitializer() { doTest(); }
|
||||
|
||||
@Override
|
||||
protected String getRelativePath() {
|
||||
|
||||
+12
@@ -58,4 +58,16 @@ public class WrapVarargArgumentsWithExplicitArrayIntentionTest extends IPPTestCa
|
||||
" }\n" +
|
||||
"}");
|
||||
}
|
||||
|
||||
public void testNonReifiable() {
|
||||
doTestIntentionNotAvailable(
|
||||
"" +
|
||||
"import java.util.*;\n" +
|
||||
"class Y {\n" +
|
||||
" <T> void m(Set<T>... t){}\n" +
|
||||
" public static void run(Set<?> s) {\n" +
|
||||
" m(/*_Wrap vararg arguments with explicit array creation*/s);\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,8 +368,9 @@ public class GitUtil {
|
||||
public static VirtualFile getGitRootOrNull(@NotNull final FilePath filePath) {
|
||||
File root = filePath.getIOFile();
|
||||
while (root != null) {
|
||||
File gitDir = findGitDir(root);
|
||||
if (gitDir != null) return LocalFileSystem.getInstance().findFileByIoFile(root);
|
||||
if (isGitRoot(root)) {
|
||||
return LocalFileSystem.getInstance().findFileByIoFile(root);
|
||||
}
|
||||
root = root.getParentFile();
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.dvcs.ui.RootAction;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.actionSystem.EmptyAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -34,7 +35,6 @@ import git4idea.repo.GitRepositoryManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -43,6 +43,7 @@ import static com.intellij.dvcs.branch.DvcsBranchPopup.MyMoreIndex.MAX_NUM;
|
||||
import static com.intellij.dvcs.ui.BranchActionGroupPopup.wrapWithMoreActionIfNeeded;
|
||||
import static com.intellij.dvcs.ui.BranchActionUtil.FAVORITE_BRANCH_COMPARATOR;
|
||||
import static com.intellij.dvcs.ui.BranchActionUtil.getNumOfTopShownBranches;
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
import static com.intellij.util.containers.ContainerUtil.map;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
@@ -64,8 +65,8 @@ class GitBranchPopup extends DvcsBranchPopup<GitRepository> {
|
||||
static GitBranchPopup getInstance(@NotNull final Project project, @NotNull GitRepository currentRepository) {
|
||||
final GitVcsSettings vcsSettings = GitVcsSettings.getInstance(project);
|
||||
Condition<AnAction> preselectActionCondition = action -> {
|
||||
if (action instanceof GitBranchPopupActions.LocalBranchActions) {
|
||||
GitBranchPopupActions.LocalBranchActions branchAction = (GitBranchPopupActions.LocalBranchActions)action;
|
||||
GitBranchPopupActions.LocalBranchActions branchAction = getBranchAction(action);
|
||||
if (branchAction != null) {
|
||||
String branchName = branchAction.getBranchName();
|
||||
|
||||
String recentBranch;
|
||||
@@ -86,6 +87,13 @@ class GitBranchPopup extends DvcsBranchPopup<GitRepository> {
|
||||
return new GitBranchPopup(currentRepository, GitUtil.getRepositoryManager(project), vcsSettings, preselectActionCondition);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static GitBranchPopupActions.LocalBranchActions getBranchAction(@NotNull AnAction action) {
|
||||
AnAction resultAction =
|
||||
action instanceof EmptyAction.MyDelegatingActionGroup ? ((EmptyAction.MyDelegatingActionGroup)action).getDelegate() : action;
|
||||
return tryCast(resultAction, GitBranchPopupActions.LocalBranchActions.class);
|
||||
}
|
||||
|
||||
private GitBranchPopup(@NotNull GitRepository currentRepository,
|
||||
@NotNull GitRepositoryManager repositoryManager,
|
||||
@NotNull GitVcsSettings vcsSettings,
|
||||
@@ -94,24 +102,6 @@ class GitBranchPopup extends DvcsBranchPopup<GitRepository> {
|
||||
preselectActionCondition, DIMENSION_SERVICE_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCurrentBranchInfo() {
|
||||
String currentBranchText = "Current branch";
|
||||
if (myRepositoryManager.moreThanOneRoot()) {
|
||||
if (myMultiRootBranchConfig.diverged()) {
|
||||
currentBranchText += " in " + DvcsUtil.getShortRepositoryName(myCurrentRepository) + ": " +
|
||||
GitBranchUtil.getDisplayableBranchText(myCurrentRepository);
|
||||
}
|
||||
else {
|
||||
currentBranchText += ": " + myMultiRootBranchConfig.getCurrentBranch();
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentBranchText += ": " + GitBranchUtil.getDisplayableBranchText(myCurrentRepository);
|
||||
}
|
||||
myPopup.setAdText(currentBranchText, SwingConstants.CENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fillWithCommonRepositoryActions(@NotNull DefaultActionGroup popupGroup,
|
||||
@NotNull AbstractRepositoryManager<GitRepository> repositoryManager) {
|
||||
@@ -122,11 +112,19 @@ class GitBranchPopup extends DvcsBranchPopup<GitRepository> {
|
||||
popupGroup.addAll(createRepositoriesActions());
|
||||
|
||||
popupGroup.addSeparator("Common Local Branches");
|
||||
List<BranchActionGroup> localBranchActions =
|
||||
myMultiRootBranchConfig.getLocalBranchNames().stream().map(l -> createLocalBranchActions(allRepositories, l)).filter(Objects::nonNull)
|
||||
.collect(toList());
|
||||
wrapWithMoreActionIfNeeded(myProject, popupGroup, ContainerUtil.sorted(localBranchActions, FAVORITE_BRANCH_COMPARATOR),
|
||||
getNumOfTopShownBranches(localBranchActions), SHOW_ALL_LOCALS_KEY, true);
|
||||
List<BranchActionGroup> localBranchActions = myMultiRootBranchConfig.getLocalBranchNames().stream()
|
||||
.map(l -> createLocalBranchActions(allRepositories, l))
|
||||
.filter(Objects::nonNull)
|
||||
.sorted(FAVORITE_BRANCH_COMPARATOR)
|
||||
.collect(toList());
|
||||
int topShownBranches = getNumOfTopShownBranches(localBranchActions);
|
||||
String currentBranch = myMultiRootBranchConfig.getCurrentBranch();
|
||||
if (currentBranch != null) {
|
||||
localBranchActions
|
||||
.add(0, new GitBranchPopupActions.CurrentBranchActions(myProject, allRepositories, currentBranch, myCurrentRepository));
|
||||
topShownBranches++;
|
||||
}
|
||||
wrapWithMoreActionIfNeeded(myProject, popupGroup, localBranchActions, topShownBranches, SHOW_ALL_LOCALS_KEY, true);
|
||||
popupGroup.addSeparator("Common Remote Branches");
|
||||
|
||||
List<BranchActionGroup> remoteBranchActions = map(((GitMultiRootBranchConfig)myMultiRootBranchConfig).getRemoteBranches(),
|
||||
@@ -154,7 +152,7 @@ class GitBranchPopup extends DvcsBranchPopup<GitRepository> {
|
||||
popupGroup.addSeparator("Repositories");
|
||||
List<ActionGroup> rootActions = DvcsUtil.sortRepositories(myRepositoryManager.getRepositories()).stream()
|
||||
.map(repo -> new RootAction<>(repo, new GitBranchPopupActions(repo.getProject(), repo).createActions(),
|
||||
GitBranchUtil.getDisplayableBranchText(repo))).collect(toList());
|
||||
isBranchesDiverged() ? GitBranchUtil.getDisplayableBranchText(repo) : null)).collect(toList());
|
||||
wrapWithMoreActionIfNeeded(myProject, popupGroup, rootActions, rootActions.size() > MAX_NUM ? DEFAULT_NUM : MAX_NUM,
|
||||
SHOW_ALL_REPOSITORIES);
|
||||
return popupGroup;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user