diff options
Diffstat (limited to 'java/java-impl/src/com/intellij/codeInsight')
20 files changed, 260 insertions, 114 deletions
diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java index d5d927cf44fc..182f79c94bce 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java @@ -48,43 +48,55 @@ public class ExternalAnnotationsLineMarkerProvider implements LineMarkerProvider @Nullable @Override public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) { - if (element instanceof PsiParameter) return null; + if (!(element instanceof PsiModifierListOwner)) return null; + if (element instanceof PsiParameter || element instanceof PsiLocalVariable) return null; - PsiModifierListOwner owner = null; - if (element instanceof PsiModifierListOwner) { - final PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)element; - final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(modifierListOwner.getProject()); - PsiAnnotation[] externalAnnotations = annotationsManager.findExternalAnnotations(modifierListOwner); - if (externalAnnotations != null && externalAnnotations.length > 0) { - owner = (PsiModifierListOwner)element; - } else if (element instanceof PsiMethod) { - final PsiParameter[] parameters = ((PsiMethod)element).getParameterList().getParameters(); - for (PsiParameter parameter : parameters) { - externalAnnotations = annotationsManager.findExternalAnnotations(parameter); - if (externalAnnotations != null && externalAnnotations.length > 0) { - owner = (PsiMethod)element; - break; - } - } - } - } - - if (owner == null) { + if (!shouldShowSignature(preferCompiledElement((PsiModifierListOwner)element))) { return null; } final Function<PsiModifierListOwner, String> annotationsCollector = new Function<PsiModifierListOwner, String>() { @Override public String fun(PsiModifierListOwner owner) { - return XmlStringUtil.wrapInHtml(JavaDocInfoGenerator.generateSignature(owner)); + return XmlStringUtil.wrapInHtml(JavaDocInfoGenerator.generateSignature(preferCompiledElement(owner))); } }; - return new LineMarkerInfo<PsiModifierListOwner>(owner, owner.getTextOffset(), AllIcons.Gutter.ExtAnnotation, + return new LineMarkerInfo<PsiModifierListOwner>((PsiModifierListOwner)element, element.getTextOffset(), AllIcons.Gutter.ExtAnnotation, Pass.UPDATE_ALL, annotationsCollector, new MyIconGutterHandler(), GutterIconRenderer.Alignment.LEFT); } + private static PsiModifierListOwner preferCompiledElement(PsiModifierListOwner element) { + PsiElement original = element.getOriginalElement(); + return original instanceof PsiModifierListOwner ? (PsiModifierListOwner)original : element; + } + + private static boolean shouldShowSignature(PsiModifierListOwner owner) { + if (hasNonCodeAnnotations(owner)) { + return true; + } + + if (owner instanceof PsiMethod) { + for (PsiParameter parameter : ((PsiMethod)owner).getParameterList().getParameters()) { + if (hasNonCodeAnnotations(parameter)) { + return true; + } + } + } + + return false; + } + + private static boolean hasNonCodeAnnotations(@NotNull PsiModifierListOwner element) { + Project project = element.getProject(); + PsiAnnotation[] externalAnnotations = ExternalAnnotationsManager.getInstance(project).findExternalAnnotations(element); + if (externalAnnotations != null && externalAnnotations.length > 0) { + return true; + } + return InferredAnnotationsManager.getInstance(project).findInferredAnnotations(element).length > 0; + } + @Override public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java index 4ff8ca2ec5f8..cbc9653b6adf 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java @@ -21,6 +21,7 @@ import com.intellij.diagnostic.AttachmentFactory; import com.intellij.openapi.diagnostic.Logger; 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.codeStyle.CodeStyleManager; @@ -38,6 +39,7 @@ import java.util.Set; * @author peter */ 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; @@ -109,9 +111,12 @@ public class JavaChainLookupElement extends LookupElementDecorator<LookupElement public void handleInsert(InsertionContext context) { final Document document = context.getEditor().getDocument(); document.replaceString(context.getStartOffset(), context.getTailOffset(), ";"); + myQualifier.putUserData(CHAIN_QUALIFIER, true); final InsertionContext qualifierContext = CompletionUtil.emulateInsertion(context, context.getStartOffset(), myQualifier); OffsetKey oldStart = context.trackOffset(context.getStartOffset(), false); + PsiDocumentManager.getInstance(context.getProject()).doPostponedOperationsAndUnblockDocument(document); + int start = CharArrayUtil.shiftForward(context.getDocument().getCharsSequence(), context.getStartOffset(), " \t\n"); if (shouldParenthesizeQualifier(context.getFile(), start, qualifierContext.getTailOffset())) { final String space = CodeStyleSettingsManager.getSettings(qualifierContext.getProject()).SPACE_WITHIN_PARENTHESES ? " " : ""; @@ -165,6 +170,7 @@ public class JavaChainLookupElement extends LookupElementDecorator<LookupElement if (expr instanceof PsiJavaCodeReferenceElement || expr instanceof PsiMethodCallExpression || + expr instanceof PsiNewExpression || expr instanceof PsiArrayAccessExpression) { return false; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java index be6d8146ce3d..f5a8253ab5ab 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java @@ -98,7 +98,8 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE context.setTailOffset(context.getOffset(refEnd)); context.commitDocument(); - if (shouldInsertParentheses(file.findElementAt(context.getTailOffset() - 1))) { + if (item.getUserData(JavaChainLookupElement.CHAIN_QUALIFIER) == null && + shouldInsertParentheses(file.findElementAt(context.getTailOffset() - 1))) { if (ConstructorInsertHandler.insertParentheses(context, item, psiClass, false)) { fillTypeArgs |= psiClass.hasTypeParameters() && PsiUtil.getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_1_5); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 7310227a80f0..fba10a633432 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -426,7 +426,7 @@ public class JavaCompletionContributor extends CompletionContributor { if (JavaCompletionData.isAfterPrimitiveOrArrayType(position)) { return false; } - + return true; } @@ -466,11 +466,11 @@ public class JavaCompletionContributor extends CompletionContributor { methods: for (PsiMethod method : annoClass.getMethods()) { if (!(method instanceof PsiAnnotationMethod)) continue; - + final String attrName = method.getName(); for (PsiNameValuePair existingAttr : existingPairs) { if (PsiTreeUtil.isAncestor(existingAttr, insertedElement, false)) break; - if (Comparing.equal(existingAttr.getName(), attrName) || + if (Comparing.equal(existingAttr.getName(), attrName) || PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(attrName) && existingAttr.getName() == null) continue methods; } LookupElementBuilder element = LookupElementBuilder.createWithIcon(method).withInsertHandler(new InsertHandler<LookupElement>() { @@ -479,7 +479,7 @@ public class JavaCompletionContributor extends CompletionContributor { final Editor editor = context.getEditor(); TailType.EQ.processTail(editor, editor.getCaretModel().getOffset()); context.setAddCompletionChar(false); - + context.commitDocument(); PsiAnnotationParameterList paramList = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiAnnotationParameterList.class, false); @@ -644,7 +644,20 @@ public class JavaCompletionContributor extends CompletionContributor { if (file instanceof PsiJavaFile) { if (context.getInvocationCount() > 0) { autoImport(file, context.getStartOffset() - 1, context.getEditor()); - PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getEditor().getDocument()); + + PsiElement leaf = file.findElementAt(context.getStartOffset() - 1); + if (leaf != null) leaf = PsiTreeUtil.prevVisibleLeaf(leaf); + + PsiVariable variable = PsiTreeUtil.getParentOfType(leaf, PsiVariable.class); + if (variable != null) { + PsiTypeElement typeElement = variable.getTypeElement(); + if (typeElement != null) { + PsiType type = typeElement.getType(); + if (type instanceof PsiClassType && ((PsiClassType)type).resolve() == null) { + autoImportReference(file, context.getEditor(), typeElement.getInnermostComponentReferenceElement()); + } + } + } } JavaCompletionUtil.initOffsets(file, context.getOffsetMap()); @@ -702,7 +715,13 @@ public class JavaCompletionContributor extends CompletionContributor { iterator.advance(); } - if (!iterator.atEnd() && (iterator.getTokenType() == JavaTokenType.LPARENTH || iterator.getTokenType() == JavaTokenType.COLON)) { + if (!iterator.atEnd() && (iterator.getTokenType() == JavaTokenType.LPARENTH)) { + return true; + } + + if (!iterator.atEnd() + && (iterator.getTokenType() == JavaTokenType.COLON) + && null == PsiTreeUtil.findElementOfClassAtOffset(file, startOffset, PsiConditionalExpression.class, false)) { return true; } @@ -721,7 +740,7 @@ public class JavaCompletionContributor extends CompletionContributor { return iterator.getTokenType() == JavaTokenType.EQ || iterator.getTokenType() == JavaTokenType.LPARENTH; } - private static void autoImport(final PsiFile file, int offset, final Editor editor) { + private static void autoImport(@NotNull final PsiFile file, int offset, @NotNull final Editor editor) { final CharSequence text = editor.getDocument().getCharsSequence(); while (offset > 0 && Character.isJavaIdentifierPart(text.charAt(offset))) offset--; if (offset <= 0) return; @@ -734,7 +753,10 @@ public class JavaCompletionContributor extends CompletionContributor { while (offset > 0 && Character.isWhitespace(text.charAt(offset))) offset--; if (offset <= 0) return; - PsiJavaCodeReferenceElement element = extractReference(PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiExpression.class, false)); + autoImportReference(file, editor, extractReference(PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiExpression.class, false))); + } + + private static void autoImportReference(@NotNull PsiFile file, @NotNull Editor editor, @Nullable PsiJavaCodeReferenceElement element) { if (element == null) return; while (true) { @@ -745,6 +767,7 @@ public class JavaCompletionContributor extends CompletionContributor { } if (!(element.getParent() instanceof PsiMethodCallExpression) && element.multiResolve(true).length == 0) { new ImportClassFix(element).doFix(editor, false, false); + PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodMergingContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodMergingContributor.java index b409014c1fe8..661d0abfcaac 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodMergingContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodMergingContributor.java @@ -18,11 +18,14 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupItem; import com.intellij.psi.PsiMethod; -import com.intellij.psi.ResolveResult; +import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import static com.intellij.util.ObjectUtils.assertNotNull; + /** * @author peter */ @@ -38,13 +41,9 @@ public class JavaMethodMergingContributor extends CompletionContributor { final LookupElement[] items = context.getItems(); if (items.length > 1) { String commonName = null; - LookupElement best = null; final ArrayList<PsiMethod> allMethods = new ArrayList<PsiMethod>(); for (LookupElement item : items) { - Object o = item.getObject(); - if (o instanceof ResolveResult) { - o = ((ResolveResult)o).getElement(); - } + Object o = item.getPsiElement(); if (item.getUserData(LookupItem.FORCE_SHOW_SIGNATURE_ATTR) != null || !(o instanceof PsiMethod)) { return AutoCompletionDecision.SHOW_LOOKUP; } @@ -56,19 +55,37 @@ public class JavaMethodMergingContributor extends CompletionContributor { return AutoCompletionDecision.SHOW_LOOKUP; } - if (best == null && method.getParameterList().getParametersCount() > 0) { - best = item; - } commonName = name; allMethods.add(method); item.putUserData(JavaCompletionUtil.ALL_METHODS_ATTRIBUTE, allMethods); } - if (best == null) { - best = items[0]; - } - return AutoCompletionDecision.insertItem(best); + + return AutoCompletionDecision.insertItem(findBestOverload(items)); } return super.handleAutoCompletionPossibility(context); } + + public static LookupElement findBestOverload(LookupElement[] items) { + LookupElement best = items[0]; + for (int i = 1; i < items.length; i++) { + LookupElement item = items[i]; + if (getPriority(best) < getPriority(item)) { + best = item; + } + } + return best; + } + + private static int getPriority(LookupElement element) { + PsiMethod method = assertNotNull(getItemMethod(element)); + return (method.getReturnType() == PsiType.VOID ? 0 : 1) + + (method.getParameterList().getParametersCount() > 0 ? 2 : 0); + } + + @Nullable + private static PsiMethod getItemMethod(LookupElement item) { + Object o = item.getPsiElement(); + return o instanceof PsiMethod ? (PsiMethod)o : null; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index f36f567199a0..ceebdecdf8c3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.completion.impl.BetterPrefixMatcher; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -41,7 +42,6 @@ import static com.intellij.patterns.PsiJavaPatterns.psiElement; * @author peter */ public class JavaNoVariantsDelegator extends CompletionContributor { - @Override public void fillCompletionVariants(@NotNull final CompletionParameters parameters, @NotNull CompletionResultSet result) { LinkedHashSet<CompletionResult> plainResults = result.runRemainingContributors(parameters, true); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateAbstractMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateAbstractMethodFromUsageFix.java index abcff2238c68..5edd1973cfd8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateAbstractMethodFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateAbstractMethodFromUsageFix.java @@ -51,7 +51,7 @@ public class CreateAbstractMethodFromUsageFix extends CreateMethodFromUsageFix { } @Override - protected boolean shouldBeAbstract(PsiClass targetClass) { + protected boolean shouldBeAbstract(PsiReferenceExpression expression, PsiClass targetClass) { return true; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFieldFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFieldFromUsageFix.java index 939b8b6f8a13..1e9d1a88cb99 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFieldFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFieldFromUsageFix.java @@ -28,6 +28,9 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + /** * @author Mike */ @@ -45,6 +48,19 @@ public class CreateFieldFromUsageFix extends CreateVarFromUsageFix { return false; } + @NotNull + @Override + protected List<PsiClass> getTargetClasses(PsiElement element) { + final List<PsiClass> targetClasses = new ArrayList<PsiClass>(); + for (PsiClass psiClass : super.getTargetClasses(element)) { + if (psiClass.getManager().isInProject(psiClass) && + (!psiClass.isInterface() && !psiClass.isAnnotationType() || shouldCreateStaticMember(myReferenceExpression, psiClass))) { + targetClasses.add(psiClass); + } + } + return targetClasses; + } + @Override protected boolean canBeTargetClass(PsiClass psiClass) { return psiClass.getManager().isInProject(psiClass) && !psiClass.isInterface() && !psiClass.isAnnotationType(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java index c12fbe8d7711..09b83e2a489f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java @@ -168,6 +168,9 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { list.deleteChildRange(list.getFirstChild(), list.getLastChild()); return; } + if (targetClass.isInterface()) { + return; + } final String visibility = getVisibility(parentClass, targetClass); if (VisibilityUtil.ESCALATE_VISIBILITY.equals(visibility)) { list.setModifierProperty(PsiModifier.PRIVATE, true); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java index b7cd8af73084..8e93a6a0c817 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java @@ -120,7 +120,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { PsiMethodCallExpression call = getMethodCall(); if (call == null) return Collections.emptyList(); for (PsiClass target : targets) { - if (target.isInterface() && shouldCreateStaticMember(call.getMethodExpression(), target)) continue; + if (target.isInterface() && shouldCreateStaticMember(call.getMethodExpression(), target) && !PsiUtil.isLanguageLevel8OrHigher(target)) continue; if (!isMethodSignatureExists(call, target)) { result.add(target); } @@ -155,7 +155,8 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { PsiCodeBlock body = method.getBody(); assert body != null; - if (shouldBeAbstract(targetClass)) { + final boolean shouldBeAbstract = shouldBeAbstract(expression.getMethodExpression(), targetClass); + if (shouldBeAbstract) { body.delete(); if (!targetClass.isInterface()) { method.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, true); @@ -167,14 +168,14 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { expression = getMethodCall(); LOG.assertTrue(expression.isValid()); - if (!targetClass.isInterface() && shouldCreateStaticMember(expression.getMethodExpression(), targetClass) && !shouldBeAbstract(targetClass)) { + if ((!targetClass.isInterface() || PsiUtil.isLanguageLevel8OrHigher(targetClass)) && shouldCreateStaticMember(expression.getMethodExpression(), targetClass) && !shouldBeAbstract) { PsiUtil.setModifierProperty(method, PsiModifier.STATIC, true); } final PsiElement context = PsiTreeUtil.getParentOfType(expression, PsiClass.class, PsiMethod.class); PsiExpression[] arguments = expression.getArgumentList().getExpressions(); - doCreate(targetClass, method, shouldBeAbstract(targetClass), + doCreate(targetClass, method, shouldBeAbstract, ContainerUtil.map2List(arguments, Pair.<PsiExpression, PsiType>createFunction(null)), getTargetSubstitutor(expression), CreateFromUsageUtils.guessExpectedTypes(expression, true), @@ -213,7 +214,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { public static void doCreate(PsiClass targetClass, PsiMethod method, List<Pair<PsiExpression, PsiType>> arguments, PsiSubstitutor substitutor, ExpectedTypeInfo[] expectedTypes, @Nullable PsiElement context) { - doCreate(targetClass, method, shouldBeAbstractImpl(targetClass), arguments, substitutor, expectedTypes, context); + doCreate(targetClass, method, shouldBeAbstractImpl(null, targetClass), arguments, substitutor, expectedTypes, context); } public static void doCreate(PsiClass targetClass, @@ -340,12 +341,12 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { return false; } - protected boolean shouldBeAbstract(PsiClass targetClass) { - return shouldBeAbstractImpl(targetClass); + protected boolean shouldBeAbstract(PsiReferenceExpression expression, PsiClass targetClass) { + return shouldBeAbstractImpl(expression, targetClass); } - private static boolean shouldBeAbstractImpl(PsiClass targetClass) { - return targetClass.isInterface(); + private static boolean shouldBeAbstractImpl(PsiReferenceExpression expression, PsiClass targetClass) { + return targetClass.isInterface() && (expression == null || !shouldCreateStaticMember(expression, targetClass)); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java index b5de7b73e318..fec3efd161ba 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java @@ -30,6 +30,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.ClassUtil; import org.jetbrains.annotations.NotNull; +import java.util.Collections; import java.util.List; public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceElement, PsiJavaCodeReferenceElement> { @@ -107,9 +108,22 @@ public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceEleme return super.getRequiredMemberName(reference); } + @Override + protected boolean canReferenceClass(PsiJavaCodeReferenceElement ref) { + if (ref instanceof PsiReferenceExpression) { + PsiElement parent = ref.getParent(); + return parent instanceof PsiReferenceExpression || parent instanceof PsiExpressionStatement; + } + return true; + } + @NotNull @Override protected List<PsiClass> filterByContext(@NotNull List<PsiClass> candidates, @NotNull PsiJavaCodeReferenceElement ref) { + if (ref instanceof PsiReferenceExpression) { + return Collections.emptyList(); + } + PsiElement typeElement = ref.getParent(); if (typeElement instanceof PsiTypeElement) { PsiElement var = typeElement.getParent(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java index 8047486d93ba..2fbe85bc7b25 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java @@ -102,14 +102,19 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe // can happen when e.g. class name happened to be in a method position if (element instanceof PsiClass && result.isValidResult()) return Collections.emptyList(); } - PsiShortNamesCache cache = PsiShortNamesCache.getInstance(myElement.getProject()); + String name = getReferenceName(myRef); GlobalSearchScope scope = myElement.getResolveScope(); if (name == null) { return Collections.emptyList(); } + + if (!canReferenceClass(myRef)) { + return Collections.emptyList(); + } + boolean referenceHasTypeParameters = hasTypeParameters(myRef); - PsiClass[] classes = cache.getClassesByName(name, scope); + PsiClass[] classes = PsiShortNamesCache.getInstance(myElement.getProject()).getClassesByName(name, scope); if (classes.length == 0) return Collections.emptyList(); List<PsiClass> classList = new ArrayList<PsiClass>(classes.length); boolean isAnnotationReference = myElement.getParent() instanceof PsiAnnotation; @@ -140,6 +145,10 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe return classList; } + protected boolean canReferenceClass(R ref) { + return true; + } + private List<PsiClass> filterByRequiredMemberName(List<PsiClass> classList) { final String memberName = getRequiredMemberName(myElement); if (memberName != null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavaSmartEnterProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavaSmartEnterProcessor.java index cea07113fe24..90c26bc6073b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavaSmartEnterProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavaSmartEnterProcessor.java @@ -47,7 +47,21 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.editorActions.smartEnter.JavaSmartEnterProcessor"); private static final Fixer[] ourFixers; - private static final EnterProcessor[] ourEnterProcessors; + private static final EnterProcessor[] ourEnterProcessors = { + new CommentBreakerEnterProcessor(), + new AfterSemicolonEnterProcessor(), + new LeaveCodeBlockEnterProcessor(), + new PlainEnterProcessor() + }; + private static final EnterProcessor[] ourAfterCompletionEnterProcessors = { + new AfterSemicolonEnterProcessor(), + new EnterProcessor() { + @Override + public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) { + return PlainEnterProcessor.expandCodeBlock(editor, psiElement); + } + } + }; static { final List<Fixer> fixers = new ArrayList<Fixer>(); @@ -78,15 +92,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { fixers.add(new MissingArrayInitializerBraceFixer()); fixers.add(new MissingArrayConstructorBracketFixer()); fixers.add(new EnumFieldFixer()); - //ourFixers.add(new CompletionFixer()); ourFixers = fixers.toArray(new Fixer[fixers.size()]); - - List<EnterProcessor> processors = new ArrayList<EnterProcessor>(); - processors.add(new CommentBreakerEnterProcessor()); - processors.add(new AfterSemicolonEnterProcessor()); - processors.add(new LeaveCodeBlockEnterProcessor()); - processors.add(new PlainEnterProcessor()); - ourEnterProcessors = processors.toArray(new EnterProcessor[processors.size()]); } private int myFirstErrorOffset = Integer.MAX_VALUE; @@ -102,13 +108,22 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { public boolean process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile) { FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.complete.statement"); + return invokeProcessor(editor, psiFile, false); + } + + @Override + public boolean processAfterCompletion(@NotNull Editor editor, @NotNull PsiFile psiFile) { + return invokeProcessor(editor, psiFile, true); + } + + private boolean invokeProcessor(Editor editor, PsiFile psiFile, boolean afterCompletion) { final Document document = editor.getDocument(); - final String textForRollback = document.getText(); + final CharSequence textForRollback = document.getImmutableCharSequence(); try { editor.putUserData(SMART_ENTER_TIMESTAMP, editor.getDocument().getModificationStamp()); myFirstErrorOffset = Integer.MAX_VALUE; mySkipEnter = false; - process(project, editor, psiFile, 0); + process(editor, psiFile, 0, afterCompletion); } catch (TooManyAttemptsException e) { document.replaceString(0, document.getTextLength(), textForRollback); @@ -118,8 +133,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { return true; } - - private void process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file, final int attempt) throws TooManyAttemptsException { + private void process(@NotNull final Editor editor, @NotNull final PsiFile file, final int attempt, boolean afterCompletion) throws TooManyAttemptsException { if (attempt > MAX_ATTEMPTS) throw new TooManyAttemptsException(); try { @@ -148,18 +162,18 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { for (PsiElement psiElement : queue) { for (Fixer fixer : ourFixers) { fixer.apply(editor, this, psiElement); - if (LookupManager.getInstance(project).getActiveLookup() != null) { + if (LookupManager.getInstance(file.getProject()).getActiveLookup() != null) { return; } - if (isUncommited(project) || !psiElement.isValid()) { + if (isUncommited(file.getProject()) || !psiElement.isValid()) { moveCaretInsideBracesIfAny(editor, file); - process(project, editor, file, attempt + 1); + process(editor, file, attempt + 1, afterCompletion); return; } } } - doEnter(atCaret, editor); + doEnter(atCaret, editor, afterCompletion); } catch (IncorrectOperationException e) { LOG.error(e); @@ -187,7 +201,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { } - private void doEnter(PsiElement atCaret, Editor editor) throws IncorrectOperationException { + private void doEnter(PsiElement atCaret, Editor editor, boolean afterCompletion) throws IncorrectOperationException { final PsiFile psiFile = atCaret.getContainingFile(); final RangeMarker rangeMarker = createRangeMarker(atCaret); @@ -205,7 +219,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { } atCaret = CodeInsightUtil.findElementInRange(psiFile, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(), atCaret.getClass()); - for (EnterProcessor processor : ourEnterProcessors) { + for (EnterProcessor processor : afterCompletion ? ourAfterCompletionEnterProcessors : ourEnterProcessors) { if(atCaret == null){ // Can't restore element at caret after enter processor execution! break; @@ -214,7 +228,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { if (processor.doEnter(editor, atCaret, isModified(editor))) return; } - if (!isModified(editor)) { + if (!isModified(editor) && !afterCompletion) { plainEnter(editor); } else { if (myFirstErrorOffset == Integer.MAX_VALUE) { diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/PlainEnterProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/PlainEnterProcessor.java index 0fe58925d884..6bafcc00d983 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/PlainEnterProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/PlainEnterProcessor.java @@ -42,29 +42,37 @@ import org.jetbrains.annotations.Nullable; public class PlainEnterProcessor implements EnterProcessor { @Override public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) { + if (expandCodeBlock(editor, psiElement)) return true; + + getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE).execute(editor, ((EditorEx)editor).getDataContext()); + return true; + } + + static boolean expandCodeBlock(Editor editor, PsiElement psiElement) { PsiCodeBlock block = getControlStatementBlock(editor.getCaretModel().getOffset(), psiElement); if (processExistingBlankLine(editor, block, psiElement)) { return true; } - EditorActionHandler enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE); - if (block != null) { - PsiElement firstElement = block.getFirstBodyElement(); - if (firstElement == null) { - firstElement = block.getRBrace(); - // Plain enter processor inserts enter after the end of line, hence, we don't want to use it here because the line ends with - // the empty braces block. So, we get the following in case of default handler usage: - // Before: - // if (condition[caret]) {} - // After: - // if (condition) {} - // [caret] - enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_ENTER); - } - editor.getCaretModel().moveToOffset(firstElement != null ? - firstElement.getTextRange().getStartOffset() : - block.getTextRange().getEndOffset()); + if (block == null) { + return false; } + EditorActionHandler enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE); + PsiElement firstElement = block.getFirstBodyElement(); + if (firstElement == null) { + firstElement = block.getRBrace(); + // Plain enter processor inserts enter after the end of line, hence, we don't want to use it here because the line ends with + // the empty braces block. So, we get the following in case of default handler usage: + // Before: + // if (condition[caret]) {} + // After: + // if (condition) {} + // [caret] + enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_ENTER); + } + editor.getCaretModel().moveToOffset(firstElement != null ? + firstElement.getTextRange().getStartOffset() : + block.getTextRange().getEndOffset()); enterHandler.execute(editor, ((EditorEx)editor).getDataContext()); return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java index 8646805b3a2f..5d948f326930 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.folding.impl; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; @@ -27,7 +28,7 @@ public class JavaFoldingBuilder extends JavaFoldingBuilderBase { @Override protected boolean isBelowRightMargin(Project project, int lineLength) { final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project); - return lineLength <= settings.RIGHT_MARGIN; + return lineLength <= settings.getRightMargin(JavaLanguage.INSTANCE); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java index 4236da3187fc..fe4208deada7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java @@ -251,11 +251,22 @@ public class GenerateDelegateHandler implements LanguageCodeInsightActionHandler final Set<MethodSignature> existingSignatures = new HashSet<MethodSignature>(aClass.getVisibleSignatures()); final Set<PsiMethodMember> selection = new HashSet<PsiMethodMember>(); Map<PsiClass, PsiSubstitutor> superSubstitutors = new HashMap<PsiClass, PsiSubstitutor>(); + + final PsiClass containingClass = targetMember.getContainingClass(); JavaPsiFacade facade = JavaPsiFacade.getInstance(target.getProject()); for (PsiMethod method : allMethods) { final PsiClass superClass = method.getContainingClass(); if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) continue; if (method.isConstructor()) continue; + + //do not suggest to override final method + if (method.hasModifierProperty(PsiModifier.FINAL)) { + PsiMethod overridden = containingClass.findMethodBySignature(method, true); + if (overridden != null && overridden.getContainingClass() != containingClass) { + continue; + } + } + PsiSubstitutor superSubstitutor = superSubstitutors.get(superClass); if (superSubstitutor == null) { superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, targetClass, substitutor); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java index d8df67367790..49e2e43f2ce4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java @@ -15,10 +15,7 @@ */ package com.intellij.codeInsight.generation; -import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInsight.CodeInsightActionHandler; -import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.MethodImplementor; +import com.intellij.codeInsight.*; import com.intellij.codeInsight.intention.AddAnnotationFix; import com.intellij.codeInsight.intention.AddAnnotationPsiFix; import com.intellij.featureStatistics.FeatureUsageTracker; @@ -259,6 +256,11 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { for (String annotation : each.getAnnotations(project)) { if (moduleScope != null && facade.findClass(annotation, moduleScope) == null) continue; if (AnnotationUtil.isAnnotated(overridden, annotation, false, false) && !AnnotationUtil.isAnnotated(method, annotation, false, false)) { + PsiAnnotation psiAnnotation = AnnotationUtil.findAnnotation(overridden, annotation); + if (psiAnnotation != null && AnnotationUtil.isInferredAnnotation(psiAnnotation)) { + continue; + } + AddAnnotationPsiFix.removePhysicalAnnotations(method, each.annotationsToRemove(project, annotation)); AddAnnotationPsiFix.addPhysicalAnnotation(annotation, PsiNameValuePair.EMPTY_ARRAY, method.getModifierList()); } diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java index b33287321535..fd85d1124171 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java @@ -23,6 +23,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.parameterInfo.*; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbService; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.CompletionParameterTypeInferencePolicy; import com.intellij.psi.infos.CandidateInfo; @@ -31,6 +32,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -443,13 +445,18 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc private static void appendModifierList(@NotNull StringBuilder buffer, @NotNull PsiModifierListOwner owner) { int lastSize = buffer.length(); - for (PsiAnnotation annotation : AnnotationUtil.getAllAnnotations(owner, false, null)) { + Set<String> shownAnnotations = ContainerUtil.newHashSet(); + for (PsiAnnotation annotation : AnnotationUtil.getAllAnnotations(owner, false, null, !DumbService.isDumb(owner.getProject()))) { final PsiJavaCodeReferenceElement element = annotation.getNameReferenceElement(); if (element != null) { final PsiElement resolved = element.resolve(); if (resolved instanceof PsiClass && !AnnotationUtil.isAnnotated((PsiClass)resolved, "java.lang.annotation.Documented", false)) continue; + + String referenceName = element.getReferenceName(); + if (!shownAnnotations.add(referenceName)) continue; + if (lastSize != buffer.length()) buffer.append(" "); - buffer.append("@").append(element.getReferenceName()); + buffer.append("@").append(referenceName); } } if (lastSize != buffer.length()) buffer.append(" "); diff --git a/java/java-impl/src/com/intellij/codeInsight/template/impl/ShortenToStaticImportProcessor.java b/java/java-impl/src/com/intellij/codeInsight/template/impl/ShortenToStaticImportProcessor.java index 41424cf2b526..fbb6786c4972 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/impl/ShortenToStaticImportProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/impl/ShortenToStaticImportProcessor.java @@ -27,11 +27,11 @@ import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -63,7 +63,7 @@ public class ShortenToStaticImportProcessor implements TemplateOptionalProcessor for ( PsiElement element = PsiUtilCore.getElementAtOffset(file, templateRange.getStartOffset()); element != null && element.getTextRange().getStartOffset() < templateRange.getEndOffset(); - element = getNext(element)) + element = PsiTreeUtil.nextLeaf(element)) { for (StaticImporter importer : IMPORTERS) { if (importer.canPerform(element)) { @@ -81,15 +81,6 @@ public class ShortenToStaticImportProcessor implements TemplateOptionalProcessor } } - @Nullable - private static PsiElement getNext(@NotNull PsiElement element) { - PsiElement result = element.getNextSibling(); - for (PsiElement current = element; current != null && result == null; current = current.getParent()) { - result = current.getNextSibling(); - } - return result; - } - @Nls @Override public String getOptionName() { diff --git a/java/java-impl/src/com/intellij/codeInsight/unwrap/JavaMethodParameterUnwrapper.java b/java/java-impl/src/com/intellij/codeInsight/unwrap/JavaMethodParameterUnwrapper.java index ec771e43c073..1c1957bcf472 100644 --- a/java/java-impl/src/com/intellij/codeInsight/unwrap/JavaMethodParameterUnwrapper.java +++ b/java/java-impl/src/com/intellij/codeInsight/unwrap/JavaMethodParameterUnwrapper.java @@ -29,15 +29,23 @@ public class JavaMethodParameterUnwrapper extends JavaUnwrapper { super(""); } + private static PsiElement adjustElementToTheLeft(PsiElement element) { + if (element instanceof PsiJavaToken && ((PsiJavaToken)element).getTokenType() == JavaTokenType.RPARENTH) { + return element.getPrevSibling(); + } + return element; + } + @Override public String getDescription(PsiElement e) { - String text = e.getText(); + String text = adjustElementToTheLeft(e).getText(); if (text.length() > 20) text = text.substring(0, 17) + "..."; return CodeInsightBundle.message("unwrap.with.placeholder", text); } @Override public boolean isApplicableTo(PsiElement e) { + e = adjustElementToTheLeft(e); final PsiElement parent = e.getParent(); if (e instanceof PsiExpression){ if (parent instanceof PsiExpressionList) { @@ -62,6 +70,7 @@ public class JavaMethodParameterUnwrapper extends JavaUnwrapper { @Override public PsiElement collectAffectedElements(PsiElement e, List<PsiElement> toExtract) { + e = adjustElementToTheLeft(e); super.collectAffectedElements(e, toExtract); return isTopLevelCall(e) ? e.getParent() : e.getParent().getParent(); } @@ -73,6 +82,7 @@ public class JavaMethodParameterUnwrapper extends JavaUnwrapper { @Override protected void doUnwrap(PsiElement element, Context context) throws IncorrectOperationException { + element = adjustElementToTheLeft(element); PsiElement methodCall = isTopLevelCall(element) ? element.getParent() : element.getParent().getParent(); final PsiElement extractedElement = isTopLevelCall(element) ? getArg(element) : element; context.extractElement(extractedElement, methodCall); |