diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java index 4ce54e2aae20..8a085f2bb25b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java @@ -41,7 +41,7 @@ public class ExcludeFromCompletionLookupActionProvider implements LookupActionPr } else if (o instanceof PsiMethod) { final PsiMethod method = (PsiMethod)o; if (method.hasModifierProperty(PsiModifier.STATIC)) { - addExcludes(consumer, method, StaticImportMethodFix.getMethodQualifiedName(method)); + addExcludes(consumer, method, StaticImportMethodFix.getMemberQualifiedName(method)); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java index 445543400def..2cc6240c91c0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java @@ -3,9 +3,10 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.DefaultLookupItemRenderer; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementPresentation; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMember; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -16,92 +17,54 @@ import static com.intellij.util.ObjectUtils.assertNotNull; * @author peter */ public class JavaGlobalMemberLookupElement extends LookupElement implements StaticallyImportable { - private final PsiMember myMember; - private final boolean myMergedOverloads; - private final PsiClass myContainingClass; + private final MemberLookupHelper myHelper; private final InsertHandler myQualifiedInsertion; private final InsertHandler myImportInsertion; - private boolean myShouldImport = false; public JavaGlobalMemberLookupElement(List overloads, PsiClass containingClass, InsertHandler qualifiedInsertion, InsertHandler importInsertion, boolean shouldImport) { - myMember = overloads.get(0); - myContainingClass = containingClass; + myHelper = new MemberLookupHelper(overloads, containingClass, shouldImport); myQualifiedInsertion = qualifiedInsertion; myImportInsertion = importInsertion; - myShouldImport = shouldImport; - myMergedOverloads = true; } public JavaGlobalMemberLookupElement(PsiMember member, PsiClass containingClass, InsertHandler qualifiedInsertion, InsertHandler importInsertion, boolean shouldImport) { - myMember = member; - myContainingClass = containingClass; + myHelper = new MemberLookupHelper(member, containingClass, shouldImport, false); myQualifiedInsertion = qualifiedInsertion; myImportInsertion = importInsertion; - myShouldImport = shouldImport; - myMergedOverloads = false; } @NotNull @Override public PsiMember getObject() { - return myMember; + return myHelper.getMember(); } @NotNull public PsiClass getContainingClass() { - return myContainingClass; + return assertNotNull(myHelper.getContainingClass()); } @NotNull @Override public String getLookupString() { - return assertNotNull(myMember.getName()); + return assertNotNull(getObject().getName()); } @Override public void renderElement(LookupElementPresentation presentation) { - final String className = myContainingClass.getName(); - presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(this, presentation.isReal())); - - final String methodName = myMember.getName(); - if (Boolean.FALSE.equals(myShouldImport) && StringUtil.isNotEmpty(className)) { - presentation.setItemText(className + "." + methodName); - } else { - presentation.setItemText(methodName); - } - - final String qname = myContainingClass.getQualifiedName(); - String location = StringUtil.isEmpty(qname) ? "" : " (" + StringUtil.getPackageName(qname) + ")"; - - final String params = myMergedOverloads - ? "(...)" - : myMember instanceof PsiMethod - ? PsiFormatUtil.formatMethod((PsiMethod)myMember, PsiSubstitutor.EMPTY, - PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE) - : ""; - if (Boolean.TRUE.equals(myShouldImport) && StringUtil.isNotEmpty(className)) { - presentation.setTailText(params + " in " + className + location); - } else { - presentation.setTailText(params + location); - } - - final PsiType type = myMember instanceof PsiMethod ? ((PsiMethod)myMember).getReturnType() : ((PsiField) myMember).getType(); - if (type != null) { - presentation.setTypeText(type.getPresentableText()); - } + myHelper.renderElement(presentation, false, PsiSubstitutor.EMPTY); } @Override public void setShouldBeImported(boolean shouldImportStatic) { - myShouldImport = shouldImportStatic; + myHelper.setShouldBeImported(shouldImportStatic); } @Override @@ -111,11 +74,12 @@ public class JavaGlobalMemberLookupElement extends LookupElement implements Stat @Override public boolean willBeImported() { - return myShouldImport; + return myHelper.willBeImported(); } @Override public void handleInsert(InsertionContext context) { - (myShouldImport ? myImportInsertion : myQualifiedInsertion).handleInsert(context, this); + (willBeImported() ? myImportInsertion : myQualifiedInsertion).handleInsert(context, this); } + } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java index 649eb433e314..9368017189ee 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java @@ -1,6 +1,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementPresentation; import com.intellij.codeInsight.lookup.VariableLookupItem; import com.intellij.psi.*; import com.intellij.psi.impl.source.PostprocessReformattingAspect; @@ -20,9 +21,7 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib return; } - final PrefixMatcher matcher = result.getPrefixMatcher(); - final String prefix = matcher.getPrefix(); - if (prefix.length() == 0 || !Character.isLowerCase(prefix.charAt(0))) { + if (result.getPrefixMatcher().getPrefix().length() == 0) { return; } @@ -43,24 +42,13 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib final StaticMemberProcessor processor = new StaticMemberProcessor(position) { @NotNull @Override - protected LookupElement createLookupElement(@NotNull PsiMember member, @NotNull final PsiClass containingClass, boolean shouldImport) { + protected LookupElement createLookupElement(@NotNull PsiMember member, @NotNull final PsiClass containingClass, final boolean shouldImport) { if (member instanceof PsiMethod) { final JavaMethodCallElement element = new JavaMethodCallElement((PsiMethod)member, true, false); element.setShouldBeImported(shouldImport); return element; } - return new VariableLookupItem((PsiVariable)member) { - @Override - public void handleInsert(InsertionContext context) { - context.commitDocument(); - final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiReferenceExpression.class, false); - if (ref != null) { - ref.bindToElementViaStaticImport(containingClass); - PostprocessReformattingAspect.getInstance(ref.getProject()).doPostponedFormatting(); - } - super.handleInsert(context); - } - }; + return new StaticFieldLookupItem((PsiField)member, shouldImport, containingClass); } @Override @@ -86,4 +74,51 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib return processor; } + private static class StaticFieldLookupItem extends VariableLookupItem implements StaticallyImportable { + private final MemberLookupHelper myHelper; + private final PsiClass myContainingClass; + + public StaticFieldLookupItem(PsiField field, boolean shouldImport, PsiClass containingClass) { + super(field); + myContainingClass = containingClass; + myHelper = new MemberLookupHelper(field, containingClass, shouldImport, false); + } + + @Override + public void setShouldBeImported(boolean shouldImportStatic) { + myHelper.setShouldBeImported(shouldImportStatic); + } + + @Override + public boolean canBeImported() { + return true; + } + + @Override + public boolean willBeImported() { + return myHelper.willBeImported(); + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + super.renderElement(presentation); + myHelper.renderElement(presentation, getAttribute(FORCE_QUALIFY) != null, PsiSubstitutor.EMPTY); + } + + @Override + public void handleInsert(InsertionContext context) { + if (willBeImported()) { + context.commitDocument(); + final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiReferenceExpression.class, false); + if (ref != null) { + ref.bindToElementViaStaticImport(myContainingClass); + PostprocessReformattingAspect.getInstance(ref.getProject()).doPostponedFormatting(); + } + } else { + context.getDocument().insertString(context.getStartOffset(), "."); + JavaCompletionUtil.insertClassReference(myContainingClass, context.getFile(), context.getStartOffset()); + } + super.handleInsert(context); + } + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index eaa74241a230..406addec2c41 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -24,9 +24,7 @@ import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.ClassConditionKey; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,9 +37,7 @@ public class JavaMethodCallElement extends LookupItem implements Type private static final Key INFERENCE_SUBSTITUTOR = Key.create("INFERENCE_SUBSTITUTOR"); @Nullable private final PsiClass myContainingClass; private final PsiMethod myMethod; - private final boolean myCanImportStatic; - private boolean myShouldImportStatic; - private final boolean myMergedOverloads; + private final MemberLookupHelper myHelper; public JavaMethodCallElement(@NotNull PsiMethod method) { this(method, false, false); @@ -50,9 +46,8 @@ public class JavaMethodCallElement extends LookupItem implements Type public JavaMethodCallElement(PsiMethod method, boolean canImportStatic, boolean mergedOverloads) { super(method, method.getName()); myMethod = method; - myMergedOverloads = mergedOverloads; myContainingClass = method.getContainingClass(); - myCanImportStatic = canImportStatic; + myHelper = canImportStatic ? new MemberLookupHelper(method, myContainingClass, false, mergedOverloads) : null; } public PsiType getType() { @@ -77,18 +72,17 @@ public class JavaMethodCallElement extends LookupItem implements Type @Override public void setShouldBeImported(boolean shouldImportStatic) { - assert myCanImportStatic; - myShouldImportStatic = shouldImportStatic; + myHelper.setShouldBeImported(shouldImportStatic); } @Override public boolean canBeImported() { - return myCanImportStatic; + return myHelper != null; } @Override public boolean willBeImported() { - return myShouldImportStatic; + return canBeImported() && myHelper.willBeImported(); } @Override @@ -108,9 +102,9 @@ public class JavaMethodCallElement extends LookupItem implements Type qualifyMethodCall(file, startOffset, document); insertExplicitTypeParameters(context, refStart); } - else if (myCanImportStatic || getAttribute(FORCE_QUALIFY) != null) { + else if (myHelper != null || getAttribute(FORCE_QUALIFY) != null) { context.commitDocument(); - if (myCanImportStatic && myShouldImportStatic) { + if (myHelper != null && willBeImported()) { final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(file, startOffset, PsiReferenceExpression.class, false); if (ref != null && myContainingClass != null) { ref.bindToElementViaStaticImport(myContainingClass); @@ -234,38 +228,12 @@ public class JavaMethodCallElement extends LookupItem implements Type @Override public void renderElement(LookupElementPresentation presentation) { - final String className = myContainingClass == null ? "???" : myContainingClass.getName(); - presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(this, presentation.isReal())); - final String methodName = myMethod.getName(); - final boolean qualify = myCanImportStatic && !myShouldImportStatic || getAttribute(FORCE_QUALIFY) != null; - if (qualify && StringUtil.isNotEmpty(className)) { - presentation.setItemText(className + "." + methodName); - } else { - presentation.setItemText(methodName); - } - - final String qname = myContainingClass == null ? "" : myContainingClass.getQualifiedName(); - String location = !myCanImportStatic || StringUtil.isEmpty(qname) ? "" : " (" + StringUtil.getPackageName(qname) + ")"; - presentation.setStrikeout(JavaElementLookupRenderer.isToStrikeout(this)); presentation.setItemTextBold(getAttribute(HIGHLIGHTED_ATTR) != null); - final String params = myMergedOverloads - ? "(...)" - : PsiFormatUtil.formatMethod(myMethod, PsiSubstitutor.EMPTY, - PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE); - if (myShouldImportStatic && StringUtil.isNotEmpty(className)) { - presentation.setTailText(params + " in " + className + location); - } else { - presentation.setTailText(params + location); - } - - final PsiType type = myMethod.getReturnType(); - if (type != null) { - presentation.setTypeText(getSubstitutor().substitute(type).getPresentableText()); - } + MemberLookupHelper helper = myHelper != null ? myHelper : new MemberLookupHelper(myMethod, myContainingClass, false, false); + helper.renderElement(presentation, getAttribute(FORCE_QUALIFY) != null, getSubstitutor()); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java new file mode 100644 index 000000000000..c36c9f9c7fd1 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java @@ -0,0 +1,82 @@ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiFormatUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author peter + */ +public class MemberLookupHelper { + private final PsiMember myMember; + private final boolean myMergedOverloads; + @Nullable private final PsiClass myContainingClass; + private boolean myShouldImport = false; + + public MemberLookupHelper(List overloads, PsiClass containingClass, boolean shouldImport) { + this(overloads.get(0), containingClass, shouldImport, true); + } + + public MemberLookupHelper(PsiMember member, PsiClass containingClass, boolean shouldImport, final boolean mergedOverloads) { + myMember = member; + myContainingClass = containingClass; + myShouldImport = shouldImport; + myMergedOverloads = mergedOverloads; + } + + public PsiMember getMember() { + return myMember; + } + + @Nullable + public PsiClass getContainingClass() { + return myContainingClass; + } + + public void setShouldBeImported(boolean shouldImportStatic) { + myShouldImport = shouldImportStatic; + } + + public boolean willBeImported() { + return myShouldImport; + } + + public void renderElement(LookupElementPresentation presentation, boolean forceQualify, PsiSubstitutor substitutor) { + final String className = myContainingClass == null ? "???" : myContainingClass.getName(); + + final String memberName = myMember.getName(); + if (!myShouldImport && StringUtil.isNotEmpty(className) || forceQualify) { + presentation.setItemText(className + "." + memberName); + } else { + presentation.setItemText(memberName); + } + + final String qname = myContainingClass == null ? "" : myContainingClass.getQualifiedName(); + String pkg = StringUtil.getPackageName(qname); + String location = StringUtil.isEmpty(pkg) ? "" : " (" + pkg + ")"; + + final String params = myMergedOverloads + ? "(...)" + : myMember instanceof PsiMethod + ? PsiFormatUtil.formatMethod((PsiMethod)myMember, PsiSubstitutor.EMPTY, + PsiFormatUtil.SHOW_PARAMETERS, + PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE) + : ""; + if (myShouldImport && StringUtil.isNotEmpty(className)) { + presentation.setTailText(params + " in " + className + location); + } else { + presentation.setTailText(params + location, !(myMember instanceof PsiMethod)); + } + + final PsiType type = myMember instanceof PsiMethod ? ((PsiMethod)myMember).getReturnType() : ((PsiField) myMember).getType(); + if (type != null) { + presentation.setTypeText(substitutor.substitute(type).getPresentableText()); + } + } + + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java index dab91ef6b554..c097b3a72a1d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java @@ -33,7 +33,7 @@ public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupEle enum MyResult { annoMethod, - returnKeyword, + probableKeyword, localOrParameter, superMethodParameters, normal, @@ -46,8 +46,11 @@ public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupEle public MyResult weigh(@NotNull LookupElement item) { final Object object = item.getObject(); - if (object instanceof PsiKeyword && PsiKeyword.RETURN.equals(((PsiKeyword)object).getText())) { - return MyResult.returnKeyword; + if (object instanceof PsiKeyword) { + String keyword = ((PsiKeyword)object).getText(); + if (PsiKeyword.RETURN.equals(keyword) || PsiKeyword.ELSE.equals(keyword) || PsiKeyword.FINALLY.equals(keyword)) { + return MyResult.probableKeyword; + } } if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java index 6f9a091ea05f..26d3eb7be78c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java @@ -69,13 +69,7 @@ public abstract class StaticMemberProcessor { if (classes.add(containingClass) && JavaCompletionUtil.isSourceLevelAccessible(myPosition, containingClass, myPackagedContext)) { final boolean shouldImport = myStaticImportedClasses.contains(containingClass); - if (!myHintShown && !shouldImport && CompletionService.getCompletionService().getAdvertisementText() == null) { - final String shortcut = CompletionContributor.getActionShortcut(IdeActions.ACTION_SHOW_INTENTION_ACTIONS); - if (shortcut != null) { - CompletionService.getCompletionService().setAdvertisementText("To import a method statically, press " + shortcut); - } - myHintShown = true; - } + showHint(shouldImport); final PsiMethod[] allMethods = containingClass.getAllMethods(); final List overloads = ContainerUtil.findAll(allMethods, new Condition() { @@ -100,6 +94,32 @@ public abstract class StaticMemberProcessor { } } } + for (final String fieldName : namesCache.getAllFieldNames()) { + if (matcher.prefixMatches(fieldName)) { + for (final PsiField field : namesCache.getFieldsByName(fieldName, scope)) { + if (isStaticallyImportable(field)) { + final PsiClass containingClass = field.getContainingClass(); + assert containingClass != null; + + if (JavaCompletionUtil.isSourceLevelAccessible(myPosition, containingClass, myPackagedContext)) { + final boolean shouldImport = myStaticImportedClasses.contains(containingClass); + showHint(shouldImport); + consumer.consume(createLookupElement(field, containingClass, shouldImport)); + } + } + } + } + } + } + + private void showHint(boolean shouldImport) { + if (!myHintShown && !shouldImport && CompletionService.getCompletionService().getAdvertisementText() == null) { + final String shortcut = CompletionContributor.getActionShortcut(IdeActions.ACTION_SHOW_INTENTION_ACTIONS); + if (shortcut != null) { + CompletionService.getCompletionService().setAdvertisementText("To import a method statically, press " + shortcut); + } + myHintShown = true; + } } public List processMembersOfRegisteredClasses(@Nullable final PrefixMatcher matcher, PairConsumer consumer) { @@ -113,7 +133,7 @@ public abstract class StaticMemberProcessor { } } for (final PsiField field : psiClass.getAllFields()) { - if (matcher == null || matcher.prefixMatches(field.getName())) { + if (matcher == null || matcher.prefixMatches(field. getName())) { if (isStaticallyImportable(field)) { consumer.consume(field, psiClass); } @@ -125,17 +145,11 @@ public abstract class StaticMemberProcessor { private boolean isStaticallyImportable(final PsiMember member) { - if (member.hasModifierProperty(PsiModifier.STATIC) && myResolveHelper.isAccessible(member, myPosition, null)) { - final PsiClass containingClass = member.getContainingClass(); - if (containingClass != null) { - if (!JavaCompletionUtil.isInExcludedPackage(containingClass) && - (!(member instanceof PsiMethod) || !StaticImportMethodFix.isExcluded((PsiMethod)member))) { - return true; - } + return member.hasModifierProperty(PsiModifier.STATIC) && isAccessible(member) && !StaticImportMethodFix.isExcluded(member); + } - } - } - return false; + protected boolean isAccessible(PsiMember member) { + return myResolveHelper.isAccessible(member, myPosition, null); } @NotNull diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java index 00cd3419a7a2..16f10641c9db 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.completion.scope; import com.intellij.codeInsight.CodeInsightSettings; +import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.daemon.ImplicitUsageProvider; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; @@ -109,7 +110,8 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme } } - private static boolean isInitializedImplicitly(final PsiField field) { + private static boolean isInitializedImplicitly(PsiField field) { + field = JavaCompletionUtil.getOriginalElement(field); for(ImplicitUsageProvider provider: ImplicitUsageProvider.EP_NAME.getExtensions()) { if (provider.isImplicitWrite(field)) { return true; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java index cc2a3d8a1a9d..1a83dbafc824 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java @@ -142,8 +142,8 @@ public class StaticImportMethodFix implements IntentionAction { return result; } - public static boolean isExcluded(PsiMethod method) { - String name = getMethodQualifiedName(method); + public static boolean isExcluded(PsiMember method) { + String name = getMemberQualifiedName(method); if (name == null) return false; CodeInsightSettings cis = CodeInsightSettings.getInstance(); for (String excluded : cis.EXCLUDED_PACKAGES) { @@ -204,7 +204,7 @@ public class StaticImportMethodFix implements IntentionAction { return FINAL_CHOICE; } - String qname = getMethodQualifiedName(selectedValue); + String qname = getMemberQualifiedName(selectedValue); if (qname == null) return FINAL_CHOICE; List excludableStrings = AddImportAction.getAllExcludableStrings(qname); return new BaseListPopupStep(null, excludableStrings) { @@ -270,7 +270,7 @@ public class StaticImportMethodFix implements IntentionAction { } @Nullable - public static String getMethodQualifiedName(PsiMethod method) { + public static String getMemberQualifiedName(PsiMember method) { PsiClass containingClass = method.getContainingClass(); if (containingClass == null) return null; String className = containingClass.getQualifiedName(); diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java index f3e6e8355069..45db8746f149 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java @@ -6,6 +6,7 @@ import com.intellij.codeInsight.completion.CodeCompletionFeatures; import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; @@ -35,6 +36,12 @@ public class VariableLookupItem extends LookupItem implements Typed public void handleInsert(InsertionContext context) { super.handleInsert(context); + PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument()); + PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset() - 1, PsiReferenceExpression.class, false); + if (ref != null) { + JavaCodeStyleManager.getInstance(context.getProject()).shortenClassReferences(ref); + } + final char completionChar = context.getCompletionChar(); if (completionChar == '=') { context.setAddCompletionChar(false); @@ -53,7 +60,6 @@ public class VariableLookupItem extends LookupItem implements Typed } else if (completionChar == '!' && PsiType.BOOLEAN.isAssignableFrom(getObject().getType())) { context.setAddCompletionChar(false); - final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset() - 1, PsiReferenceExpression.class, false); if (ref != null) { FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EXCLAMATION_FINISH); context.getDocument().insertString(ref.getTextRange().getStartOffset(), "!"); diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index a1ec2cffbd32..746a89e87d02 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -23,6 +23,7 @@ import com.intellij.lexer.Lexer; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; @@ -238,6 +239,19 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { else if (myRole2 == ChildRole.RBRACE && aClass.isEnum()) { createParenthSpace(true, false); } + else if (aClass instanceof PsiAnonymousClass && ElementType.JAVA_PLAIN_COMMENT_BIT_SET.contains(myChild1.getElementType())) { + ASTNode prev = myChild1.getTreePrev(); + if (prev.getElementType() == JavaTokenType.WHITE_SPACE && !StringUtil.containsLineBreak(prev.getChars())) { + prev = prev.getTreePrev(); + } + if (prev.getElementType() == JavaTokenType.LBRACE) { + myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER + 1, + mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); + } + else { + processClassBody(); + } + } else processClassBody(); } diff --git a/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java b/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java index dee79cdc942c..7d510277860e 100644 --- a/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java +++ b/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java @@ -34,6 +34,8 @@ public class KnownElementWeigher extends ProximityWeigher { if (qname != null) { if (qname.startsWith("java.")) return 2; if (qname.startsWith("javax.")) return 1; + if (qname.startsWith("com.")) return -1; + if (qname.startsWith("net.")) return -1; } } if (element instanceof PsiMethod) { diff --git a/java/java-tests/testData/codeInsight/completion/normal/InnerEnumConstant.java b/java/java-tests/testData/codeInsight/completion/normal/InnerEnumConstant.java new file mode 100644 index 000000000000..4b557c29164a --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/InnerEnumConstant.java @@ -0,0 +1,9 @@ +class Foo { + { + Bar b = FOOOO + } + + enum Bar { + FOOOOOOO + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/InnerEnumConstant_after.java b/java/java-tests/testData/codeInsight/completion/normal/InnerEnumConstant_after.java new file mode 100644 index 000000000000..94b578f6a76c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/InnerEnumConstant_after.java @@ -0,0 +1,9 @@ +class Foo { + { + Bar b = Bar.FOOOOOOO + } + + enum Bar { + FOOOOOOO + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreferElse.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferElse.java new file mode 100644 index 000000000000..45ab274ba65b --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferElse.java @@ -0,0 +1,8 @@ +class Foo { + { + Object element; + if (true) {} + el + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy index 79cbccaa99a5..2cf4238f1f49 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy @@ -24,6 +24,36 @@ public class Foo { class Bar {{ abcmethod() }}""" } + public void testFieldName() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcfield = 2 + static final int fieldThatsNotVisible = 3 +} +""") + + doTest "class Bar {{ abcf }}", true, """import static foo.Foo.abcfield; + +class Bar {{ abcfield }}""" + } + + public void testFieldNameQualified() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcfield = 2 + static final int fieldThatsNotVisible = 3 +} +""") + + doTest "class Bar {{ abcf }}", false, """import foo.Foo; + +class Bar {{ Foo.abcfield }}""" + } + public void testQualifiedMethodName() throws Exception { myFixture.addClass(""" package foo; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java index 5346d9e479cd..787b21cc96f6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java @@ -217,6 +217,10 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { checkPreferredItems(0, "private", "protected", "public", "paaa", "paab"); } + public void testPreferElse() { + checkPreferredItems(0, "else", "element"); + } + public void testPreferSamePackageOverImported() { myFixture.addClass("package bar; public class Bar1 {}"); myFixture.addClass("package bar; public class Bar2 {}"); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index d5e7c2a1f642..f87548f6f112 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -514,6 +514,8 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { public void testFieldWithCastingCaret() throws Throwable { doTest(); } + public void testInnerEnumConstant() throws Throwable { doTest('\n'); } + public void testMethodReturnType() throws Throwable { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index 8f90525530a4..d58532489034 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -431,9 +431,15 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testPrivateOverloads() throws Throwable { doTest(); } - public void testCastAutoboxing() throws Throwable { doActionItemTest(); } - public void testCastAutoboxing2() throws Throwable { doActionItemTest(); } - public void testCastAutoboxing3() throws Throwable { doActionItemTest(); } + public void testCastAutoboxing() throws Throwable { + doItemTest(); + } + public void testCastAutoboxing2() throws Throwable { + doItemTest(); + } + public void testCastAutoboxing3() throws Throwable { + doItemTest(); + } public void testCastWildcards() throws Throwable { doTest(); } public void testNoSecondMethodTypeArguments() throws Throwable { doTest(Lookup.REPLACE_SELECT_CHAR); } @@ -772,17 +778,17 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { } public void testClassLiteralInAnno2() throws Throwable { - doActionItemTest(); + doItemTest(); } public void testClassLiteralInheritors() throws Throwable { - doActionItemTest(); + doItemTest(); } public void testInsertOverride() throws Exception { CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(getProject()); styleSettings.INSERT_OVERRIDE_ANNOTATION = true; - doActionItemTest(); + doItemTest(); } public void testForeach() throws Exception { @@ -952,7 +958,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testCastToParameterizedType() throws Throwable { doActionTest(); } public void testInnerEnumInMethod() throws Throwable { - doActionItemTest(); + doItemTest(); } public void testEnumAsDefaultAnnotationParam() throws Throwable { doTest(); } @@ -1023,27 +1029,13 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { doFirstItemTest('\t'); } - private void doTest(boolean performAction, boolean selectItem) throws Exception { + private void doActionTest() throws Exception { configureByTestName(); - if (performAction) { - performAction(); - } - if (selectItem) { - selectItem(myFixture.getLookupElements()[0]); - } checkResultByTestName(); } - private void doActionTest() throws Exception { - doTest(true, false); - } - private void doItemTest() throws Exception { - doTest(false, true); - } - - private void doActionItemTest() throws Exception { - doTest(true, true); + doFirstItemTest('\n'); } private void performAction() { diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java index 74f53a7d73a8..bf11a587f2c3 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java @@ -330,6 +330,29 @@ public class JavaFormatterBlankLinesTest extends AbstractJavaFormatterTest { ); } + public void testAfterAnonymousClassWhereCodeBlockStartsWithComment() throws Exception { + // Inspired by IDEA-66583 + getSettings().BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER = 0; + + String textWithWhiteSpaceBetweenCommentAndLbrace = + "Object object = new Object() { // comment breaks \"blank line after anonymous class header\"\n" + + " @Override\n" + + " public String toString() {\n" + + " return super.toString();\n" + + " }\n" + + "};"; + doMethodTest(textWithWhiteSpaceBetweenCommentAndLbrace, textWithWhiteSpaceBetweenCommentAndLbrace); + + String textWithoutWhiteSpaceBetweenCommentAndLbrace = + "Object object = new Object() {// comment breaks \"blank line after anonymous class header\"\n" + + " @Override\n" + + " public String toString() {\n" + + " return super.toString();\n" + + " }\n" + + "};"; + doMethodTest(textWithoutWhiteSpaceBetweenCommentAndLbrace, textWithoutWhiteSpaceBetweenCommentAndLbrace); + } + public void testBeforeMethodBody() { // Inspired by IDEA-54747 getSettings().BLANK_LINES_BEFORE_METHOD_BODY = 3; diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java index 1633629ecd9c..bf7814536d0d 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java @@ -20,6 +20,8 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.util.containers.HashMap; +import org.jdom.Content; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -33,11 +35,14 @@ import java.util.*; public class CommonCodeStyleSettingsManager implements JDOMExternalizable { private Map myCommonSettingsMap = null; + private Map myUnknownSettingsMap; + private final CodeStyleSettings myParentSettings; private static final String COMMON_SETTINGS_TAG = "codeStyleSettings"; private static final String LANGUAGE_ATTR = "language"; + public CommonCodeStyleSettingsManager(CodeStyleSettings parentSettings) { myParentSettings = parentSettings; } @@ -101,6 +106,7 @@ public class CommonCodeStyleSettingsManager implements JDOMExternalizable { private void initCommonSettingsMap() { myCommonSettingsMap = new LinkedHashMap(); + myUnknownSettingsMap = new LinkedHashMap(); } private void registerCommonSettings(@NotNull Language lang, @NotNull CommonCodeStyleSettings settings) { @@ -136,6 +142,8 @@ public class CommonCodeStyleSettingsManager implements JDOMExternalizable { final CommonCodeStyleSettings settings = defaultSettings != null ? defaultSettings : new CommonCodeStyleSettings(target); settings.readExternal(commonSettingsElement); registerCommonSettings(target, settings); + } else { + myUnknownSettingsMap.put(languageId, (Content)commonSettingsElement.clone()); } } } @@ -147,20 +155,36 @@ public class CommonCodeStyleSettingsManager implements JDOMExternalizable { @Override public void writeExternal(Element element) throws WriteExternalException { if (myCommonSettingsMap == null) return; - final Language[] languages = myCommonSettingsMap.keySet().toArray(new Language[myCommonSettingsMap.keySet().size()]); - Arrays.sort(languages, new Comparator() { - public int compare(final Language o1, final Language o2) { - return o1.getDisplayName().compareTo(o2.getDisplayName()); + + final Map id2lang = new HashMap(); + for (final Language language : myCommonSettingsMap.keySet()) { + id2lang.put(language.getID(), language); + } + + final Set langIdList = new HashSet(); + langIdList.addAll(myUnknownSettingsMap.keySet()); + langIdList.addAll(id2lang.keySet()); + + final String[] languages = langIdList.toArray(new String[langIdList.size()]); + Arrays.sort(languages, new Comparator() { + public int compare(final String o1, final String o2) { + return o1.compareTo(o2); } }); - for (Language language : languages) { - final CommonCodeStyleSettings commonSettings = myCommonSettingsMap.get(language); - Element commonSettingsElement = new Element(COMMON_SETTINGS_TAG); - commonSettings.writeExternal(commonSettingsElement); - commonSettingsElement.setAttribute(LANGUAGE_ATTR, language.getID()); - if (!commonSettingsElement.getChildren().isEmpty()) { - element.addContent(commonSettingsElement); + for (final String id : languages) { + final Language language = id2lang.get(id); + if (language != null) { + final CommonCodeStyleSettings commonSettings = myCommonSettingsMap.get(language); + Element commonSettingsElement = new Element(COMMON_SETTINGS_TAG); + commonSettings.writeExternal(commonSettingsElement); + commonSettingsElement.setAttribute(LANGUAGE_ATTR, language.getID()); + if (!commonSettingsElement.getChildren().isEmpty()) { + element.addContent(commonSettingsElement); + } + } else { + final Content unknown = myUnknownSettingsMap.get(id); + if (unknown != null) element.addContent(unknown.detach()); } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 7d003ebd1a4e..4d62dd82a611 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -53,7 +53,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.impl.PsiFileEx; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; @@ -297,15 +296,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { indicator.addItem(lookupElement); } }; - LookupElement[] result = CompletionService.getCompletionService().performCompletion(parameters, consumer); - if (NameUtil.isUseMinusculeHumpMatcher() && parameters.getInvocationCount() == 0) { - if (result.length == 0) { - result = CompletionService.getCompletionService().performCompletion(parameters.withRelaxedMatching(), consumer); - } else { - indicator.restartOnEmpty = true; - } - } - data.set(result); + data.set(CompletionService.getCompletionService().performCompletion(parameters, consumer)); } }); } @@ -357,7 +348,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { LOG.error("wrong text: copy='" + fileCopy.getText() + "'; element='" + insertedElement.getText() + "'; range=" + range); } - return new CompletionParameters(insertedElement, fileCopy.getOriginalFile(), myCompletionType, offset, invocationCount, invocationCount >= 2); + return new CompletionParameters(insertedElement, fileCopy.getOriginalFile(), myCompletionType, offset, invocationCount, false); } private AutoCompletionDecision shouldAutoComplete( diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index e77fad64b7cb..636cea0537b0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -574,8 +574,6 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } } - public boolean restartOnEmpty = false; - public void prefixUpdated() { final CharSequence text = myEditor.getDocument().getCharsSequence(); final int caretOffset = myEditor.getCaretModel().getOffset(); @@ -588,13 +586,16 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } } - if (hideAutopopupIfMeaningless() && restartOnEmpty) { - CompletionAutoPopupHandler.scheduleAutoPopup(getProject(), myEditor, getParameters().getOriginalFile()); - } + hideAutopopupIfMeaningless(); updateFocus(); } public void scheduleRestart() { + if (isAutopopupCompletion() && hideAutopopupIfMeaningless()) { + CompletionAutoPopupHandler.scheduleAutoPopup(getProject(), myEditor, getParameters().getOriginalFile()); + return; + } + cancel(); ApplicationManager.getApplication().assertIsDispatchThread(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/RelaxedMatchingContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/RelaxedMatchingContributor.java new file mode 100644 index 000000000000..94b00f7f950e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/RelaxedMatchingContributor.java @@ -0,0 +1,83 @@ +/* + * Copyright 2000-2011 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.codeInsight.completion; + +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.patterns.PatternCondition; +import com.intellij.patterns.StandardPatterns; +import com.intellij.util.Consumer; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author peter + */ +public class RelaxedMatchingContributor extends CompletionContributor { + + @Override + public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet result) { + final Set elements = new HashSet(); + result.runRemainingContributors(parameters, new Consumer() { + @Override + public void consume(LookupElement element) { + elements.add(element); + result.addElement(element); + } + }); + + if (!elements.isEmpty() && parameters.getInvocationCount() == 0) { + Set prefixes = new HashSet(); + for (LookupElement element : elements) { + prefixes.add(element.getPrefixMatcher().getPrefix()); + } + for (String prefix : prefixes) { + result.withPrefixMatcher(prefix) + .restartCompletionOnPrefixChange(StandardPatterns.string().with(new PatternCondition("noneMatch") { + @Override + public boolean accepts(@NotNull String s, ProcessingContext context) { + for (LookupElement element : elements) { + if (element.getPrefixMatcher().cloneWithPrefix(s).prefixMatches(element)) { + return false; + } + } + return true; + } + })); + } + } + + CompletionParameters relaxed; + if (elements.isEmpty() && parameters.getInvocationCount() == 0) { + relaxed = parameters.withRelaxedMatching(); + } + else if (parameters.getInvocationCount() >= 2) { + relaxed = parameters.withRelaxedMatching().withInvocationCount(parameters.getInvocationCount() - 1); + } + else { + return; + } + + result.runRemainingContributors(relaxed, new Consumer() { + @Override + public void consume(LookupElement element) { + result.addElement(element); + } + }); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java index 70a83f4454e5..ae7fd6f9295b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java @@ -49,29 +49,46 @@ public class CamelHumpMatcher extends PrefixMatcher { ourLastCompletionCaseSetting = currentSetting; } - String key = myRelaxedMatching + myPrefix; - NameUtil.Matcher pattern = ourPatternCache.get(key); - if (pattern == null) { - pattern = createCamelHumpsMatcher(); - ourPatternCache.put(key, pattern); - } - myMatcher = pattern; + myMatcher = obtainMatcher(myRelaxedMatching); } - return myMatcher.matches(name); + if (myMatcher.matches(name)) { + if (myRelaxedMatching && obtainMatcher(false).matches(name)) { + return false; + } + + return true; + } + return false; } } + private NameUtil.Matcher obtainMatcher(final boolean relax) { + String key = relax + myPrefix; + NameUtil.Matcher pattern = ourPatternCache.get(key); + if (pattern == null) { + pattern = createCamelHumpsMatcher(relax); + ourPatternCache.put(key, pattern); + } + return pattern; + } + public boolean prefixMatches(@NotNull final LookupElement element) { return prefixMatchersInternal(element, !element.isCaseSensitive()); } private boolean prefixMatchersInternal(final LookupElement element, final boolean itemCaseInsensitive) { + if (itemCaseInsensitive && myRelaxedMatching) { + return false; + } + for (final String name : element.getAllLookupStrings()) { if (itemCaseInsensitive && StringUtil.startsWithIgnoreCase(name, myPrefix) || prefixMatches(name)) { return true; } - if (itemCaseInsensitive && CodeInsightSettings.ALL != CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE && name.length() > 0) { + if (itemCaseInsensitive && + CodeInsightSettings.ALL != CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE && + name.length() > 0) { final char c = name.charAt(0); String swappedCase = (Character.isUpperCase(c) ? Character.toLowerCase(c) : Character.toUpperCase(c)) + name.substring(1); if (prefixMatches(swappedCase)) { @@ -87,12 +104,12 @@ public class CamelHumpMatcher extends PrefixMatcher { return new CamelHumpMatcher(prefix, myCaseSensitive, myRelaxedMatching); } - private NameUtil.Matcher createCamelHumpsMatcher() { + private NameUtil.Matcher createCamelHumpsMatcher(final boolean relaxedMatching) { if (!myCaseSensitive) { return NameUtil.buildCompletionMatcher(myPrefix, 0, true, true); } - if (myRelaxedMatching) { + if (relaxedMatching) { return NameUtil.buildCompletionMatcher(myPrefix, 0, true, true); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/BackspaceHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/BackspaceHandler.java index 5087e8a4e055..fc7001956284 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/BackspaceHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/BackspaceHandler.java @@ -45,6 +45,7 @@ public class BackspaceHandler extends EditorActionHandler { lookup.performGuardedChange(new Runnable() { @Override public void run() { + editor.getSelectionModel().removeSelection(); handler.execute(editor, dataContext); } }); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java index 76fa7b940f9e..548d95db32de 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java @@ -207,6 +207,7 @@ public abstract class LookupActionHandler extends EditorActionHandler { lookup.performGuardedChange(new Runnable() { @Override public void run() { + editor.getSelectionModel().removeSelection(); editor.getCaretModel().moveToOffset(offset + 1); } }); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index d448b1e4ab0a..2204558249b9 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -564,7 +564,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo myDeferredTypes.add(contentType); - s = StringUtil.convertLineSeparators(s); + s = StringUtil.convertLineSeparators(s, true); myContentSize += s.length(); myDeferredOutputLength += s.length(); StringBuilder bufferToUse; @@ -833,7 +833,13 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo myEditor.getScrollingModel().accumulateViewportChanges(); } try { - document.insertString(document.getTextLength(), text); + String[] strings = text.split("\\r"); + for (int i = 0; i < strings.length - 1; i++) { + document.insertString(document.getTextLength(), strings[i]); + int lastLine = document.getLineCount() - 1; + document.deleteString(document.getLineStartOffset(lastLine), document.getTextLength()); + } + document.insertString(document.getTextLength(), strings[strings.length - 1]); } finally { if (preserveCurrentVisualArea) { diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index cde3e2a62c58..771eb11382b5 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -383,6 +383,7 @@ + diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index acd5d2068407..618b2769094a 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -254,7 +254,12 @@ public class StringUtil { */ @NotNull public static String convertLineSeparators(@NotNull String text) { - return convertLineSeparators(text, "\n", null); + return convertLineSeparators(text, false); + } + + @NotNull + public static String convertLineSeparators(@NotNull String text, boolean keepCarriageReturn) { + return convertLineSeparators(text, "\n", null, keepCarriageReturn); } @NotNull @@ -264,6 +269,13 @@ public class StringUtil { @NotNull public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator, @Nullable int[] offsetsToKeep) { + return convertLineSeparators(text, newSeparator, offsetsToKeep, false); + } + + @NotNull + public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator, @Nullable int[] offsetsToKeep, + boolean keepCarriageReturn) + { StringBuilder buffer = null; int intactLength = 0; final boolean newSeparatorIsSlashN = "\n".equals(newSeparator); @@ -286,12 +298,22 @@ public class StringUtil { } } else if (c == '\r') { + boolean followedByLineFeed = i < text.length() - 1 && text.charAt(i + 1) == '\n'; + if (!followedByLineFeed && keepCarriageReturn) { + if (buffer == null) { + intactLength++; + } + else { + buffer.append(c); + } + continue; + } if (buffer == null) { buffer = new StringBuilder(text.length()); buffer.append(text, 0, intactLength); } buffer.append(newSeparator); - if (i < text.length() - 1 && text.charAt(i + 1) == '\n') { + if (followedByLineFeed) { i++; shiftOffsets(offsetsToKeep, buffer.length(), 2, newSeparator.length()); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java index 4471ebab97fd..ea2ac94faf5c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java @@ -172,7 +172,20 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper { return myFileHistoryPanel; } + private FileHistoryPanelImpl resetHistoryPanel() { + if (myFileHistoryPanel == null) { + ContentManager contentManager = ProjectLevelVcsManagerEx.getInstanceEx(myVcs.getProject()).getContentManager(); + final VcsHistorySession copy = mySession.copyWithCachedRevision(); + myFileHistoryPanel = new FileHistoryPanelImpl(myVcs, myPath, copy, myVcsHistoryProvider, + contentManager, myRefresher); + } else { + myFileHistoryPanel.getHistoryPanelRefresh().consume(mySession); + } + return myFileHistoryPanel; + } + public void reportCreatedEmptySession(final VcsAbstractHistorySession session) { + if (mySession != null && session != null && mySession.getRevisionList().equals(session.getRevisionList())) return; mySession = session; mySession.shouldBeRefreshed(); // to init current revision! ApplicationManager.getApplication().invokeLater(new Runnable() { @@ -180,7 +193,7 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper { String actionName = VcsBundle.message("action.name.file.history", myPath.getName()); ContentManager contentManager = ProjectLevelVcsManagerEx.getInstanceEx(myVcs.getProject()).getContentManager(); - myFileHistoryPanel = ensureHistoryPanelCreated(); + myFileHistoryPanel = resetHistoryPanel(); Content content = ContentFactory.SERVICE.getInstance().createContent(myFileHistoryPanel, actionName, true); ContentsUtil.addOrReplaceContent(contentManager, content, true); diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 0f193d548b92..1b6d627b282b 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -563,6 +563,7 @@ + 0 && super.isAccessible(getters[0]); + } + + return result; + } }; final PsiFile file = position.getContainingFile(); if (file instanceof GroovyFile) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index 7be3e79ba8f9..5dcc6ce5136d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -80,7 +80,7 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { public void testPossibleClosureParameter2() { myFixture.configureByText("a.gpp", "{ a, }") type 'h' - assert !lookup + assert !lookup.focused } public void testImpossibleClosureParameter() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy index 6ab8b945c9d5..78d50f33f80a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy @@ -128,6 +128,46 @@ def foo() { } + public void testImportedStaticField() throws Exception { + myFixture.addFileToProject("b.groovy", """ +class Foo { + static def abcfield1 + static def abcfield2 +}""") + myFixture.configureByText("a.groovy", """def foo() { + abcfi +}""") + def item = myFixture.complete(CompletionType.CLASS_NAME)[0] + ((StaticallyImportable) item).shouldBeImported = true + myFixture.type('\n') + myFixture.checkResult """import static Foo.abcfield1 + +def foo() { + abcfield1 +}""" + + } + + public void testImportedInterfaceConstant() throws Exception { + myFixture.addFileToProject("b.groovy", """ +interface Foo { + static def abcfield1 = 2 + static def abcfield2 = 3 +}""") + myFixture.configureByText("a.groovy", """def foo() { + abcfi +}""") + def item = myFixture.complete(CompletionType.CLASS_NAME)[0] + ((StaticallyImportable) item).shouldBeImported = true + myFixture.type('\n') + myFixture.checkResult """import static Foo.abcfield1 + +def foo() { + abcfield1 +}""" + + } + public void testQualifiedStaticMethod() throws Exception { myFixture.addFileToProject("foo/b.groovy", """package foo class Foo { diff --git a/plugins/junit/src/META-INF/plugin.xml b/plugins/junit/src/META-INF/plugin.xml index f34d19f72bc0..0d91587353f2 100644 --- a/plugins/junit/src/META-INF/plugin.xml +++ b/plugins/junit/src/META-INF/plugin.xml @@ -30,7 +30,17 @@ + + + + + + + + + + diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java index 92eda7ff8379..43fe0877619c 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java @@ -424,10 +424,9 @@ public class TestNGConfigurationEditor extends SettingsEditor