Merge remote-tracking branch 'origin/master'

This commit is contained in:
Konstantin Bulenkov
2017-06-06 00:13:41 +02:00
185 changed files with 2820 additions and 1302 deletions
@@ -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));
}
}
}
@@ -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));
}
@@ -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;
@@ -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;
}
}
}
@@ -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()));
@@ -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;
}
@@ -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();
@@ -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;
@@ -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) {
@@ -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) {
@@ -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();
@@ -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++) { }
}
}
@@ -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> {
}
@@ -0,0 +1,5 @@
class A {
{
Runnable r = Syst::setOu<caret>
}
}
@@ -0,0 +1,5 @@
class A {
{
Runnable r = System::setOut;<caret>
}
}
@@ -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;}
}
@@ -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;}
}
@@ -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>());
}
}
@@ -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")
}
}
@@ -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();
@@ -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,
@@ -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,
@@ -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() {
@@ -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)) {
@@ -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);
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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[]{});
}
@@ -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);
}
@@ -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

@@ -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());
@@ -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
@@ -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));
@@ -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);
@@ -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) &&
@@ -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));
}
}
@@ -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 =
@@ -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)) {
@@ -0,0 +1,5 @@
package com.siyeh.ipp.concatenation.string_builder;
public @interface ConstantRequiredInsideAnnotationMethod {
String val() default "hey," <caret>+ "";
}
@@ -0,0 +1,5 @@
class B {
{
Runnable r = () <caret>-> {} ;
}
}
@@ -0,0 +1,8 @@
class B {
{
Runnable r = B::run;
}
private static void run() {
}
}
@@ -0,0 +1,8 @@
class Foo {
static final int f<caret>1 = 2;
static final int f2 = f1 + 1;
static {
System.out.println();
}
}
@@ -0,0 +1,13 @@
class Foo {
static final int f1;
static {
f1 = 2;
}
static final int f2 = f1 + 1;
static {
System.out.println();
}
}
@@ -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() {
@@ -54,6 +54,10 @@ public class ExtractToMethodReferenceTest extends IPPTestCase {
assertIntentionNotAvailable();
}
public void testEmptyCodeBlock() throws Exception {
doTest();
}
public void testUsedLocalVariables() throws Exception {
assertIntentionNotAvailable();
}
@@ -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() {
@@ -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" +
"}");
}
}
+3 -2
View File
@@ -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