diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java b/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java index ed62d32ba2cd..81c76b2737c8 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java @@ -78,8 +78,8 @@ public class PsiSuperMethodImplUtil { @NotNull private static List findSuperMethodSignatures(PsiMethod method, - PsiClass parentClass, - boolean allowStaticMethod) { + PsiClass parentClass, + boolean allowStaticMethod) { return new ArrayList(SuperMethodsSearch.search(method, parentClass, true, allowStaticMethod).findAll()); } @@ -306,4 +306,58 @@ public class PsiSuperMethodImplUtil { private static Map getSignaturesMap(final PsiClass aClass) { return SIGNATURES_KEY.getValue(aClass); } + + + // uses hierarchy signature tree if available, traverses class structure by itself otherwise + public static boolean isSuperMethodSmart(@NotNull PsiMethod method, @NotNull PsiMethod superMethod) { + //boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod); + + if (method == superMethod) return false; + PsiClass aClass = method.getContainingClass(); + PsiClass superClass = superMethod.getContainingClass(); + + if (aClass == null || superClass == null || superClass == aClass) return false; + + if (!canHaveSuperMethod(method, true, false)) return false; + + PsiMethod[] superMethods = null; + Map cachedMap = SIGNATURES_KEY.getCachedValueOrNull(aClass); + if (cachedMap != null) { + HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); + if (signature != null) { + superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures()); + } + } + if (superMethods == null) { + PsiClassType[] directSupers = aClass.getSuperTypes(); + List found = null; + boolean canceled = false; + for (PsiClassType directSuper : directSupers) { + PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics(); + if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { + // generics + canceled = true; + break; + } + PsiClass directSuperClass = resolveResult.getElement(); + if (directSuperClass == null) continue; + PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false); + if (candidates.length != 0) { + if (found == null) found = new ArrayList(); + for (PsiMethod candidate : candidates) { + if (PsiUtil.canBeOverriden(candidate)) found.add(candidate); + } + } + } + superMethods = canceled ? null : found == null ? PsiMethod.EMPTY_ARRAY : found.toArray(new PsiMethod[found.size()]); + } + if (superMethods == null) { + superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(method.getHierarchicalMethodSignature().getSuperSignatures()); + } + + for (PsiMethod superCandidate : superMethods) { + if (superMethod.equals(superCandidate) || isSuperMethodSmart(superCandidate, superMethod)) return true; + } + return false; + } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java index d85d4a99a724..b49ea654f6dd 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java @@ -332,6 +332,7 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements public boolean isReferenceTo(PsiElement element) { IElementType i = getLastChildNode().getElementType(); + boolean resolvingToMethod = element instanceof PsiMethod; if (i == JavaTokenType.IDENTIFIER) { if (!(element instanceof PsiPackage)) { if (!(element instanceof PsiNamedElement)) return false; @@ -341,10 +342,15 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements } } else if (i == JavaTokenType.SUPER_KEYWORD || i == JavaTokenType.THIS_KEYWORD) { - if (!(element instanceof PsiMethod)) return false; + if (!resolvingToMethod) return false; if (!((PsiMethod)element).isConstructor()) return false; } + PsiElement parent = getParent(); + boolean parentIsMethodCall = parent instanceof PsiMethodCallExpression; + // optimization: methodCallExpression should resolve to a method + if (parentIsMethodCall != resolvingToMethod) return false; + return element.getManager().areElementsEquivalent(element, resolve()); } diff --git a/java/java-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index f324999ba9a7..db990d48f565 100644 --- a/java/java-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -19,6 +19,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.scope.PsiConflictResolver; @@ -150,7 +151,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ if (!method.hasModifierProperty(PsiModifier.STATIC)) { for (int k=i-1; k>=0; k--) { PsiMethod existingMethod = (PsiMethod)conflicts.get(k).getElement(); - if (PsiSuperMethodUtil.isSuperMethod(existingMethod, method)) { + if (PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) { conflicts.remove(i); i--; continue nextConflict; @@ -189,12 +190,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ // filter out methods with incorrect inferred bounds (for unrelated methods only) boolean existingTypeParamAgree = areTypeParametersAgree(existing); boolean infoTypeParamAgree = areTypeParametersAgree(info); - if (existingTypeParamAgree && !infoTypeParamAgree && !PsiSuperMethodUtil.isSuperMethod(method, existingMethod)) { + if (existingTypeParamAgree && !infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(method, existingMethod)) { conflicts.remove(i); i--; continue; } - else if (!existingTypeParamAgree && infoTypeParamAgree && !PsiSuperMethodUtil.isSuperMethod(existingMethod, method)) { + else if (!existingTypeParamAgree && infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) { signatures.put(signature, info); int index = conflicts.indexOf(existing); conflicts.remove(index); diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiCacheKey.java b/platform/lang-api/src/com/intellij/psi/util/PsiCacheKey.java index d6ccc12f249a..8c6c16991e0e 100644 --- a/platform/lang-api/src/com/intellij/psi/util/PsiCacheKey.java +++ b/platform/lang-api/src/com/intellij/psi/util/PsiCacheKey.java @@ -21,9 +21,11 @@ package com.intellij.psi.util; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.UserDataHolderEx; import com.intellij.psi.PsiElement; import com.intellij.util.Function; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; public class PsiCacheKey extends Key> { private final Function myFunction; @@ -34,10 +36,34 @@ public class PsiCacheKey extends Key> { } public final T getValue(H h) { + while (true) { + Pair data = h.getUserData(this); + + final long count = h.getManager().getModificationTracker().getJavaStructureModificationCount(); + if (data == null) { + data = new Pair(count, myFunction.fun(h)); + data = ((UserDataHolderEx)h).putUserDataIfAbsent(this, data); + } + else if (data.getFirst() != count) { + Pair newData = new Pair(count, myFunction.fun(h)); + if (((UserDataHolderEx)h).replace(this, data, newData)) { + data = newData; + } + else { + continue; + } + } + + return data.getSecond(); + } + } + + @Nullable + public final T getCachedValueOrNull(H h) { Pair data = h.getUserData(this); final long count = h.getManager().getModificationTracker().getJavaStructureModificationCount(); if (data == null || data.getFirst() != count) { - h.putUserData(this, data = new Pair(count, myFunction.fun(h))); + return null; } return data.getSecond(); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index aa180d5fae4a..1c2aaf448b61 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -18,7 +18,6 @@ package com.intellij.psi.impl.search; import com.intellij.codeInsight.CommentUtil; import com.intellij.concurrency.JobUtil; -import com.intellij.ide.todo.TodoConfiguration; import com.intellij.ide.todo.TodoIndexPatternProvider; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; @@ -44,6 +43,7 @@ import com.intellij.psi.search.searches.IndexPatternSearch; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; +import com.intellij.util.SmartList; import com.intellij.util.containers.CollectionFactory; import com.intellij.util.containers.MultiMap; import com.intellij.util.indexing.FileBasedIndex; @@ -489,8 +489,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { refProcessor = new Processor() { @Override public boolean process(PsiReference psiReference) { - if (!myProcessor.process(psiReference)) return false; - return another.refProcessor.process(psiReference); + return myProcessor.process(psiReference) && another.refProcessor.process(psiReference); } }; } @@ -571,7 +570,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { progress.setText(PsiBundle.message("psi.scanning.files.progress")); } - final MultiMap candidateFiles = collectFiles(singles); + final MultiMap candidateFiles = collectFiles(singles, progress); if (candidateFiles.isEmpty()) { return true; @@ -593,7 +592,8 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { final VirtualFile vfile = psiRoot.getContainingFile().getVirtualFile(); for (final RequestWithProcessor singleRequest : candidateFiles.get(vfile)) { StringSearcher searcher = searchers.get(singleRequest); - if (!LowLevelSearchUtil.processElementsContainingWordInElement(adaptProcessor(singleRequest.request, singleRequest.refProcessor), psiRoot, searcher, false, progress)) { + TextOccurenceProcessor adapted = adaptProcessor(singleRequest.request, singleRequest.refProcessor); + if (!LowLevelSearchUtil.processElementsContainingWordInElement(adapted, psiRoot, searcher, false, progress)) { return false; } } @@ -616,9 +616,10 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { }; } - private MultiMap collectFiles(MultiMap, RequestWithProcessor> singles) { + private MultiMap collectFiles(MultiMap, RequestWithProcessor> singles, + ProgressIndicator progress) { final ProjectFileIndex index = ProjectRootManager.getInstance(myManager.getProject()).getFileIndex(); - final MultiMap result = new MultiMap(); + final MultiMap result = createMultiMap(); for (Set key : singles.keySet()) { if (key.isEmpty()) { continue; @@ -631,7 +632,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { boolean first = true; for (IdIndexEntry entry : key) { - final MultiMap local = findFilesWithIndexEntry(entry, index, data, commonScope); + final MultiMap local = findFilesWithIndexEntry(entry, index, data, commonScope, progress); if (first) { intersection = local; first = false; @@ -648,6 +649,15 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { return result; } + private static MultiMap createMultiMap() { + return new MultiMap(){ + @Override + protected Collection createCollection() { + return new SmartList(); // usually there is just one request + } + }; + } + private static GlobalSearchScope uniteScopes(Collection requests) { GlobalSearchScope commonScope = null; for (RequestWithProcessor r : requests) { @@ -659,29 +669,30 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { } private static MultiMap findFilesWithIndexEntry(final IdIndexEntry entry, - final ProjectFileIndex index, - final Collection data, - final GlobalSearchScope commonScope) { - final MultiMap local = new MultiMap(); + final ProjectFileIndex index, + final Collection data, + final GlobalSearchScope commonScope, + final ProgressIndicator progress) { + final MultiMap local = createMultiMap(); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { - ProgressManager.checkCanceled(); + if (progress != null) progress.checkCanceled(); FileBasedIndex.getInstance().processValues(IdIndex.NAME, entry, null, new FileBasedIndex.ValueProcessor() { - public boolean process(VirtualFile file, Integer value) { - ProgressManager.checkCanceled(); - if (!IndexCacheManagerImpl.shouldBeFound(file, index)) { + public boolean process(VirtualFile file, Integer value) { + if (progress != null) progress.checkCanceled(); + if (!IndexCacheManagerImpl.shouldBeFound(file, index)) { + return true; + } + int mask = value.intValue(); + for (RequestWithProcessor single : data) { + final PsiSearchRequest request = single.request; + if ((mask & request.searchContext) != 0 && ((GlobalSearchScope)request.searchScope).contains(file)) { + local.putValue(file, single); + } + } return true; } - int mask = value.intValue(); - for (RequestWithProcessor single : data) { - final PsiSearchRequest request = single.request; - if ((mask & request.searchContext) != 0 && ((GlobalSearchScope)request.searchScope).contains(file)) { - local.putValue(file, single); - } - } - return true; - } - }, commonScope); + }, commonScope); } });