diff options
author | Tor Norbye <tnorbye@google.com> | 2013-07-08 11:26:24 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-07-08 11:26:24 -0700 |
commit | c1ace1f7e1e49c81bb4b75377c99f07be340abfe (patch) | |
tree | 9d0db96bd3d86ddfec80e7e3554cad9dcc066553 /java/java-impl/src/com/intellij/codeInsight/daemon | |
parent | c6218e46d5d2017e987ecdbd99b318a95c42abc0 (diff) | |
download | idea-c1ace1f7e1e49c81bb4b75377c99f07be340abfe.tar.gz |
Snapshot aea001abfc1b38fec3a821bcd5174cc77dc75787 from master branch of git://git.jetbrains.org/idea/community.git
Change-Id: Icdea2a2bd7ad43b4d05967b1f0479db3bda1c93c
Diffstat (limited to 'java/java-impl/src/com/intellij/codeInsight/daemon')
16 files changed, 154 insertions, 118 deletions
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/JavaAwareInspectionProfileCoverter.java b/java/java-impl/src/com/intellij/codeInsight/daemon/JavaAwareInspectionProfileCoverter.java index e79fdbe14ed9..5caad6166995 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/JavaAwareInspectionProfileCoverter.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/JavaAwareInspectionProfileCoverter.java @@ -20,9 +20,8 @@ */ package com.intellij.codeInsight.daemon; -import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.ModifiableModel; -import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; +import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection; import com.intellij.profile.codeInspection.InspectionProfileManager; import org.jdom.Element; @@ -53,8 +52,8 @@ public class JavaAwareInspectionProfileCoverter extends InspectionProfileConvert super.fillErrorLevels(profile); //javadoc attributes - final InspectionProfileEntry inspectionTool = profile.getInspectionTool(JavaDocLocalInspection.SHORT_NAME, null); - JavaDocLocalInspection inspection = (JavaDocLocalInspection)((LocalInspectionToolWrapper)inspectionTool).getTool(); + final InspectionToolWrapper toolWrapper = profile.getInspectionTool(JavaDocLocalInspection.SHORT_NAME, null); + JavaDocLocalInspection inspection = (JavaDocLocalInspection)toolWrapper.getTool(); inspection.myAdditionalJavadocTags = myAdditionalJavadocTags; } }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java index a36521fbe936..43a7037397ff 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java @@ -139,7 +139,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { VirtualFile virtualFile = viewProvider.getVirtualFile(); myInLibrary = fileIndex.isInLibraryClasses(virtualFile) || fileIndex.isInLibrarySource(virtualFile); - myRefCountHolder = RefCountHolder.endUsing(myFile); + myRefCountHolder = RefCountHolder.endUsing(myFile, progress); if (myRefCountHolder == null || !myRefCountHolder.retrieveUnusedReferencesInfo(progress, new Runnable() { @Override public void run() { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java index 0fd26857ab86..892eec196986 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java @@ -63,7 +63,7 @@ public class RecursiveCallLineMarkerProvider implements LineMarkerProvider { public static boolean isRecursiveMethodCall(@NotNull PsiMethodCallExpression methodCall) { final PsiMethod method = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class); - if (method == null) { + if (method == null || !method.getName().equals(methodCall.getMethodExpression().getReferenceName())) { return false; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java index 6fd6ba54a888..175c1332db46 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java @@ -18,7 +18,6 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.UserDataHolderEx; import com.intellij.psi.*; @@ -34,11 +33,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.ref.SoftReference; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; public class RefCountHolder { @@ -55,34 +50,35 @@ public class RefCountHolder { private volatile ProgressIndicator analyzedUnder; private static class HolderReference extends SoftReference<RefCountHolder> { - @SuppressWarnings("UnusedDeclaration") - private volatile RefCountHolder myHardRef; // to prevent gc - // number of live references to RefCountHolder. Once it reaches zero, hard ref is cleared - // the counter is used instead of a flag because multiple passes can be running simultaneously (one actual and several canceled winding down) - // and there is a chance they overlap the usage of RCH - private final AtomicInteger myRefCount = new AtomicInteger(); + // Map holding hard references to RefCountHolder for each highlighting pass (identified by its progress indicator) + // there can be multiple passes running simultaneously (one actual and several passes just canceled and winding down but still alive) + // so there is a chance they overlap the usage of RCH + // As soon as everybody finished using RCH, map become empty and the RefCountHolder is eligible for gc + private final Map<ProgressIndicator, RefCountHolder> map = new ConcurrentHashMap<ProgressIndicator, RefCountHolder>(); public HolderReference(@NotNull RefCountHolder holder) { super(holder); - myHardRef = holder; } - private void changeLivenessBy(int delta) { - if (myRefCount.addAndGet(delta) == 0) { - myHardRef = null; - } - else if (myHardRef == null) { - myHardRef = get(); - } + private void acquire(@NotNull ProgressIndicator indicator) { + RefCountHolder holder = get(); + assert holder != null: "no way"; + map.put(indicator, holder); + holder = get(); + assert holder != null: "can't be!"; + } + + private RefCountHolder release(@NotNull ProgressIndicator indicator) { + return map.remove(indicator); } } private static final Key<HolderReference> REF_COUNT_HOLDER_IN_FILE_KEY = Key.create("REF_COUNT_HOLDER_IN_FILE_KEY"); - @NotNull - private static Pair<RefCountHolder, HolderReference> getInstance(@NotNull PsiFile file, boolean create) { + + private static RefCountHolder getInstance(@NotNull PsiFile file, @NotNull ProgressIndicator indicator, boolean acquire) { HolderReference ref = file.getUserData(REF_COUNT_HOLDER_IN_FILE_KEY); RefCountHolder holder = ref == null ? null : ref.get(); - if (holder == null && create) { + if (holder == null && acquire) { holder = new RefCountHolder(file); HolderReference newRef = new HolderReference(holder); while (true) { @@ -99,31 +95,30 @@ public class RefCountHolder { } } } - return Pair.create(holder, ref); + if (ref != null) { + if (acquire) { + ref.acquire(indicator); + } + else { + ref.release(indicator); + } + } + return holder; } @NotNull - public static RefCountHolder startUsing(@NotNull PsiFile file) { - Pair<RefCountHolder, HolderReference> pair = getInstance(file, true); - HolderReference reference = pair.second; - reference.changeLivenessBy(1); // make sure RefCountHolder won't be gced during highlighting - log("startUsing: " + pair.first.myState+" for "+file); - return pair.first; + public static RefCountHolder startUsing(@NotNull PsiFile file, @NotNull ProgressIndicator indicator) { + return getInstance(file, indicator, true); } @Nullable("might be gced") - public static RefCountHolder endUsing(@NotNull PsiFile file) { - Pair<RefCountHolder, HolderReference> pair = getInstance(file, false); - HolderReference reference = pair.second; - reference.changeLivenessBy(-1); // no longer needed, can be cleared - RefCountHolder holder = pair.first; - log("endUsing: " + (holder == null ? null : holder.myState)+" for "+file); - return holder; + public static RefCountHolder endUsing(@NotNull PsiFile file, @NotNull ProgressIndicator indicator) { + return getInstance(file, indicator, false); } private RefCountHolder(@NotNull PsiFile file) { myFile = file; - log("c: created: " + myState.get()+" for "+file); + log("c: created: ", myState.get(), " for ", file); } private void clear() { @@ -284,10 +279,10 @@ public class RefCountHolder { ProgressIndicator old = myState.get(); if (old != VIRGIN && old != READY) return false; if (!myState.compareAndSet(old, indicator)) { - log("a: failed to change " + old + "->" + indicator); + log("a: failed to change ", old, "->", indicator); return false; } - log("a: changed " + old + "->" + indicator); + log("a: changed ", old, "->", indicator); analyzedUnder = null; boolean completed = false; try { @@ -308,22 +303,22 @@ public class RefCountHolder { ProgressIndicator resultState = completed ? READY : VIRGIN; boolean set = myState.compareAndSet(indicator, resultState); assert set : myState.get(); - log("a: changed after analyze" + indicator + "->" + resultState); + log("a: changed after analyze", indicator, "->", resultState); } return true; } - private static void log(@NonNls String s) { - //System.err.println("RFC: "+s); + private static void log(@NonNls Object... s) { + //System.err.println("RFC: "+ Arrays.asList(s)); } public boolean retrieveUnusedReferencesInfo(@NotNull ProgressIndicator indicator, @NotNull Runnable analyze) { ProgressIndicator old = myState.get(); if (!myState.compareAndSet(READY, indicator)) { - log("r: failed to change " + old + "->" + indicator); + log("r: failed to change ", old, "->", indicator); return false; } - log("r: changed " + old + "->" + indicator); + log("r: changed ", old, "->", indicator); try { if (analyzedUnder != indicator) { return false; @@ -333,7 +328,7 @@ public class RefCountHolder { finally { boolean set = myState.compareAndSet(indicator, READY); assert set : myState.get(); - log("r: changed back " + indicator + "->" + READY); + log("r: changed back ", indicator, "->", READY); } return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 1d74a2f3dcf4..48e10ee31035 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -40,6 +40,7 @@ import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -384,8 +385,10 @@ public class GenericsHighlightUtil { } @Nullable - public static HighlightInfo checkElementInTypeParameterExtendsList(PsiReferenceList referenceList, JavaResolveResult resolveResult, PsiElement element) { - PsiClass aClass = (PsiClass)referenceList.getParent(); + public static HighlightInfo checkElementInTypeParameterExtendsList(@NotNull PsiReferenceList referenceList, + @NotNull PsiClass aClass, + @NotNull JavaResolveResult resolveResult, + @NotNull PsiElement element) { final PsiJavaCodeReferenceElement[] referenceElements = referenceList.getReferenceElements(); PsiClass extendFrom = (PsiClass)resolveResult.getElement(); if (extendFrom == null) return null; @@ -462,7 +465,7 @@ public class GenericsHighlightUtil { return null; } - public static HighlightInfo checkOverrideEquivalentMethods(final PsiClass aClass) { + public static HighlightInfo checkOverrideEquivalentMethods(@NotNull PsiClass aClass) { final Collection<HierarchicalMethodSignature> signaturesWithSupers = aClass.getVisibleSignatures(); PsiManager manager = aClass.getManager(); Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods = @@ -520,10 +523,10 @@ public class GenericsHighlightUtil { } @Nullable - private static HighlightInfo checkSameErasureNotSubSignatureInner(final HierarchicalMethodSignature signature, - final PsiManager manager, - final PsiClass aClass, - final Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods) { + private static HighlightInfo checkSameErasureNotSubSignatureInner(@NotNull HierarchicalMethodSignature signature, + @NotNull PsiManager manager, + @NotNull PsiClass aClass, + @NotNull Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods) { PsiMethod method = signature.getMethod(); JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); if (!facade.getResolveHelper().isAccessible(method, aClass, null)) return null; @@ -549,10 +552,11 @@ public class GenericsHighlightUtil { if (superSignature.isRaw() && !signature.isRaw()) { final PsiType[] parameterTypes = signature.getParameterTypes(); - PsiType[] types = superSignature.getParameterTypes(); - for (int i = 0; i < types.length; i++) { - if (!Comparing.equal(parameterTypes[i], TypeConversionUtil.erasure(types[i]))) { - return getSameErasureMessage(false, method, superSignature.getMethod(), HighlightNamesUtil.getClassDeclarationTextRange(aClass)); + PsiType[] erasedTypes = superSignature.getErasedParameterTypes(); + for (int i = 0; i < erasedTypes.length; i++) { + if (!Comparing.equal(parameterTypes[i], erasedTypes[i])) { + return getSameErasureMessage(false, method, superSignature.getMethod(), + HighlightNamesUtil.getClassDeclarationTextRange(aClass)); } } } @@ -601,10 +605,10 @@ public class GenericsHighlightUtil { !(checkEqualsSuper && Arrays.equals(superSignature.getParameterTypes(), signatureToCheck.getParameterTypes())) && !atLeast17) { int idx = 0; - final PsiType[] parameterTypes = signatureToCheck.getParameterTypes(); - boolean erasure = parameterTypes.length > 0; + final PsiType[] erasedTypes = signatureToCheck.getErasedParameterTypes(); + boolean erasure = erasedTypes.length > 0; for (PsiType type : superSignature.getParameterTypes()) { - erasure &= Comparing.equal(type, TypeConversionUtil.erasure(parameterTypes[idx])); + erasure &= Comparing.equal(type, erasedTypes[idx]); idx++; } @@ -624,9 +628,9 @@ public class GenericsHighlightUtil { } } - private static HighlightInfo getSameErasureMessage(final boolean sameClass, final PsiMethod method, final PsiMethod superMethod, + private static HighlightInfo getSameErasureMessage(final boolean sameClass, @NotNull PsiMethod method, @NotNull PsiMethod superMethod, TextRange textRange) { - @NonNls final String key = sameClass ? "generics.methods.have.same.erasure" : + @NonNls final String key = sameClass ? "generics.methods.have.same.erasure" : method.hasModifierProperty(PsiModifier.STATIC) ? "generics.methods.have.same.erasure.hide" : "generics.methods.have.same.erasure.override"; @@ -1275,7 +1279,7 @@ public class GenericsHighlightUtil { if (resolve instanceof PsiClass) { final PsiClass containingClass = ((PsiClass)resolve).getContainingClass(); if (containingClass != null) { - if (psiClass.isInheritor(containingClass, true) || + if (psiClass.isInheritor(containingClass, true) || unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(containingClass, ((PsiClass)resolve).getExtendsList()) || unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(containingClass, ((PsiClass)resolve).getImplementsList())) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(((PsiClass)resolve).getName() + " is not accessible in current context").range(ref).create(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 4f6f0996ad29..ae32b61b8e45 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -55,10 +55,7 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; +import java.util.*; public class HighlightClassUtil { private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance(); @@ -94,19 +91,32 @@ public class HighlightClassUtil { static HighlightInfo checkClassWithAbstractMethods(PsiClass aClass, PsiElement implementsFixElement, TextRange range) { PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(aClass); - if (abstractMethod == null || abstractMethod.getContainingClass() == null) { + if (abstractMethod == null) { return null; } + + final PsiClass superClass = abstractMethod.getContainingClass(); + if (superClass == null) { + return null; + } + String baseClassName = HighlightUtil.formatClass(aClass, false); String methodName = JavaHighlightUtil.formatMethod(abstractMethod); String message = JavaErrorMessages.message(aClass instanceof PsiEnumConstantInitializer || implementsFixElement instanceof PsiEnumConstant ? "enum.constant.should.implement.method" : "class.must.be.abstract", baseClassName, methodName, - HighlightUtil.formatClass(abstractMethod.getContainingClass(), false)); + HighlightUtil.formatClass(superClass, false)); HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(message).create(); - if (ClassUtil.getAnyMethodToImplement(aClass) != null) { - QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createImplementMethodsFix(implementsFixElement)); + final PsiMethod anyMethodToImplement = ClassUtil.getAnyMethodToImplement(aClass); + if (anyMethodToImplement != null) { + if (!anyMethodToImplement.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || + JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, superClass)) { + QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createImplementMethodsFix(implementsFixElement)); + } else { + QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createModifierListFix(anyMethodToImplement, PsiModifier.PROTECTED, true, true)); + QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createModifierListFix(anyMethodToImplement, PsiModifier.PUBLIC, true, true)); + } } if (!(aClass instanceof PsiAnonymousClass) && HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, aClass.getModifierList()) == null) { @@ -985,7 +995,7 @@ public class HighlightClassUtil { if (classReference == null) return; final PsiClass psiClass = (PsiClass)classReference.resolve(); if (psiClass == null) return; - final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, psiClass); + final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, psiClass, false); if (chooser == null) return; final List<PsiMethodMember> selectedElements = chooser.getSelectedElements(); @@ -999,12 +1009,17 @@ public class HighlightClassUtil { newExpression = (PsiNewExpression)startElement.replace(newExpression); final PsiClass psiClass = newExpression.getAnonymousClass(); if (psiClass == null) return; - PsiClassType baseClassType = ((PsiAnonymousClass)psiClass).getBaseClassType(); - PsiClass resolve = baseClassType.resolve(); - if (resolve == null) return; - PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(resolve, psiClass, PsiSubstitutor.EMPTY); + Map<PsiClass, PsiSubstitutor> subst = new HashMap<PsiClass, PsiSubstitutor>(); for (PsiMethodMember selectedElement : selectedElements) { - selectedElement.setSubstitutor(superClassSubstitutor); + final PsiClass baseClass = selectedElement.getElement().getContainingClass(); + if (baseClass != null) { + PsiSubstitutor substitutor = subst.get(baseClass); + if (substitutor == null) { + substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, psiClass, PsiSubstitutor.EMPTY); + subst.put(baseClass, substitutor); + } + selectedElement.setSubstitutor(substitutor); + } } OverrideImplementUtil.overrideOrImplementMethodsInRightPlace(editor, psiClass, selectedElements, chooser.isCopyJavadoc(), chooser.isInsertOverrideAnnotation()); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 80f4b1715a1c..2d1a4db5ff7d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -35,6 +35,7 @@ import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.util.*; import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.ui.ColorUtil; +import com.intellij.util.containers.MostlySingularMultiMap; import com.intellij.util.ui.UIUtil; import com.intellij.xml.util.XmlStringUtil; import org.intellij.lang.annotations.Language; @@ -833,18 +834,15 @@ public class HighlightMethodUtil { } @Nullable - static HighlightInfo checkDuplicateMethod(PsiClass aClass, PsiMethod method) { + static HighlightInfo checkDuplicateMethod(PsiClass aClass, + @NotNull PsiMethod method, + @NotNull MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods) { if (aClass == null || method instanceof ExternallyDefinedPsiElement) return null; MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY); - int methodCount = 0; - final PsiMethod[] methodsByName = aClass.findMethodsByName(method.getName(), false); - for (PsiMethod other : methodsByName) { - if (other instanceof ExternallyDefinedPsiElement) continue; - if (other == method || - other.isConstructor() == method.isConstructor() && other.getSignature(PsiSubstitutor.EMPTY).equals(methodSignature)) { - methodCount++; - if (methodCount > 1) break; - } + int methodCount = 1; + List<PsiMethod> methods = (List<PsiMethod>)duplicateMethods.get(methodSignature); + if (methods.size() > 1) { + methodCount++; } if (methodCount == 1 && aClass.isEnum() && @@ -874,6 +872,7 @@ public class HighlightMethodUtil { if (hasNoBody) { if (isExtension) { description = JavaErrorMessages.message("extension.method.should.have.a.body"); + additionalFixes.add(new AddMethodBodyFix(method)); } else if (isInterface && isStatic) { description = "Static methods in interfaces should have a body"; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 94508dfe2352..e7b3d6b4bbc9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -2516,7 +2516,7 @@ public class HighlightUtil extends HighlightUtilBase { PsiClass aClass = (PsiClass)resolved; if (refGrandParent instanceof PsiClass) { if (refGrandParent instanceof PsiTypeParameter) { - highlightInfo = GenericsHighlightUtil.checkElementInTypeParameterExtendsList(referenceList, resolveResult, ref); + highlightInfo = GenericsHighlightUtil.checkElementInTypeParameterExtendsList(referenceList, (PsiClass)refGrandParent, resolveResult, ref); } else { highlightInfo = HighlightClassUtil.checkExtendsClassAndImplementsInterface(referenceList, resolveResult, ref); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 1c0e2ecf342b..c705951fe395 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -39,11 +39,9 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspClass; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTagValue; -import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.psi.xml.XmlAttributeValue; +import com.intellij.util.containers.MostlySingularMultiMap; import gnu.trove.THashMap; import gnu.trove.TObjectIntHashMap; import org.jetbrains.annotations.NotNull; @@ -82,11 +80,27 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } }; + private final Map<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>> myDuplicateMethods = new THashMap<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>>(); public HighlightVisitorImpl(@NotNull PsiResolveHelper resolveHelper) { myResolveHelper = resolveHelper; } + @NotNull + private MostlySingularMultiMap<MethodSignature, PsiMethod> getDuplicateMethods(PsiClass aClass) { + MostlySingularMultiMap<MethodSignature, PsiMethod> signatures = myDuplicateMethods.get(aClass); + if (signatures == null) { + signatures = new MostlySingularMultiMap<MethodSignature, PsiMethod>(); + for (PsiMethod method : aClass.getMethods()) { + MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY); + signatures.add(signature, method); + } + + myDuplicateMethods.put(aClass, signatures); + } + return signatures; + } + @Override @NotNull public HighlightVisitorImpl clone() { @@ -130,12 +144,13 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh Project project = file.getProject(); DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(project); FileStatusMap fileStatusMap = ((DaemonCodeAnalyzerImpl)daemonCodeAnalyzer).getFileStatusMap(); - RefCountHolder refCountHolder = RefCountHolder.startUsing(file); + ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + if (indicator == null) throw new IllegalStateException("Must be run under progress"); + RefCountHolder refCountHolder = RefCountHolder.startUsing(file, indicator); myRefCountHolder = refCountHolder; Document document = PsiDocumentManager.getInstance(project).getDocument(file); TextRange dirtyScope = document == null ? file.getTextRange() : fileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL); - ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - success = indicator != null && refCountHolder.analyze(file, dirtyScope, action, indicator); + success = refCountHolder.analyze(file, dirtyScope, action, indicator); } else { myRefCountHolder = null; @@ -152,6 +167,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myRefCountHolder = null; myFile = null; myHolder = null; + myDuplicateMethods.clear(); } return success; @@ -775,7 +791,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } PsiClass aClass = method.getContainingClass(); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodMustHaveBody(method, aClass)); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass))); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorCallsBaseClassConstructor(method, myRefCountHolder, myResolveHelper)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkStaticMethodOverride(method)); } @@ -932,7 +948,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkCannotPassInner(ref)); if (resolved != null && parent instanceof PsiReferenceList) { - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkElementInReferenceList(ref, (PsiReferenceList)parent, result)); + if (!myHolder.hasErrorResults()) { + PsiReferenceList referenceList = (PsiReferenceList)parent; + myHolder.add(HighlightUtil.checkElementInReferenceList(ref, referenceList, result)); + } } if (parent instanceof PsiAnonymousClass && ref.equals(((PsiAnonymousClass)parent).getBaseClassReference())) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeArgumentsConditionalFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeArgumentsConditionalFix.java index 4457e5d47c40..0057749d056b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeArgumentsConditionalFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeArgumentsConditionalFix.java @@ -102,8 +102,8 @@ public class AddTypeArgumentsConditionalFix implements IntentionAction { return true; } - public static void register(HighlightInfo highlightInfo, PsiExpression expression, PsiType lType) { - if (expression instanceof PsiConditionalExpression) { + public static void register(HighlightInfo highlightInfo, PsiExpression expression, @NotNull PsiType lType) { + if (lType != PsiType.NULL && expression instanceof PsiConditionalExpression) { final PsiExpression thenExpression = ((PsiConditionalExpression)expression).getThenExpression(); final PsiExpression elseExpression = ((PsiConditionalExpression)expression).getElseExpression(); if (thenExpression != null && elseExpression != null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java index ad63c638f5d0..667143b2da35 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java @@ -134,7 +134,7 @@ public class CreateFromUsageUtils { JVMElementFactory factory = JVMElementFactories.getFactory(aClass.getLanguage(), aClass.getProject()); - LOG.assertTrue(!aClass.isInterface(), "Interface bodies should be already set up"); + LOG.assertTrue(!aClass.isInterface() || method.hasModifierProperty(PsiModifier.DEFAULT), "Interface bodies should be already set up"); FileType fileType = FileTypeManager.getInstance().getFileTypeByExtension(template.getExtension()); Properties properties = new Properties(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java index 24ba71dc024c..919c6b447259 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java @@ -54,8 +54,11 @@ public class CreateLocalFromUsageFix extends CreateVarFromUsageFix { if (!super.isAvailableImpl(offset)) return false; if(myReferenceExpression.isQualified()) return false; PsiElement scope = PsiTreeUtil.getParentOfType(myReferenceExpression, PsiModifierListOwner.class); + if (scope instanceof PsiAnonymousClass) { + scope = PsiTreeUtil.getParentOfType(scope, PsiModifierListOwner.class, true); + } return scope instanceof PsiMethod || scope instanceof PsiClassInitializer || - scope instanceof PsiLocalVariable || scope instanceof PsiAnonymousClass; + scope instanceof PsiLocalVariable; } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java index f9c9b7b7373c..5e632738fa5c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java @@ -28,16 +28,13 @@ import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiEnumConstant; -import com.intellij.psi.PsiFile; +import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.List; +import java.util.*; public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiElement { public ImplementMethodsFix(PsiElement aClass) { @@ -75,7 +72,7 @@ public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiEle if (editor == null || !FileModificationService.getInstance().prepareFileForWrite(myPsiElement.getContainingFile())) return; if (myPsiElement instanceof PsiEnumConstant) { - final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, ((PsiEnumConstant)myPsiElement).getContainingClass()); + final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, ((PsiEnumConstant)myPsiElement).getContainingClass(), true); if (chooser == null) return; final List<PsiMethodMember> selectedElements = chooser.getSelectedElements(); @@ -103,10 +100,14 @@ public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiEle @Nullable - protected static MemberChooser<PsiMethodMember> chooseMethodsToImplement(Editor editor, PsiElement startElement, PsiClass aClass) { + protected static MemberChooser<PsiMethodMember> chooseMethodsToImplement(Editor editor, + PsiElement startElement, + PsiClass aClass, + boolean implemented) { FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT); + final Collection<CandidateInfo> overrideImplement = OverrideImplementExploreUtil.getMapToOverrideImplement(aClass, true, implemented).values(); return OverrideImplementUtil - .showOverrideImplementChooser(editor, startElement, true, OverrideImplementExploreUtil.getMethodsToOverrideImplement(aClass, true), Collections.<CandidateInfo>emptyList()); + .showOverrideImplementChooser(editor, startElement, true, overrideImplement, ContainerUtil.<CandidateInfo>newArrayList()); } } 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 a2bebf63ac18..2e23f7ef65e4 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 @@ -107,6 +107,7 @@ public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceEleme return super.getRequiredMemberName(reference); } + @NotNull @Override protected List<PsiClass> filterByContext(@NotNull List<PsiClass> candidates, @NotNull PsiJavaCodeReferenceElement ref) { PsiElement typeElement = ref.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 e34ad1820c89..bfb7c45bf3c8 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 @@ -184,6 +184,7 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe return null; } + @NotNull protected List<PsiClass> filterByContext(@NotNull List<PsiClass> candidates, @NotNull T ref) { return candidates; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java index 6ac2e5d9e37e..0d710688eec1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java @@ -141,6 +141,7 @@ public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement { final PsiModifierList myModifierList = (PsiModifierList)startElement; final PsiVariable variable = myVariable == null ? null : myVariable.getElement(); if (!FileModificationService.getInstance().preparePsiElementForWrite(myModifierList)) return; + if (variable != null && !FileModificationService.getInstance().preparePsiElementForWrite(variable)) return; final List<PsiModifierList> modifierLists = new ArrayList<PsiModifierList>(); final PsiFile containingFile = myModifierList.getContainingFile(); final PsiModifierList modifierList; @@ -180,8 +181,6 @@ public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement { })); } - if (!FileModificationService.getInstance().prepareFileForWrite(containingFile)) return; - if (!modifierLists.isEmpty()) { if (Messages.showYesNoDialog(project, QuickFixBundle.message("change.inheritors.visibility.warning.text"), |