diff options
author | Tor Norbye <tnorbye@google.com> | 2013-08-07 11:11:08 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-08-07 11:11:08 -0700 |
commit | 6739a8f0977b70ddc8a8283b169902da3f2eecb3 (patch) | |
tree | 5c5573c2ac01544f02d9318671aa558769726289 /java/java-psi-impl/src/com | |
parent | c1ace1f7e1e49c81bb4b75377c99f07be340abfe (diff) | |
download | idea-6739a8f0977b70ddc8a8283b169902da3f2eecb3.tar.gz |
Snapshot af729d01433bb5bbd6ca93c0fdf9778b36d624ce from master branch of git://git.jetbrains.org/idea/community.git
Change-Id: I214dd066d0d27444a26166c0eae1a5aaf3705d49
Diffstat (limited to 'java/java-psi-impl/src/com')
59 files changed, 467 insertions, 2466 deletions
diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java index 4b245a060297..44055a7f08b0 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java @@ -15,8 +15,6 @@ */ package com.intellij.codeInsight; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; import com.intellij.psi.impl.PsiImplUtil; @@ -403,7 +401,8 @@ public class ExceptionUtil { boolean includeSelfCalls) { final JavaResolveResult result = methodCall.resolveMethodGenerics(); final PsiMethod method = (PsiMethod)result.getElement(); - if (!includeSelfCalls && method == PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class)) { + PsiMethod containingMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class); + if (!includeSelfCalls && method == containingMethod) { return Collections.emptyList(); } @@ -411,7 +410,8 @@ public class ExceptionUtil { if (method != null && !isArrayClone(method, methodCall) && methodCall instanceof PsiMethodCallExpression) { final PsiClassType[] thrownExceptions = method.getThrowsList().getReferencedTypes(); if (thrownExceptions.length > 0) { - final MethodResolverProcessor processor = new MethodResolverProcessor((PsiMethodCallExpression)methodCall); + PsiFile containingFile = (containingMethod == null ? methodCall : containingMethod).getContainingFile(); + final MethodResolverProcessor processor = new MethodResolverProcessor((PsiMethodCallExpression)methodCall, containingFile); try { PsiScopesUtil.setupAndRunProcessor(processor, methodCall, false); final List<CandidateInfo> results = processor.getResults(); @@ -541,7 +541,7 @@ public class ExceptionUtil { List<PsiClassType> result = ContainerUtil.newArrayList(); for (PsiClassType referencedType : referencedTypes) { - final PsiType type = substitutor.substitute(referencedType); + final PsiType type = GenericsUtil.eliminateWildcards(substitutor.substitute(referencedType), false); if (!(type instanceof PsiClassType)) continue; PsiClassType classType = (PsiClassType)type; PsiClass exceptionClass = ((PsiClassType)type).resolve(); diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowFactory.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowFactory.java index e8ca9d832771..a1b28c5c59a8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowFactory.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowFactory.java @@ -29,7 +29,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NotNullLazyKey; import com.intellij.psi.PsiElement; import com.intellij.psi.impl.PsiManagerEx; -import com.intellij.util.ConcurrencyUtil; import com.intellij.util.containers.ConcurrentWeakHashMap; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -163,10 +162,7 @@ public class ControlFlowFactory { CopyOnWriteArrayList<ControlFlowContext> cached = cachedRef == null ? null : cachedRef.get(); if (cached == null) { cached = ContainerUtil.createEmptyCOWList(); - Reference<CopyOnWriteArrayList<ControlFlowContext>> reference = new SoftReference<CopyOnWriteArrayList<ControlFlowContext>>(cached); - cachedRef = ConcurrencyUtil.cacheOrGet(cachedFlows, element, reference); - CopyOnWriteArrayList<ControlFlowContext> existing = cachedRef.get(); - if (existing != null) cached = existing; + cachedFlows.put(element, new SoftReference<CopyOnWriteArrayList<ControlFlowContext>>(cached)); } return cached; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java index 247477e20323..e9596f8dd96b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java @@ -39,7 +39,8 @@ public class InheritanceImplUtil { public static boolean isInheritor(@NotNull final PsiClass candidateClass, @NotNull PsiClass baseClass, final boolean checkDeep) { if (baseClass instanceof PsiAnonymousClass) return false; if (!checkDeep) return isInheritor(candidateClass, baseClass, false, null); - + + if (CommonClassNames.JAVA_LANG_OBJECT.equals(candidateClass.getQualifiedName())) return false; if (CommonClassNames.JAVA_LANG_OBJECT.equals(baseClass.getQualifiedName())) return true; Map<PsiClass, Boolean> map = CachedValuesManager.getManager(candidateClass.getProject()). getCachedValue(candidateClass, new CachedValueProvider<Map<PsiClass, Boolean>>() { @@ -50,7 +51,7 @@ public class InheritanceImplUtil { return Result.create(map, candidateClass); } }); - + Boolean computed = map.get(baseClass); if (computed == null) { computed = isInheritor(candidateClass, baseClass, true, null); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java index 2bde13a67ae5..b805ef4cf8f0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java @@ -34,6 +34,7 @@ import com.intellij.psi.impl.source.JavaDummyHolderFactory; import com.intellij.psi.impl.source.resolve.FileContextUtil; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.stubs.StubTreeLoader; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiUtilCore; import com.intellij.reference.SoftReference; @@ -249,9 +250,12 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return result == null ? PsiClass.EMPTY_ARRAY : result.toArray(new PsiClass[result.size()]); } - public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope, @NotNull Processor<PsiDirectory> consumer) { + public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, + @NotNull GlobalSearchScope scope, + @NotNull Processor<PsiDirectory> consumer, + boolean includeLibrarySources) { for (PsiElementFinder finder : filteredFinders()) { - if (!finder.processPackageDirectories(psiPackage, scope, consumer)) { + if (!finder.processPackageDirectories(psiPackage, scope, consumer, includeLibrarySources)) { return false; } } @@ -371,7 +375,11 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { for (PsiFile file : dir.getFiles()) { if (file instanceof PsiClassOwner && file.getViewProvider().getLanguages().size() == 1) { VirtualFile vFile = file.getVirtualFile(); - if (vFile != null && !facade.isInSourceContent(vFile) && !(file instanceof PsiCompiledElement)) { + if (vFile != null && + !(file instanceof PsiCompiledElement) && + !facade.isInSourceContent(vFile) && + (!scope.isForceSearchingInLibrarySources() || + !StubTreeLoader.getInstance().canHaveStub(vFile))) { continue; } @@ -388,16 +396,20 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } @Override - public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull final GlobalSearchScope scope, @NotNull final Processor<PsiDirectory> consumer) { + public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, + @NotNull final GlobalSearchScope scope, + @NotNull final Processor<PsiDirectory> consumer, + boolean includeLibrarySources) { final PsiManager psiManager = PsiManager.getInstance(getProject()); - return PackageIndex.getInstance(getProject()).getDirsByPackageName(psiPackage.getQualifiedName(), false).forEach(new ReadActionProcessor<VirtualFile>() { - @Override - public boolean processInReadAction(final VirtualFile dir) { - if (!scope.contains(dir)) return true; - PsiDirectory psiDir = psiManager.findDirectory(dir); - return psiDir == null || consumer.process(psiDir); - } - }); + return PackageIndex.getInstance(getProject()).getDirsByPackageName(psiPackage.getQualifiedName(), includeLibrarySources) + .forEach(new ReadActionProcessor<VirtualFile>() { + @Override + public boolean processInReadAction(final VirtualFile dir) { + if (!scope.contains(dir)) return true; + PsiDirectory psiDir = psiManager.findDirectory(dir); + return psiDir == null || consumer.process(psiDir); + } + }); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index a0f3e9a3e045..831f7ad2112e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -15,7 +15,6 @@ */ package com.intellij.psi.impl; -import com.intellij.lang.ASTNode; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicatorProvider; @@ -430,6 +429,7 @@ public class PsiClassImplUtil { @Nullable Set<PsiClass> visited, PsiElement last, @NotNull PsiElement place, + @NotNull LanguageLevel languageLevel, boolean isRaw) { if (last instanceof PsiTypeParameterList || last instanceof PsiModifierList) { return true; //TypeParameterList and ModifierList do not see our declarations @@ -441,7 +441,6 @@ public class PsiClassImplUtil { ParameterizedCachedValue<MembersMap, PsiClass> cache = getValues(aClass); //aClass.getUserData(MAP_IN_CLASS_KEY); boolean upToDate = cache.hasUpToDateValue(); - LanguageLevel languageLevel = PsiUtil.getLanguageLevel(place); if (/*true || */upToDate) { final NameHint nameHint = processor.getHint(NameHint.KEY); if (nameHint != null) { @@ -693,7 +692,7 @@ public class PsiClassImplUtil { if (superClass == null) continue; PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superTypeResolveResult.getSubstitutor(), aClass, state.get(PsiSubstitutor.KEY), factory, languageLevel); - if (!processDeclarationsInClass(superClass, processor, state.put(PsiSubstitutor.KEY, finalSubstitutor), visited, last, place, isRaw)) { + if (!processDeclarationsInClass(superClass, processor, state.put(PsiSubstitutor.KEY, finalSubstitutor), visited, last, place, languageLevel, isRaw)) { resolved = true; } } @@ -1041,14 +1040,8 @@ public class PsiClassImplUtil { @NotNull private static PsiElement originalElement(@NotNull PsiClass aClass) { final PsiElement originalElement = aClass.getOriginalElement(); - ASTNode node = originalElement.getNode(); - if (node != null) { - final PsiCompiledElement compiled = node.getUserData(ClsElementImpl.COMPILED_ELEMENT); - if (compiled != null) { - return compiled; - } - } - return originalElement; + final PsiCompiledElement compiled = originalElement.getUserData(ClsElementImpl.COMPILED_ELEMENT); + return compiled != null ? compiled : originalElement; } public static boolean isFieldEquivalentTo(@NotNull PsiField field, PsiElement another) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java index 9ac1dd20098a..5b659f0f4631 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java @@ -182,11 +182,12 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps public PsiTypeParameter createTypeParameter(String name, PsiClassType[] superTypes) { @NonNls StringBuilder builder = new StringBuilder(); builder.append("public <").append(name); - if (superTypes.length > 1) { + if (superTypes.length > 1 || + superTypes.length == 1 && !superTypes[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { builder.append(" extends "); for (PsiClassType type : superTypes) { if (type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) continue; - builder.append(type.getCanonicalText()).append(','); + builder.append(type.getCanonicalText()).append('&'); } builder.delete(builder.length() - 1, builder.length()); @@ -755,4 +756,33 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps GeneratedMarkerVisitor.markGenerated(catchSection); return catchSection; } + + @Override + public boolean isValidClassName(@NotNull String name) { + return isIdentifier(name); + } + + @Override + public boolean isValidMethodName(@NotNull String name) { + return isIdentifier(name); + } + + @Override + public boolean isValidParameterName(@NotNull String name) { + return isIdentifier(name); + } + + @Override + public boolean isValidFieldName(@NotNull String name) { + return isIdentifier(name); + } + + @Override + public boolean isValidLocalVariableName(@NotNull String name) { + return isIdentifier(name); + } + + private boolean isIdentifier(@NotNull String name) { + return JavaPsiFacade.getInstance(myManager.getProject()).getNameHelper().isIdentifier(name); + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index 61e71bbb7270..c27bfdc68d62 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -168,6 +168,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { } } if (!wildcard.isBounded()) return PsiWildcardType.createUnbounded(wildcardType.getManager()); + return newBound; } return rebound(wildcardType, newBound); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java index 466a53cb0514..68e5b0f02ec7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.compiled; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -29,6 +30,7 @@ import com.intellij.util.indexing.FileContent; * @author max */ public class ClassFileStubBuilder implements BinaryFileStubBuilder { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.compiled.ClassFileStubBuilder"); public static final int STUB_VERSION = JavaFileElementType.STUB_VERSION + 6; @Override @@ -49,6 +51,9 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder { if (stub != null) return stub; } } + if (!fileContent.getFileName().contains("$")) { + LOG.info("No stub built for file " + fileContent); + } return null; } catch (ClsFormatException e) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java index e73ac2a3ccdf..60e343b188e7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java @@ -21,6 +21,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.InheritanceImplUtil; import com.intellij.psi.impl.PsiClassImplUtil; @@ -31,7 +32,9 @@ import com.intellij.psi.impl.java.stubs.PsiClassStub; import com.intellij.psi.impl.source.*; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.scope.processor.MethodsProcessor; import com.intellij.psi.search.SearchScope; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; @@ -445,7 +448,8 @@ public class ClsClassImpl extends ClsMemberImpl<PsiClassStub<?>> implements PsiE @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { - return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, false); + LanguageLevel languageLevel = processor instanceof MethodsProcessor ? ((MethodsProcessor)processor).getLanguageLevel() : PsiUtil.getLanguageLevel(place); + return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, languageLevel, false); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsElementImpl.java index 5f55a5bd0412..3fbfc4ba69c2 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsElementImpl.java @@ -288,7 +288,7 @@ public abstract class ClsElementImpl extends PsiElementBase implements PsiCompil throw new InvalidMirrorException(element.getElementType() + " != " + type); } - element.putUserData(COMPILED_ELEMENT, this); + element.getPsi().putUserData(COMPILED_ELEMENT, this); myMirror = element; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java index 05655345dbb7..a6820cd13164 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java @@ -421,13 +421,13 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub> stubTree = (StubTree)StubTreeLoader.getInstance().readOrBuild(getProject(), getVirtualFile(), this); if (stubTree == null) { - LOG.warn("Class file is corrupted: " + getVirtualFile().getPresentableUrl()); + LOG.warn("No stub for class file in index: " + getVirtualFile().getPresentableUrl()); stubTree = new StubTree(new PsiJavaFileStubImpl("corrupted.classfiles", true)); } - - myStub = new SoftReference<StubTree>(stubTree); //noinspection unchecked ((PsiFileStubImpl)stubTree.getRoot()).setPsi(this); + + myStub = new SoftReference<StubTree>(stubTree); } return stubTree; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java index 7c2e8e0e5068..3096f2485d6b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java @@ -199,7 +199,7 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P } @Override - public void processVariants(PsiScopeProcessor processor) { + public void processVariants(@NotNull PsiScopeProcessor processor) { throw new RuntimeException("Variants are not available for light references"); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsReferenceExpressionImpl.java index bb2776b5f026..155e0daa7fc2 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsReferenceExpressionImpl.java @@ -169,7 +169,7 @@ public class ClsReferenceExpressionImpl extends ClsElementImpl implements PsiRef } @Override - public void processVariants(PsiScopeProcessor processor) { + public void processVariants(@NotNull PsiScopeProcessor processor) { myPatternExpression.processVariants(processor); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeParameterImpl.java index 937def146dab..cf6e15928d59 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeParameterImpl.java @@ -30,6 +30,7 @@ import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.SearchScope; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -153,7 +154,7 @@ public class ClsTypeParameterImpl extends ClsRepositoryPsiElement<PsiTypeParamet @Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { - return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, false); + return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, PsiUtil.getLanguageLevel(place), false); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java index 20ab20211c95..d023667ef063 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java @@ -29,6 +29,7 @@ import com.intellij.psi.impl.source.tree.java.PsiCompositeModifierList; import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.NameHint; import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.*; import com.intellij.reference.SoftReference; @@ -47,6 +48,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya public static boolean DEBUG = false; private volatile CachedValue<PsiModifierList> myAnnotationList; private volatile CachedValue<Collection<PsiDirectory>> myDirectories; + private volatile CachedValue<Collection<PsiDirectory>> myDirectoriesWithLibSources; private volatile SoftReference<Set<String>> myPublicClassNamesCache; public PsiPackageImpl(PsiManager manager, String qualifiedName) { @@ -54,19 +56,31 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya } @Override - protected Collection<PsiDirectory> getAllDirectories() { - if (myDirectories == null) { - myDirectories = CachedValuesManager.getManager(myManager.getProject()).createCachedValue(new CachedValueProvider<Collection<PsiDirectory>>() { - @Override - public Result<Collection<PsiDirectory>> compute() { - final CommonProcessors.CollectProcessor<PsiDirectory> processor = new CommonProcessors.CollectProcessor<PsiDirectory>(); - getFacade().processPackageDirectories(PsiPackageImpl.this, allScope(), processor); - return Result.create(processor.getResults(), PsiPackageImplementationHelper.getInstance().getDirectoryCachedValueDependencies( - PsiPackageImpl.this)); - } - }, false); + protected Collection<PsiDirectory> getAllDirectories(boolean includeLibrarySources) { + if (includeLibrarySources) { + if (myDirectoriesWithLibSources == null) { + myDirectoriesWithLibSources = createCachedDirectories(true); + } + return myDirectoriesWithLibSources.getValue(); + } + else { + if (myDirectories == null) { + myDirectories = createCachedDirectories(false); + } + return myDirectories.getValue(); } - return myDirectories.getValue(); + } + + private CachedValue<Collection<PsiDirectory>> createCachedDirectories(final boolean includeLibrarySources) { + return CachedValuesManager.getManager(myManager.getProject()).createCachedValue(new CachedValueProvider<Collection<PsiDirectory>>() { + @Override + public Result<Collection<PsiDirectory>> compute() { + final CommonProcessors.CollectProcessor<PsiDirectory> processor = new CommonProcessors.CollectProcessor<PsiDirectory>(); + getFacade().processPackageDirectories(PsiPackageImpl.this, allScope(), processor, includeLibrarySources); + return Result.create(processor.getResults(), PsiPackageImplementationHelper.getInstance().getDirectoryCachedValueDependencies( + PsiPackageImpl.this)); + } + }, false); } @Override @@ -103,7 +117,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya @Override public boolean isValid() { - return PsiPackageImplementationHelper.getInstance().packagePrefixExists(this) || !getAllDirectories().isEmpty(); + return PsiPackageImplementationHelper.getInstance().packagePrefixExists(this) || !getAllDirectories(true).isEmpty(); } @Override @@ -165,7 +179,17 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya SoftReference<Set<String>> ref = myPublicClassNamesCache; Set<String> cache = ref == null ? null : ref.get(); if (cache == null) { - cache = getFacade().getClassNames(this, allScope()); + GlobalSearchScope scope = allScope(); + + if (!scope.isForceSearchingInLibrarySources()) { + scope = new DelegatingGlobalSearchScope(scope) { + @Override + public boolean isForceSearchingInLibrarySources() { + return true; + } + }; + } + cache = getFacade().getClassNames(this, scope); myPublicClassNamesCache = new SoftReference<Set<String>>(cache); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/light/AbstractLightClass.java b/java/java-psi-impl/src/com/intellij/psi/impl/light/AbstractLightClass.java index 2de3bc886f0c..baef0daece76 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/light/AbstractLightClass.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/light/AbstractLightClass.java @@ -27,6 +27,7 @@ import com.intellij.psi.impl.PsiClassImplUtil; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -206,7 +207,7 @@ public abstract class AbstractLightClass extends LightElement implements PsiClas @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { - return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, false); + return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, PsiUtil.getLanguageLevel(place), false); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightClassReference.java b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightClassReference.java index e47d8965bfe3..163e0266d656 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightClassReference.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightClassReference.java @@ -119,7 +119,7 @@ public class LightClassReference extends LightElement implements PsiJavaCodeRefe } @Override - public void processVariants(PsiScopeProcessor processor){ + public void processVariants(@NotNull PsiScopeProcessor processor){ throw new RuntimeException("Variants are not available for light references"); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightMemberReference.java b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightMemberReference.java index f1f5d484135f..bc90ac135613 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightMemberReference.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightMemberReference.java @@ -61,7 +61,7 @@ public class LightMemberReference extends LightElement implements PsiJavaCodeRef } @Override - public void processVariants(PsiScopeProcessor processor){ + public void processVariants(@NotNull PsiScopeProcessor processor){ throw new RuntimeException("Variants are not available for light references"); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightPackageReference.java b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightPackageReference.java index 1f5abf5560f5..7aa6aaac83af 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightPackageReference.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightPackageReference.java @@ -138,7 +138,7 @@ public class LightPackageReference extends LightElement implements PsiJavaCodeRe } @Override - public void processVariants(PsiScopeProcessor processor){ + public void processVariants(@NotNull PsiScopeProcessor processor){ throw new RuntimeException("Variants are not available for light references"); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java index 3ce5161b4ff9..6d6229c32886 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java @@ -40,6 +40,7 @@ import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.stubs.PsiFileStub; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -515,7 +516,7 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements } } - return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, false); + return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, PsiUtil.getLanguageLevel(place), false); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiEnumConstantImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiEnumConstantImpl.java index e05d5eb2d731..4b28435bf089 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiEnumConstantImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiEnumConstantImpl.java @@ -260,7 +260,7 @@ public class PsiEnumConstantImpl extends JavaStubPsiElement<PsiFieldStub> implem } @Override - public void processVariants(PsiScopeProcessor processor) { + public void processVariants(@NotNull PsiScopeProcessor processor) { } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java index 2a71d6e6303d..a98412f5b0b5 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java @@ -239,8 +239,9 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps @Override public boolean hasInitializer() { - if (getStub() != null) { - return getInitializerText() != null; + PsiFieldStub stub = getStub(); + if (stub != null) { + return stub.getInitializerText() != null; } return getInitializer() != null; @@ -327,16 +328,6 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps return JavaResolveCache.getInstance(getProject()).computeConstantValueWithCaching(this, OurConstValueComputer.INSTANCE, visitedVars); } - @Nullable - private String getInitializerText() { - final PsiFieldStub stub = getStub(); - if (stub != null) { - return stub.getInitializerText(); - } - - throw new RuntimeException("Shall not be called when in stubless mode"); - } - @Override public boolean isDeprecated() { final PsiFieldStub stub = getStub(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImportStaticReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImportStaticReferenceElementImpl.java index da73dcde6404..affc24678325 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImportStaticReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImportStaticReferenceElementImpl.java @@ -320,7 +320,7 @@ public class PsiImportStaticReferenceElementImpl extends CompositePsiElement imp } @Override - public void processVariants(PsiScopeProcessor processor) { + public void processVariants(@NotNull PsiScopeProcessor processor) { FilterScopeProcessor proc = new FilterScopeProcessor(new ClassFilter(PsiModifierListOwner.class), processor); PsiScopesUtil.resolveAndWalk(proc, this, null, true); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index 9605d07b619c..48a0e0948132 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java @@ -24,7 +24,6 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettingsFacade; import com.intellij.psi.filters.*; -import com.intellij.psi.filters.classes.AnnotationTypeFilter; import com.intellij.psi.filters.element.ModifierFilter; import com.intellij.psi.impl.CheckUtil; import com.intellij.psi.impl.DebugUtil; @@ -55,7 +54,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl"); private volatile String myCachedQName = null; - private volatile String myCachedTextSkipWhiteSpaceAndComments; + private volatile String myCachedNormalizedText; private int myKindWhenDummy = CLASS_NAME_KIND; public static final int CLASS_NAME_KIND = 1; @@ -291,12 +290,12 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme } else { LOG.assertTrue(target == null, target); - return getTextSkipWhiteSpaceAndComments(); + return getNormalizedText(); } case PACKAGE_NAME_KIND: case CLASS_FQ_NAME_KIND: case CLASS_FQ_OR_PACKAGE_NAME_KIND: - return getTextSkipWhiteSpaceAndComments(); + return getNormalizedText(); default: LOG.assertTrue(false); @@ -322,14 +321,15 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme public JavaResolveResult[] resolve(@NotNull PsiJavaReference ref, boolean incompleteCode) { PsiJavaCodeReferenceElementImpl referenceElement = (PsiJavaCodeReferenceElementImpl)ref; int kind = referenceElement.getKind(); - JavaResolveResult[] result = referenceElement.resolve(kind); + PsiFile containingFile = referenceElement.getContainingFile(); + JavaResolveResult[] result = referenceElement.resolve(kind, containingFile); if (incompleteCode && result.length == 0 && kind != CLASS_FQ_NAME_KIND && kind != CLASS_FQ_OR_PACKAGE_NAME_KIND) { - VariableResolverProcessor processor = new VariableResolverProcessor(referenceElement); + VariableResolverProcessor processor = new VariableResolverProcessor(referenceElement, containingFile); PsiScopesUtil.resolveAndWalk(processor, referenceElement, null, incompleteCode); result = processor.getResult(); if (result.length == 0 && kind == CLASS_NAME_KIND) { - result = referenceElement.resolve(PACKAGE_NAME_KIND); + result = referenceElement.resolve(PACKAGE_NAME_KIND, containingFile); } } @@ -380,19 +380,18 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme return subst; } - private JavaResolveResult[] resolve(final int kind) { + private JavaResolveResult[] resolve(final int kind, PsiFile containingFile) { switch (kind) { case CLASS_FQ_NAME_KIND: { // TODO: support type parameters in FQ names - String text = getTextSkipWhiteSpaceAndComments(); + String text = getNormalizedText(); if (StringUtil.isEmptyOrSpaces(text)) return JavaResolveResult.EMPTY_ARRAY; PsiClass aClass = JavaPsiFacade.getInstance(getProject()).findClass(text, getResolveScope()); if (aClass == null) return JavaResolveResult.EMPTY_ARRAY; if (!isQualified() && text.equals(aClass.getQualifiedName())) { - PsiFile file = getContainingFile(); - if (file instanceof PsiJavaFile && !((PsiJavaFile)file).getPackageName().isEmpty()) { + if (containingFile instanceof PsiJavaFile && !((PsiJavaFile)containingFile).getPackageName().isEmpty()) { // classes in default (unnamed) package cannot be referenced from other packages return JavaResolveResult.EMPTY_ARRAY; } @@ -432,7 +431,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme if (!(classNameElement instanceof PsiIdentifier)) return JavaResolveResult.EMPTY_ARRAY; final String className = classNameElement.getText(); - final ClassResolverProcessor processor = new ClassResolverProcessor(className, this, getContainingFile()); + final ClassResolverProcessor processor = new ClassResolverProcessor(className, this, containingFile); resultElement.processDeclarations(processor, ResolveState.initial().put(PsiSubstitutor.KEY, result.getSubstitutor()), this, this); return processor.getResult(); } @@ -440,12 +439,12 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme final PsiElement classNameElement = getReferenceNameElement(); if (!(classNameElement instanceof PsiIdentifier)) return JavaResolveResult.EMPTY_ARRAY; final String className = classNameElement.getText(); - final ClassResolverProcessor processor = new ClassResolverProcessor(className, this, getContainingFile()); + final ClassResolverProcessor processor = new ClassResolverProcessor(className, this, containingFile); PsiScopesUtil.resolveAndWalk(processor, this, null); return processor.getResult(); } case PACKAGE_NAME_KIND: { - String packageName = getTextSkipWhiteSpaceAndComments(); + String packageName = getNormalizedText(); Project project = getManager().getProject(); PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(packageName); if (aPackage == null || !aPackage.isValid()) { @@ -457,16 +456,16 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme case CLASS_FQ_OR_PACKAGE_NAME_KIND: case CLASS_OR_PACKAGE_NAME_KIND: { int classKind = kind == CLASS_OR_PACKAGE_NAME_KIND ? CLASS_NAME_KIND : CLASS_FQ_NAME_KIND; - JavaResolveResult[] result = resolve(classKind); + JavaResolveResult[] result = resolve(classKind,containingFile); if (result.length == 1 && !result[0].isAccessible()) { - JavaResolveResult[] packageResult = resolve(PACKAGE_NAME_KIND); + JavaResolveResult[] packageResult = resolve(PACKAGE_NAME_KIND,containingFile); if (packageResult.length != 0) { result = packageResult; } } else if (result.length == 0) { - result = resolve(PACKAGE_NAME_KIND); + result = resolve(PACKAGE_NAME_KIND,containingFile); } return result; @@ -712,10 +711,10 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme return name != null && referenceNameElement.getText().equals(name) && element.getManager().areElementsEquivalent(resolve(), element); } - private String getTextSkipWhiteSpaceAndComments() { - String whiteSpaceAndComments = myCachedTextSkipWhiteSpaceAndComments; + private String getNormalizedText() { + String whiteSpaceAndComments = myCachedNormalizedText; if (whiteSpaceAndComments == null) { - myCachedTextSkipWhiteSpaceAndComments = whiteSpaceAndComments = SourceUtil.getReferenceText(this); + myCachedNormalizedText = whiteSpaceAndComments = SourceUtil.getReferenceText(this); } return whiteSpaceAndComments; } @@ -724,7 +723,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme public String getClassNameText() { String cachedQName = myCachedQName; if (cachedQName == null) { - myCachedQName = cachedQName = PsiNameHelper.getQualifiedClassName(getTextSkipWhiteSpaceAndComments(), false); + myCachedQName = cachedQName = PsiNameHelper.getQualifiedClassName(getNormalizedText(), false); } return cachedQName; } @@ -753,7 +752,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme public void clearCaches() { super.clearCaches(); myCachedQName = null; - myCachedTextSkipWhiteSpaceAndComments = null; + myCachedNormalizedText = null; } @Override @@ -797,7 +796,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme } @Override - public void processVariants(final PsiScopeProcessor processor) { + public void processVariants(@NotNull final PsiScopeProcessor processor) { final OrFilter filter = new OrFilter(); if (isInCode() && !(getParent() instanceof PsiImportStatement)) { filter.addFilter(new AndFilter(ElementClassFilter.METHOD, new NotFilter(new ConstructorFilter()))); @@ -805,11 +804,11 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme } switch (getKind()) { case CLASS_OR_PACKAGE_NAME_KIND: - addClassFilter(filter); + filter.addFilter(ElementClassFilter.CLASS); filter.addFilter(ElementClassFilter.PACKAGE_FILTER); break; case CLASS_NAME_KIND: - addClassFilter(filter); + filter.addFilter(ElementClassFilter.CLASS); if (isQualified()) { filter.addFilter(ElementClassFilter.PACKAGE_FILTER); } @@ -867,15 +866,6 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme return false; } - private void addClassFilter(final OrFilter filter) { - if (getParent() instanceof PsiAnnotation) { - filter.addFilter(new AnnotationTypeFilter()); - } - else { - filter.addFilter(ElementClassFilter.CLASS); - } - } - @Override public PsiElement getReferenceNameElement() { return SourceTreeToPsiMap.treeElementToPsi(getReferenceNameNode()); @@ -918,7 +908,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme case PACKAGE_NAME_KIND: case CLASS_FQ_NAME_KIND: case CLASS_FQ_OR_PACKAGE_NAME_KIND: - return getTextSkipWhiteSpaceAndComments(); // there cannot be any <...> + return getNormalizedText(); // there cannot be any <...> default: LOG.assertTrue(false); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java index fccee00e96e2..ebc3168758e7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java @@ -226,7 +226,7 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo } @Override - public void processVariants(PsiScopeProcessor processor) { + public void processVariants(@NotNull PsiScopeProcessor processor) { for (final PsiElement element : getVariants()) { if (!processor.execute(element, ResolveState.initial())) { return; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocParamRef.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocParamRef.java index 36f7c61047f5..21e8c6cbbc38 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocParamRef.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocParamRef.java @@ -157,7 +157,7 @@ public class PsiDocParamRef extends CompositePsiElement implements PsiDocTagValu } @Override - public void processVariants(PsiScopeProcessor processor) { + public void processVariants(@NotNull PsiScopeProcessor processor) { for (final PsiElement element : getVariants()) { if (!processor.execute(element, ResolveState.initial())) { return; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/GraphInferencePolicy.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/GraphInferencePolicy.java index 0b895d74dc16..1b2ea842e46b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/GraphInferencePolicy.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/GraphInferencePolicy.java @@ -59,7 +59,7 @@ public class GraphInferencePolicy extends ProcessCandidateParameterTypeInference @NotNull @Override - protected JavaResolveResult[] getResults(PsiCallExpression contextCall, final int exprIdx) + protected JavaResolveResult[] getResults(@NotNull PsiCallExpression contextCall, final int exprIdx) throws MethodProcessorSetupFailedException { Map<JavaResolveResult, PsiSubstitutor> map = ourResults.get().get(contextCall); if (map != null) { @@ -67,7 +67,8 @@ public class GraphInferencePolicy extends ProcessCandidateParameterTypeInference return results.toArray(new JavaResolveResult[results.size()]); } - final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(contextCall) { + PsiFile containingFile = contextCall.getContainingFile(); + final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(contextCall, containingFile) { @Override protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) { if (argumentList != null) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java index 981739b7d815..6bb94b3d7a5c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java @@ -19,6 +19,7 @@ */ package com.intellij.psi.impl.source.resolve; +import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.JavaVersionService; import com.intellij.psi.*; @@ -129,7 +130,7 @@ public class JavaResolveUtil { PsiClass topAccessClass = getTopLevelClass(accessObjectClass, memberClass); if (!manager.areElementsEquivalent(topMemberClass, topAccessClass)) return false; if (accessObjectClass instanceof PsiAnonymousClass && accessObjectClass.isInheritor(memberClass, true)) { - if (place instanceof PsiMethodCallExpression && + if (place instanceof PsiMethodCallExpression && ((PsiMethodCallExpression)place).getMethodExpression().getQualifierExpression() instanceof PsiThisExpression) { return false; } @@ -148,7 +149,7 @@ public class JavaResolveUtil { } if (!facade.arePackagesTheSame(member, place)) return false; - if (modifierList.hasModifierProperty(PsiModifier.STATIC)) return true; + //if (modifierList.hasModifierProperty(PsiModifier.STATIC)) return true; // maybe inheritance lead through package local class in other package ? final PsiClass placeClass = getContextClass(place); if (memberClass == null || placeClass == null) return true; @@ -192,13 +193,13 @@ public class JavaResolveUtil { if (placeParent instanceof PsiClass && !(placeParent instanceof PsiAnonymousClass)) { final boolean isTypeParameter = placeParent instanceof PsiTypeParameter; if (isTypeParameter && isAtLeast17 == null) { - isAtLeast17 = JavaVersionService.getInstance().isAtLeast(place, JavaSdkVersion.JDK_1_7); + isAtLeast17 = JavaVersionService.getInstance().isAtLeast(placeParent, JavaSdkVersion.JDK_1_7); } - if (!isTypeParameter || (isAtLeast17 != null && isAtLeast17)) { + if (!isTypeParameter || isAtLeast17) { PsiClass aClass = (PsiClass)placeParent; - + if (memberClass != null && aClass.isInheritor(memberClass, true)) return aClass; - + lastClass = aClass; } } @@ -236,4 +237,20 @@ public class JavaResolveUtil { } } } + + @NotNull + public static <T extends PsiPolyVariantReference> JavaResolveResult[] resolveWithContainingFile(@NotNull T ref, + @NotNull ResolveCache.PolyVariantResolver<T> resolver, + boolean needToPreventRecursion, + boolean incompleteCode, + @NotNull PsiFile containingFile) { + boolean valid = containingFile.isValid(); + if (!valid) { + return JavaResolveResult.EMPTY_ARRAY; + } + Project project = containingFile.getProject(); + ResolveResult[] results = ResolveCache.getInstance(project).resolveWithCaching(ref, resolver, needToPreventRecursion, incompleteCode, + containingFile); + return results.length == 0 ? JavaResolveResult.EMPTY_ARRAY : (JavaResolveResult[])results; + } }
\ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ProcessCandidateParameterTypeInferencePolicy.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ProcessCandidateParameterTypeInferencePolicy.java index 3509fd90a93c..1b33cfb196b6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ProcessCandidateParameterTypeInferencePolicy.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ProcessCandidateParameterTypeInferencePolicy.java @@ -23,7 +23,7 @@ import com.intellij.psi.scope.MethodProcessorSetupFailedException; import com.intellij.psi.scope.processor.MethodCandidatesProcessor; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.ArrayUtil; +import com.intellij.util.ArrayUtilRt; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -35,19 +35,19 @@ import java.util.List; */ public class ProcessCandidateParameterTypeInferencePolicy extends DefaultParameterTypeInferencePolicy { public static final ProcessCandidateParameterTypeInferencePolicy INSTANCE = new ProcessCandidateParameterTypeInferencePolicy(); - - + + @Override public Pair<PsiType, ConstraintType> inferTypeConstraintFromCallContext(PsiExpression innerMethodCall, PsiExpressionList expressionList, - PsiCallExpression contextCall, + @NotNull PsiCallExpression contextCall, PsiTypeParameter typeParameter) { PsiExpression[] expressions = expressionList.getExpressions(); PsiElement parent = innerMethodCall; while (parent.getParent() instanceof PsiParenthesizedExpression) { parent = parent.getParent(); } - int i = ArrayUtil.find(expressions, parent); + int i = ArrayUtilRt.find(expressions, parent); if (i < 0) return null; PsiMethod owner = (PsiMethod)typeParameter.getOwner(); if (owner == null) return null; @@ -108,8 +108,9 @@ public class ProcessCandidateParameterTypeInferencePolicy extends DefaultParamet return substitutor.substitute(finalParameter.getType()); } }); + PsiResolveHelperImpl resolveHelper = (PsiResolveHelperImpl)JavaPsiFacade.getInstance(method.getProject()).getResolveHelper(); final Pair<PsiType, ConstraintType> constraint = - PsiResolveHelperImpl.getSubstitutionForTypeParameterConstraint(typeParameter, innerReturnType, type, false, + resolveHelper.getSubstitutionForTypeParameterConstraint(typeParameter, innerReturnType, type, false, PsiUtil.getLanguageLevel(finalParameter)); if (constraint != null) return constraint; } @@ -118,8 +119,9 @@ public class ProcessCandidateParameterTypeInferencePolicy extends DefaultParamet } @NotNull - protected JavaResolveResult[] getResults(PsiCallExpression contextCall, final int exprIdx) throws MethodProcessorSetupFailedException { - final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(contextCall); + protected JavaResolveResult[] getResults(@NotNull PsiCallExpression contextCall, final int exprIdx) throws MethodProcessorSetupFailedException { + PsiFile containingFile = contextCall.getContainingFile(); + final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(contextCall, containingFile); //can't call resolve() since it obtains full substitution, that may result in infinite recursion PsiScopesUtil.setupAndRunProcessor(processor, contextCall, false); return processor.getResult(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java index 6dd543993fb6..d24bfd9ff654 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java @@ -62,7 +62,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { @Override @NotNull - public JavaResolveResult[] multiResolveConstructor(PsiClassType type, PsiExpressionList argumentList, PsiElement place) { + public JavaResolveResult[] multiResolveConstructor(@NotNull PsiClassType type, @NotNull PsiExpressionList argumentList, @NotNull PsiElement place) { PsiClassType.ClassResolveResult classResolveResult = type.resolveGenerics(); PsiClass aClass = classResolveResult.getElement(); if (aClass == null) { @@ -72,13 +72,13 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { PsiSubstitutor substitutor = classResolveResult.getSubstitutor(); if (argumentList.getParent() instanceof PsiAnonymousClass) { final PsiAnonymousClass anonymous = (PsiAnonymousClass)argumentList.getParent(); - processor = new MethodResolverProcessor(anonymous, argumentList, place); + processor = new MethodResolverProcessor(anonymous, argumentList, place, place.getContainingFile()); aClass = anonymous.getBaseClassType().resolve(); if (aClass == null) return JavaResolveResult.EMPTY_ARRAY; substitutor = substitutor.putAll(TypeConversionUtil.getSuperClassSubstitutor(aClass, anonymous, substitutor)); } else { - processor = new MethodResolverProcessor(aClass, argumentList, place); + processor = new MethodResolverProcessor(aClass, argumentList, place, place.getContainingFile()); } ResolveState state = ResolveState.initial().put(PsiSubstitutor.KEY, substitutor); @@ -143,8 +143,9 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { @Override @NotNull - public CandidateInfo[] getReferencedMethodCandidates(PsiCallExpression expr, boolean dummyImplicitConstructor) { - final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(expr); + public CandidateInfo[] getReferencedMethodCandidates(@NotNull PsiCallExpression expr, boolean dummyImplicitConstructor) { + PsiFile containingFile = expr.getContainingFile(); + final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(expr, containingFile); try { PsiScopesUtil.setupAndRunProcessor(processor, expr, dummyImplicitConstructor); } @@ -154,12 +155,12 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return processor.getCandidates(); } - private static Pair<PsiType, ConstraintType> inferTypeForMethodTypeParameterInner(@NotNull PsiTypeParameter typeParameter, + private Pair<PsiType, ConstraintType> inferTypeForMethodTypeParameterInner(@NotNull PsiTypeParameter typeParameter, @NotNull PsiParameter[] parameters, @NotNull PsiExpression[] arguments, @NotNull PsiSubstitutor partialSubstitutor, final PsiElement parent, - final ParameterTypeInferencePolicy policy) { + @NotNull ParameterTypeInferencePolicy policy) { PsiType[] paramTypes = new PsiType[arguments.length]; PsiType[] argTypes = new PsiType[arguments.length]; if (parameters.length > 0) { @@ -191,12 +192,12 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return inferTypeForMethodTypeParameterInner(typeParameter, paramTypes, argTypes, partialSubstitutor, parent, policy); } - private static Pair<PsiType, ConstraintType> inferTypeForMethodTypeParameterInner(@NotNull PsiTypeParameter typeParameter, + private Pair<PsiType, ConstraintType> inferTypeForMethodTypeParameterInner(@NotNull PsiTypeParameter typeParameter, @NotNull PsiType[] paramTypes, @NotNull PsiType[] argTypes, @NotNull PsiSubstitutor partialSubstitutor, @Nullable PsiElement parent, - final ParameterTypeInferencePolicy policy) { + @NotNull ParameterTypeInferencePolicy policy) { PsiWildcardType wildcardToCapture = null; Pair<PsiType, ConstraintType> rawInference = null; PsiType lowerBound = PsiType.NULL; @@ -233,7 +234,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { lambdaRaw = true; } if (currentSubstitution == null && lambdaRaw) { - return new Pair<PsiType, ConstraintType>(PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope()), ConstraintType.EQUALS); + return new Pair<PsiType, ConstraintType>(PsiType.getJavaLangObject(myManager, typeParameter.getResolveScope()), ConstraintType.EQUALS); } } else if (argumentType instanceof PsiMethodReferenceType) { final PsiMethodReferenceExpression referenceExpression = ((PsiMethodReferenceType)argumentType).getExpression(); @@ -265,7 +266,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { lowerBound = type; } else if (!lowerBound.equals(type)) { - lowerBound = GenericsUtil.getLeastUpperBound(lowerBound, type, typeParameter.getManager()); + lowerBound = GenericsUtil.getLeastUpperBound(lowerBound, type, myManager); if (lowerBound == null) return getFailedInferenceConstraint(typeParameter); } break; @@ -283,7 +284,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { if (wildcardToCapture.isSuper()) { return new Pair<PsiType, ConstraintType>(wildcardToCapture, ConstraintType.SUPERTYPE); } - lowerBound = GenericsUtil.getLeastUpperBound(lowerBound, wildcardToCapture, typeParameter.getManager()); + lowerBound = GenericsUtil.getLeastUpperBound(lowerBound, wildcardToCapture, myManager); } else { if (upperBound != PsiType.NULL && !upperBound.isAssignableFrom(wildcardToCapture)) return getFailedInferenceConstraint(typeParameter); @@ -341,7 +342,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { @NotNull PsiExpression[] arguments, @NotNull PsiSubstitutor partialSubstitutor, PsiElement parent, - final ParameterTypeInferencePolicy policy) { + @NotNull final ParameterTypeInferencePolicy policy) { final Pair<PsiType, ConstraintType> constraint = inferTypeForMethodTypeParameterInner(typeParameter, parameters, arguments, partialSubstitutor, parent, policy); @@ -349,21 +350,18 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return constraint.getFirst(); } - @Override @NotNull + @Override public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, @NotNull PsiParameter[] parameters, @NotNull PsiExpression[] arguments, @NotNull PsiSubstitutor partialSubstitutor, @NotNull PsiElement parent, - ParameterTypeInferencePolicy policy) { + @NotNull ParameterTypeInferencePolicy policy, + @NotNull LanguageLevel languageLevel) { PsiType[] substitutions = new PsiType[typeParameters.length]; @SuppressWarnings("unchecked") Pair<PsiType, ConstraintType>[] constraints = new Pair[typeParameters.length]; - PsiFile file = parent.getContainingFile(); - LOG.assertTrue(file != null, parent); - final PsiManager manager = file.getManager(); - final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(file); for (int i = 0; i < typeParameters.length; i++) { if (substitutions[i] != null) continue; final Pair<PsiType, ConstraintType> constraint = @@ -409,7 +407,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { substitutionFromBounds = currentSubstitution; } else { - substitutionFromBounds = GenericsUtil.getLeastUpperBound(substitutionFromBounds, currentSubstitution, manager); + substitutionFromBounds = GenericsUtil.getLeastUpperBound(substitutionFromBounds, currentSubstitution, myManager); } } } @@ -453,7 +451,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } if (substitution == null) { - PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); return factory.createRawSubstitutor(partialSubstitutor, typeParameters); } if (substitution != PsiType.NULL) { @@ -470,6 +468,17 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { @Override @NotNull public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, + @NotNull PsiParameter[] parameters, + @NotNull PsiExpression[] arguments, + @NotNull PsiSubstitutor partialSubstitutor, + @NotNull PsiElement parent, + @NotNull ParameterTypeInferencePolicy policy) { + return inferTypeArguments(typeParameters, parameters, arguments, partialSubstitutor, parent, policy, PsiUtil.getLanguageLevel(parent)); + } + + @Override + @NotNull + public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, @NotNull PsiType[] leftTypes, @NotNull PsiType[] rightTypes, @NotNull LanguageLevel languageLevel) { @@ -495,7 +504,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { substitution = current; } else { - substitution = GenericsUtil.getLeastUpperBound(substitution, current, typeParameter.getManager()); + substitution = GenericsUtil.getLeastUpperBound(substitution, current, myManager); } } else { @@ -503,7 +512,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { lowerBound = current; } else { - lowerBound = GenericsUtil.getLeastUpperBound(lowerBound, current, typeParameter.getManager()); + lowerBound = GenericsUtil.getLeastUpperBound(lowerBound, current, myManager); } } } @@ -524,14 +533,20 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { private static Pair<PsiType, ConstraintType> processArgType(PsiType arg, final ConstraintType constraintType, final boolean captureWildcard) { if (arg instanceof PsiWildcardType && !captureWildcard) return FAILED_INFERENCE; - if (arg != PsiType.NULL) return new Pair<PsiType, ConstraintType>(arg, constraintType); + if (arg != PsiType.NULL) { + if (arg instanceof PsiWildcardType) { + final PsiType bound = ((PsiWildcardType)arg).getBound(); + if (bound instanceof PsiClassType && ((PsiClassType)bound).isRaw()) return Pair.create(null, constraintType); + } + return new Pair<PsiType, ConstraintType>(arg, constraintType); + } return null; } - private static Pair<PsiType, ConstraintType> inferMethodTypeParameterFromParent(final PsiTypeParameter typeParameter, - PsiSubstitutor substitutor, - PsiElement parent, - final ParameterTypeInferencePolicy policy) { + private Pair<PsiType, ConstraintType> inferMethodTypeParameterFromParent(@NotNull PsiTypeParameter typeParameter, + @NotNull PsiSubstitutor substitutor, + @NotNull PsiElement parent, + @NotNull ParameterTypeInferencePolicy policy) { PsiTypeParameterListOwner owner = typeParameter.getOwner(); Pair<PsiType, ConstraintType> substitution = null; if (owner instanceof PsiMethod && parent instanceof PsiCallExpression) { @@ -553,18 +568,18 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } @Nullable - public static Pair<PsiType, ConstraintType> getSubstitutionForTypeParameterConstraint(PsiTypeParameter typeParam, - PsiType param, - PsiType arg, - boolean isContraVariantPosition, - final LanguageLevel languageLevel) { + public Pair<PsiType, ConstraintType> getSubstitutionForTypeParameterConstraint(PsiTypeParameter typeParam, + PsiType param, + PsiType arg, + boolean isContraVariantPosition, + final LanguageLevel languageLevel) { if (param instanceof PsiArrayType && arg instanceof PsiArrayType) { return getSubstitutionForTypeParameterConstraint(typeParam, ((PsiArrayType)param).getComponentType(), ((PsiArrayType)arg).getComponentType(), isContraVariantPosition, languageLevel); } if (!(param instanceof PsiClassType)) return null; - PsiManager manager = typeParam.getManager(); + PsiManager manager = myManager; if (arg instanceof PsiPrimitiveType) { if (!JavaVersionService.getInstance().isAtLeast(typeParam, JavaSdkVersion.JDK_1_7) && !isContraVariantPosition) return null; arg = ((PsiPrimitiveType)arg).getBoxedType(typeParam); @@ -612,7 +627,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } @Nullable - private static Pair<PsiType, ConstraintType> inferSubstitutionFromLambda(PsiTypeParameter typeParam, + private Pair<PsiType, ConstraintType> inferSubstitutionFromLambda(PsiTypeParameter typeParam, PsiLambdaExpressionType arg, PsiType lowerBound, PsiSubstitutor partialSubstitutor) { @@ -642,7 +657,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } @Nullable - private static Pair<PsiType, ConstraintType> inferConstraintFromFunctionalInterfaceMethod(final PsiTypeParameter typeParam, + private Pair<PsiType, ConstraintType> inferConstraintFromFunctionalInterfaceMethod(final PsiTypeParameter typeParam, final PsiMethodReferenceExpression methodReferenceExpression, final PsiType functionalInterfaceType, final PsiSubstitutor partialSubstitutor, @@ -722,7 +737,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } @Nullable - private static Pair<PsiType, ConstraintType> inferConstraintFromFunctionalInterfaceMethod(PsiTypeParameter typeParam, + private Pair<PsiType, ConstraintType> inferConstraintFromFunctionalInterfaceMethod(PsiTypeParameter typeParam, final PsiLambdaExpression lambdaExpression, final PsiType functionalInterfaceType, PsiType lowerBound) { @@ -779,7 +794,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { if (returnExprConstraint != null) { if (returnExprConstraint == FAILED_INFERENCE) return returnExprConstraint; if (constraint != null) { - final PsiType leastUpperBound = GenericsUtil.getLeastUpperBound(constraint.getFirst(), returnExprConstraint.getFirst(), typeParam.getManager()); + final PsiType leastUpperBound = GenericsUtil.getLeastUpperBound(constraint.getFirst(), returnExprConstraint.getFirst(), myManager); constraint = new Pair<PsiType, ConstraintType>(leastUpperBound, ConstraintType.SUPERTYPE); } else { constraint = returnExprConstraint; @@ -805,7 +820,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } @Nullable - private static Pair<PsiType, ConstraintType> inferConstraintFromLambdaFormalParams(PsiTypeParameter typeParam, + private Pair<PsiType, ConstraintType> inferConstraintFromLambdaFormalParams(PsiTypeParameter typeParam, PsiSubstitutor subst, PsiMethod method, PsiLambdaExpression lambdaExpression) { final PsiParameter[] parameters = lambdaExpression.getParameterList().getParameters(); @@ -843,12 +858,12 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { private static final Pair<PsiType, ConstraintType> FAILED_INFERENCE = new Pair<PsiType, ConstraintType>(PsiType.NULL, ConstraintType.EQUALS); @Nullable - private static Pair<PsiType, ConstraintType> getSubstitutionForTypeParameterInner(PsiType param, + private Pair<PsiType, ConstraintType> getSubstitutionForTypeParameterInner(PsiType param, PsiType arg, PsiType patternType, final ConstraintType constraintType, final int depth) { - if (arg instanceof PsiCapturedWildcardType) arg = ((PsiCapturedWildcardType)arg).getWildcard(); //reopen + if (arg instanceof PsiCapturedWildcardType && (depth < 2 || constraintType != ConstraintType.EQUALS)) arg = ((PsiCapturedWildcardType)arg).getWildcard(); //reopen if (patternType.equals(param)) { return processArgType(arg, constraintType, depth < 2); @@ -905,7 +920,10 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { if (substituted != null) { Pair<PsiType, ConstraintType> res = getSubstitutionForTypeParameterInner( superSubstitutor.substitute(typeParameter), substituted, patternType, ConstraintType.EQUALS, depth + 1); - if (res != null) return res; + if (res != null) { + if (res == FAILED_INFERENCE) continue; + return res; + } } } } @@ -931,6 +949,8 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return inferBySubtypingConstraint(patternType, constraintType, depth, paramClass, argClass); } + PsiType lowerBound = PsiType.NULL; + PsiType upperBound = PsiType.NULL; Pair<PsiType,ConstraintType> wildcardCaptured = null; for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(paramClass)) { PsiType paramType = paramResult.getSubstitutor().substitute(typeParameter); @@ -952,13 +972,35 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { Pair<PsiType,ConstraintType> res = getSubstitutionForTypeParameterInner(paramType, argType, patternType, ConstraintType.EQUALS, depth + 1); if (res != null) { - PsiType type = res.getFirst(); - if (!(type instanceof PsiWildcardType)) return res; - if (wildcardCaptured != null) return FAILED_INFERENCE; - wildcardCaptured = res; + final PsiType type = res.getFirst(); + switch (res.getSecond()) { + case EQUALS: + if (!(type instanceof PsiWildcardType)) return res; + if (wildcardCaptured != null) return FAILED_INFERENCE; + wildcardCaptured = res; + break; + case SUPERTYPE: + wildcardCaptured = res; + if (PsiType.NULL.equals(lowerBound)) { + lowerBound = type; + } + else if (!lowerBound.equals(type)) { + lowerBound = GenericsUtil.getLeastUpperBound(lowerBound, type, myManager); + if (lowerBound == null) return FAILED_INFERENCE; + } + break; + case SUBTYPE: + wildcardCaptured = res; + if (PsiType.NULL.equals(upperBound) || TypeConversionUtil.isAssignable(upperBound, type)) { + upperBound = type; + } + } } } + if (lowerBound != PsiType.NULL) return new Pair<PsiType, ConstraintType>(lowerBound, ConstraintType.SUPERTYPE); + if (upperBound != PsiType.NULL) return new Pair<PsiType, ConstraintType>(upperBound, ConstraintType.SUBTYPE); + return wildcardCaptured; } @@ -966,7 +1008,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } private static final Key<Boolean> inferSubtyping = Key.create("infer.subtyping.marker"); - private static Pair<PsiType, ConstraintType> inferBySubtypingConstraint(PsiType patternType, + private Pair<PsiType, ConstraintType> inferBySubtypingConstraint(PsiType patternType, ConstraintType constraintType, int depth, PsiClass paramClass, @@ -1010,11 +1052,11 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return null; } - private static Pair<PsiType, ConstraintType> inferMethodTypeParameterFromParent(final PsiElement parent, - PsiExpression methodCall, - final PsiTypeParameter typeParameter, - PsiSubstitutor substitutor, - ParameterTypeInferencePolicy policy) { + private Pair<PsiType, ConstraintType> inferMethodTypeParameterFromParent(@NotNull final PsiElement parent, + @NotNull PsiExpression methodCall, + @NotNull PsiTypeParameter typeParameter, + @NotNull PsiSubstitutor substitutor, + @NotNull ParameterTypeInferencePolicy policy) { Pair<PsiType, ConstraintType> constraint = null; PsiType expectedType = PsiTypesUtil.getExpectedTypeByParent(methodCall); @@ -1065,7 +1107,6 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } } - final PsiManager manager = typeParameter.getManager(); final GlobalSearchScope scope = parent.getResolveScope(); PsiType returnType = null; if (constraint == null) { @@ -1093,7 +1134,6 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } } - final Pair<PsiType, ConstraintType> result; if (constraint == null) { if (methodCall instanceof PsiCallExpression) { final PsiExpressionList argumentList = ((PsiCallExpression)methodCall).getArgumentList(); @@ -1129,14 +1169,14 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { if (superType instanceof PsiClassType && ((PsiClassType)superType).isRaw()) { superType = TypeConversionUtil.erasure(superType); } - if (superType == null) superType = PsiType.getJavaLangObject(manager, scope); + if (superType == null) superType = PsiType.getJavaLangObject(myManager, scope); if (superType == null) return null; - return policy.getInferredTypeWithNoConstraint(manager, superType); + return policy.getInferredTypeWithNoConstraint(myManager, superType); } return null; } PsiType guess = constraint.getFirst(); - guess = policy.adjustInferredType(manager, guess, constraint.getSecond()); + guess = policy.adjustInferredType(myManager, guess, constraint.getSecond()); //The following code is the result of deep thought, do not shit it out before discussing with [ven] if (returnType instanceof PsiClassType && typeParameter.equals(((PsiClassType)returnType).resolve())) { @@ -1156,8 +1196,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } } - result = new Pair<PsiType, ConstraintType>(guess, constraint.getSecond()); - return result; + return new Pair<PsiType, ConstraintType>(guess, constraint.getSecond()); } private static boolean checkSameExpression(PsiExpression templateExpr, final PsiExpression expression) { @@ -1213,11 +1252,11 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return null; } - private static Pair<PsiType, ConstraintType> inferFromConditionalExpression(PsiElement parent, - PsiExpression methodCall, - PsiTypeParameter typeParameter, - PsiSubstitutor substitutor, - ParameterTypeInferencePolicy policy) { + private Pair<PsiType, ConstraintType> inferFromConditionalExpression(@NotNull PsiElement parent, + @NotNull PsiExpression methodCall, + @NotNull PsiTypeParameter typeParameter, + @NotNull PsiSubstitutor substitutor, + @NotNull ParameterTypeInferencePolicy policy) { Pair<PsiType, ConstraintType> pair = inferMethodTypeParameterFromParent(PsiUtil.skipParenthesizedExprUp(parent.getParent()), (PsiExpression)parent, typeParameter, substitutor, policy); if (pair == null) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ResolveVariableUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ResolveVariableUtil.java index 09199569aaa0..02e025c98431 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ResolveVariableUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ResolveVariableUtil.java @@ -1,4 +1,3 @@ - /* * Copyright 2000-2009 JetBrains s.r.o. * @@ -20,19 +19,19 @@ import com.intellij.psi.PsiJavaCodeReferenceElement; import com.intellij.psi.PsiVariable; import com.intellij.psi.JavaResolveResult; import com.intellij.psi.scope.util.PsiScopesUtil; +import org.jetbrains.annotations.NotNull; public class ResolveVariableUtil { - public static PsiVariable resolveVariable( - PsiJavaCodeReferenceElement ref, - boolean[] problemWithAccess, - boolean[] problemWithStatic - ) { + public static PsiVariable resolveVariable(@NotNull PsiJavaCodeReferenceElement ref, + boolean[] problemWithAccess, + boolean[] problemWithStatic + ) { /* long time1 = System.currentTimeMillis(); */ - final VariableResolverProcessor processor = new VariableResolverProcessor(ref); + final VariableResolverProcessor processor = new VariableResolverProcessor(ref, ref.getContainingFile()); PsiScopesUtil.resolveAndWalk(processor, ref, null); /* @@ -41,13 +40,13 @@ public class ResolveVariableUtil { Statistics.resolveVariableCount++; */ final JavaResolveResult[] result = processor.getResult(); - if(result.length != 1) return null; - final PsiVariable refVar = (PsiVariable) result[0].getElement(); + if (result.length != 1) return null; + final PsiVariable refVar = (PsiVariable)result[0].getElement(); - if (problemWithAccess != null){ + if (problemWithAccess != null) { problemWithAccess[0] = !result[0].isAccessible(); } - if (problemWithStatic != null){ + if (problemWithStatic != null) { problemWithStatic[0] = !result[0].isStaticsScopeCorrect(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/VariableResolverProcessor.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/VariableResolverProcessor.java index c544598b25c5..f72ee4f54427 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/VariableResolverProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/VariableResolverProcessor.java @@ -41,8 +41,8 @@ public class VariableResolverProcessor extends ConflictFilterProcessor implement private final PsiClass myAccessClass; private PsiElement myCurrentFileContext = null; - public VariableResolverProcessor(PsiJavaCodeReferenceElement place) { - super(place.getText(), ourFilter, new PsiConflictResolver[]{new JavaVariableConflictResolver()}, new SmartList<CandidateInfo>(), place); + public VariableResolverProcessor(@NotNull PsiJavaCodeReferenceElement place, PsiFile placeFile) { + super(place.getText(), ourFilter, new PsiConflictResolver[]{new JavaVariableConflictResolver()}, new SmartList<CandidateInfo>(), place, placeFile); PsiElement referenceName = place.getReferenceNameElement(); if (referenceName instanceof PsiIdentifier){ diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/SourceUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/SourceUtil.java index 83261a3bdcae..5e0865e0ec45 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/SourceUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/SourceUtil.java @@ -46,7 +46,15 @@ public class SourceUtil { @Override public void visitLeaf(LeafElement leaf) { if (!REF_FILTER.contains(leaf.getElementType())) { - buffer.append(leaf.getText()); + String leafText = leaf.getText(); + if (buffer.length() > 0 && leafText.length() > 0 && Character.isJavaIdentifierPart(leafText.charAt(0))) { + char lastInBuffer = buffer.charAt(buffer.length() - 1); + if (lastInBuffer == '?' || Character.isJavaIdentifierPart(lastInBuffer)) { + buffer.append(" "); + } + } + + buffer.append(leafText); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java index 74d1350b3dc7..f6c790a362c9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java @@ -382,7 +382,8 @@ public class PsiLiteralExpressionImpl @Override @NotNull public PsiReference[] getReferences() { - return PsiReferenceService.getService().getContributedReferences(this); + PsiReference[] references = PsiReferenceService.getService().getContributedReferences(this); + return references; } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java index 699e33476b48..1dd74f133dcf 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java @@ -151,8 +151,9 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements PsiReferenceExpression methodExpression = call.getMethodExpression(); PsiType theOnly = null; final JavaResolveResult[] results = methodExpression.multiResolve(false); + LanguageLevel languageLevel = PsiUtil.getLanguageLevel(call); for (int i = 0; i < results.length; i++) { - final PsiType type = getResultType(call, methodExpression, results[i]); + final PsiType type = getResultType(call, methodExpression, results[i], languageLevel); if (type == null) { return null; } @@ -169,11 +170,13 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements } @Nullable - private static PsiType getResultType(PsiExpression call, PsiReferenceExpression methodExpression, JavaResolveResult result) { + private static PsiType getResultType(PsiExpression call, + PsiReferenceExpression methodExpression, + JavaResolveResult result, + @NotNull final LanguageLevel languageLevel) { final PsiMethod method = (PsiMethod)result.getElement(); if (method == null) return null; - final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(call); boolean is15OrHigher = languageLevel.compareTo(LanguageLevel.JDK_1_5) >= 0; final PsiType getClassReturnType = PsiTypesUtil.patchMethodGetClassReturnType(call, methodExpression, method, new Condition<IElementType>() { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index 109d32dccecf..2cd3f29c37bc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -45,7 +45,6 @@ import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; @@ -57,7 +56,7 @@ import java.util.List; import java.util.Map; public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase implements PsiMethodReferenceExpression { - private static Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiMethodReferenceExpressionImpl"); + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiMethodReferenceExpressionImpl"); public PsiMethodReferenceExpressionImpl() { super(JavaElementType.METHOD_REF_EXPRESSION); @@ -93,7 +92,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase } @Override - public void processVariants(final PsiScopeProcessor processor) { + public void processVariants(@NotNull final PsiScopeProcessor processor) { final FilterScopeProcessor proc = new FilterScopeProcessor(ElementClassFilter.METHOD, processor); PsiScopesUtil.resolveAndWalk(proc, this, null, true); } @@ -147,7 +146,6 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase LOG.error("invalid!"); return JavaResolveResult.EMPTY_ARRAY; } - Project project = manager.getProject(); final MethodReferenceResolver resolver = new MethodReferenceResolver(); final Map<PsiMethodReferenceExpression, PsiType> map = PsiMethodReferenceUtil.ourRefs.get(); if (map != null && map.containsKey(this)) { @@ -284,15 +282,17 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); final MethodSignature signature = interfaceMethod != null ? interfaceMethod.getSignature(LambdaUtil.getSubstitutor(interfaceMethod, resolveResult)) : null; final PsiType interfaceMethodReturnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType); - final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(PsiMethodReferenceExpressionImpl.this); + PsiFile containingFile = getContainingFile(); + final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(containingFile); if (isConstructor && interfaceMethod != null) { final PsiTypeParameter[] typeParameters = containingClass.getTypeParameters(); final boolean isRawSubst = PsiUtil.isRawSubstitutor(containingClass, substitutor); - final PsiClassType returnType = JavaPsiFacade.getElementFactory(getProject()).createType(containingClass, + Project project = containingClass.getProject(); + final PsiClassType returnType = JavaPsiFacade.getElementFactory(project).createType(containingClass, isRawSubst ? PsiSubstitutor.EMPTY : substitutor); substitutor = LambdaUtil.inferFromReturnType(typeParameters, returnType, interfaceMethodReturnType, substitutor, languageLevel, - PsiMethodReferenceExpressionImpl.this.getProject()); + project); if (containingClass.getConstructors().length == 0) { ClassCandidateInfo candidateInfo = null; @@ -309,13 +309,13 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final PsiConflictResolver[] resolvers; if (signature != null) { final PsiType[] parameterTypes = signature.getParameterTypes(); - resolvers = new PsiConflictResolver[]{conflictResolver, new MethodRefsSpecificResolver(parameterTypes)}; + resolvers = new PsiConflictResolver[]{conflictResolver, new MethodRefsSpecificResolver(parameterTypes, languageLevel)}; } else { resolvers = new PsiConflictResolver[]{conflictResolver}; } final MethodCandidatesProcessor processor = - new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this, resolvers, new SmartList<CandidateInfo>()) { + new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this, containingFile, resolvers, new SmartList<CandidateInfo>()) { @Override protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, final PsiSubstitutor substitutor, @@ -326,7 +326,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase argumentList != null ? argumentList.getExpressionTypes() : null, getTypeArguments(), getLanguageLevel()) { @Override - public PsiSubstitutor inferTypeArguments(ParameterTypeInferencePolicy policy) { + public PsiSubstitutor inferTypeArguments(@NotNull ParameterTypeInferencePolicy policy) { return inferTypeArgumentsFromInterfaceMethod(signature, interfaceMethodReturnType, method, substitutor, languageLevel); } }; @@ -389,7 +389,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase psiSubstitutor.substitute(method.getReturnType()), interfaceMethodReturnType, psiSubstitutor, - languageLevel, PsiMethodReferenceExpressionImpl.this.getProject()); + languageLevel, getProject()); } private PsiSubstitutor getSubstitutor(PsiType type) { @@ -446,7 +446,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final boolean validConstructorRef = psiMethod.isConstructor() && (myContainingClass.getContainingClass() == null || myContainingClass.hasModifierProperty(PsiModifier.STATIC)); final boolean staticOrValidConstructorRef = psiMethod.hasModifierProperty(PsiModifier.STATIC) || validConstructorRef; - if ((parameterTypes.length == signatureParameterTypes2.length || varArgs) && + if ((parameterTypes.length == signatureParameterTypes2.length || varArgs) && (!(myBeginsWithReferenceType ^ staticOrValidConstructorRef) || (psiMethod.isConstructor() && conflict.isStaticsScopeCorrect()))) { boolean correct = true; for (int i = 0; i < parameterTypes.length; i++) { @@ -497,8 +497,8 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase } private class MethodRefsSpecificResolver extends JavaMethodsConflictResolver { - public MethodRefsSpecificResolver(PsiType[] parameterTypes) { - super(PsiMethodReferenceExpressionImpl.this, parameterTypes); + public MethodRefsSpecificResolver(@NotNull PsiType[] parameterTypes, @NotNull LanguageLevel languageLevel) { + super(PsiMethodReferenceExpressionImpl.this, parameterTypes, languageLevel); } @Override @@ -512,7 +512,8 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase } } checkSpecifics(conflicts, - varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY); + varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, + myLanguageLevel); return conflicts.size() == 1 ? conflicts.get(0) : null; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java index 4b2dc0b96d3d..932bec004fb5 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java @@ -45,9 +45,9 @@ import com.intellij.psi.tree.ChildRoleBase; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.*; -import com.intellij.util.containers.Stack; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,7 +61,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl"); private volatile String myCachedQName = null; - private volatile String myCachedTextSkipWhiteSpaceAndComments = null; + private volatile String myCachedNormalizedText = null; public PsiReferenceExpressionImpl() { super(JavaElementType.REFERENCE_EXPRESSION); @@ -177,20 +177,12 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple @Override public void clearCaches() { myCachedQName = null; - myCachedTextSkipWhiteSpaceAndComments = null; + myCachedNormalizedText = null; super.clearCaches(); } - private static final class OurGenericsResolver implements ResolveCache.PolyVariantResolver<PsiJavaReference> { - private static final OurGenericsResolver INSTANCE = new OurGenericsResolver(); - - @SuppressWarnings("SSBasedInspection") - private static final ThreadLocal<Stack<Object>> ourQualifiers = new ThreadLocal<Stack<Object>>() { - @Override - protected Stack<Object> initialValue() { - return new Stack<Object>(); - } - }; + public static final class OurGenericsResolver implements ResolveCache.PolyVariantResolver<PsiJavaReference> { + public static final OurGenericsResolver INSTANCE = new OurGenericsResolver(); @Override @NotNull @@ -200,8 +192,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple IElementType parentType = treeParent == null ? null : treeParent.getElementType(); PsiFile file = expression.getContainingFile(); - List<ResolveResult[]> qualifierResults = resolveAllQualifiers(expression, file); - ourQualifiers.get().push(qualifierResults); + List<PsiElement> qualifiers = resolveAllQualifiers(expression, file); try { JavaResolveResult[] result = expression.resolve(parentType, file); @@ -214,16 +205,20 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple return result; } finally { - ourQualifiers.get().pop(); + PsiElement item = qualifiers.isEmpty() ? PsiUtilCore.NULL_PSI_ELEMENT : qualifiers.get(qualifiers.size()-1); + qualifiers.clear(); // hold qualifiers list until this moment to avoid psi elements inside to GC + if (item == null) { + throw new IncorrectOperationException(); + } } } - private static List<ResolveResult[]> resolveAllQualifiers(@NotNull PsiReferenceExpressionImpl expression, final PsiFile containingFile) { + private static List<PsiElement> resolveAllQualifiers(@NotNull PsiReferenceExpressionImpl expression, @NotNull final PsiFile containingFile) { // to avoid SOE, resolve all qualifiers starting from the innermost PsiElement qualifier = expression.getQualifier(); if (qualifier == null) return Collections.emptyList(); - final List<ResolveResult[]> qualifierResults = new SmartList<ResolveResult[]>(); + final List<PsiElement> qualifiers = new SmartList<PsiElement>(); final ResolveCache resolveCache = ResolveCache.getInstance(containingFile.getProject()); qualifier.accept(new JavaRecursiveElementWalkingVisitor() { @Override @@ -232,10 +227,9 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple return; } ResolveResult[] cachedResults = resolveCache.getCachedResults(expression, true, false, true); - if (cachedResults == null) { + if (cachedResults != null) { return; } - qualifierResults.add(cachedResults); visitElement(expression); } @@ -243,10 +237,11 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple protected void elementFinished(PsiElement element) { if (!(element instanceof PsiReferenceExpressionImpl)) return; PsiReferenceExpressionImpl expression = (PsiReferenceExpressionImpl)element; - qualifierResults.add(resolveCache.resolveWithCaching(expression, INSTANCE, false, false, containingFile)); + resolveCache.resolveWithCaching(expression, INSTANCE, false, false, containingFile); + qualifiers.add(expression); } }); - return qualifierResults; + return qualifiers; } } @@ -278,7 +273,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple } if (parentType == JavaElementType.METHOD_CALL_EXPRESSION) { - return resolveToMethod(); + return resolveToMethod(containingFile); } if (parentType == JavaElementType.METHOD_REF_EXPRESSION) { @@ -289,9 +284,9 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple } @NotNull - private JavaResolveResult[] resolveToMethod() { + private JavaResolveResult[] resolveToMethod(@NotNull PsiFile containingFile) { final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)getParent(); - final MethodResolverProcessor processor = new MethodResolverProcessor(methodCall); + final MethodResolverProcessor processor = new MethodResolverProcessor(methodCall, containingFile); try { PsiScopesUtil.setupAndRunProcessor(processor, methodCall, false); } @@ -303,7 +298,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple @NotNull private JavaResolveResult[] resolveToPackage(PsiFile containingFile) { - final String packageName = getCachedTextSkipWhiteSpaceAndComments(); + final String packageName = getCachedNormalizedText(); Project project = containingFile.getProject(); JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); final PsiPackage aPackage = psiFacade.findPackage(packageName); @@ -331,7 +326,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple @NotNull private JavaResolveResult[] resolveToVariable() { - final VariableResolverProcessor processor = new VariableResolverProcessor(this); + final VariableResolverProcessor processor = new VariableResolverProcessor(this, getContainingFile()); PsiScopesUtil.resolveAndWalk(processor, this, null); return processor.getResult(); } @@ -371,7 +366,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple " resolves to:" + LogUtil.objectAndClass(element) + " parent:" + LogUtil.objectAndClass(element.getParent())); } - return getCachedTextSkipWhiteSpaceAndComments(); + return getCachedNormalizedText(); } private static final Function<PsiReferenceExpressionImpl, PsiType> TYPE_EVALUATOR = new TypeEvaluator(); @@ -379,8 +374,12 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple private static class TypeEvaluator implements NullableFunction<PsiReferenceExpressionImpl, PsiType> { @Override public PsiType fun(final PsiReferenceExpressionImpl expr) { - JavaResolveResult result = expr.advancedResolve(false); - PsiElement resolve = result.getElement(); + PsiFile file = expr.getContainingFile(); + Project project = file.getProject(); + ResolveResult[] results = ResolveCache.getInstance(project).resolveWithCaching(expr, OurGenericsResolver.INSTANCE, true, false, file); + JavaResolveResult result = results.length == 1 ? (JavaResolveResult)results[0] : null; + + PsiElement resolve = result == null ? null : result.getElement(); if (resolve == null) { ASTNode refName = expr.findChildByRole(ChildRole.REFERENCE_NAME); if (refName != null && "length".equals(refName.getText())) { @@ -417,7 +416,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple } if (ret == null) return null; - final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(expr); + final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(file); if (ret instanceof PsiClassType) { ret = ((PsiClassType)ret).setLanguageLevel(languageLevel); } @@ -468,7 +467,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple } @Override - public void processVariants(PsiScopeProcessor processor) { + public void processVariants(@NotNull PsiScopeProcessor processor) { OrFilter filter = new OrFilter(); filter.addFilter(ElementClassFilter.CLASS); if (isQualified()) { @@ -477,7 +476,8 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple filter.addFilter(new AndFilter(ElementClassFilter.METHOD, new NotFilter(new ConstructorFilter()), new ElementFilter() { @Override public boolean isAcceptable(Object element, @Nullable PsiElement context) { - return LambdaUtil.isValidQualifier4InterfaceStaticMethodCall((PsiMethod)element, PsiReferenceExpressionImpl.this); + return LambdaUtil.isValidQualifier4InterfaceStaticMethodCall((PsiMethod)element, PsiReferenceExpressionImpl.this, + PsiUtil.getLanguageLevel(PsiReferenceExpressionImpl.this)); } @Override @@ -727,7 +727,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple public String getClassNameText() { String cachedQName = myCachedQName; if (cachedQName == null) { - myCachedQName = cachedQName = PsiNameHelper.getQualifiedClassName(getCachedTextSkipWhiteSpaceAndComments(), false); + myCachedQName = cachedQName = PsiNameHelper.getQualifiedClassName(getCachedNormalizedText(), false); } return cachedQName; } @@ -761,10 +761,10 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple } } - private String getCachedTextSkipWhiteSpaceAndComments() { - String whiteSpaceAndComments = myCachedTextSkipWhiteSpaceAndComments; + private String getCachedNormalizedText() { + String whiteSpaceAndComments = myCachedNormalizedText; if (whiteSpaceAndComments == null) { - myCachedTextSkipWhiteSpaceAndComments = whiteSpaceAndComments = SourceUtil.getReferenceText(this); + myCachedNormalizedText = whiteSpaceAndComments = SourceUtil.getReferenceText(this); } return whiteSpaceAndComments; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTypeCastExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTypeCastExpressionImpl.java index bfd7482724d8..fccd07418045 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTypeCastExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTypeCastExpressionImpl.java @@ -18,6 +18,7 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; +import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.Constants; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.tree.IElementType; @@ -46,7 +47,7 @@ public class PsiTypeCastExpressionImpl extends ExpressionPsiElement implements P @Nullable public PsiType getType() { final PsiTypeElement castType = getCastType(); if (castType == null) return null; - return castType.getType(); + return PsiImplUtil.normalizeWildcardTypeByPosition(castType.getType(), this); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTypeParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTypeParameterImpl.java index 12bc9fb34ca2..f03b44e8adb9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTypeParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTypeParameterImpl.java @@ -33,6 +33,7 @@ import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -201,7 +202,7 @@ public class PsiTypeParameterImpl extends JavaStubPsiElement<PsiTypeParameterStu @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { - return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, false); + return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, PsiUtil.getLanguageLevel(place), false); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index f74d883834cf..50218fe92adf 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -49,14 +49,18 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ private final PsiElement myArgumentsList; private final PsiType[] myActualParameterTypes; + protected LanguageLevel myLanguageLevel; - public JavaMethodsConflictResolver(@NotNull PsiExpressionList list) { - this(list, list.getExpressionTypes()); + public JavaMethodsConflictResolver(@NotNull PsiExpressionList list, @NotNull LanguageLevel languageLevel) { + this(list, list.getExpressionTypes(), languageLevel); } - public JavaMethodsConflictResolver(final PsiElement argumentsList, final PsiType[] actualParameterTypes) { + public JavaMethodsConflictResolver(@NotNull PsiElement argumentsList, + @NotNull PsiType[] actualParameterTypes, + @NotNull LanguageLevel languageLevel) { myArgumentsList = argumentsList; myActualParameterTypes = actualParameterTypes; + myLanguageLevel = languageLevel; } @Override @@ -67,7 +71,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ boolean atLeastOneMatch = checkParametersNumber(conflicts, myActualParameterTypes.length, true); if (conflicts.size() == 1) return conflicts.get(0); - checkSameSignatures(conflicts); + checkSameSignatures(conflicts, myLanguageLevel); if (conflicts.size() == 1) return conflicts.get(0); checkAccessStaticLevels(conflicts, true); @@ -83,10 +87,10 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ // then noone can be more specific if (!atLeastOneMatch) return null; - checkLambdaApplicable(conflicts); + checkLambdaApplicable(conflicts, myLanguageLevel); if (conflicts.size() == 1) return conflicts.get(0); - checkSpecifics(conflicts, applicabilityLevel); + checkSpecifics(conflicts, applicabilityLevel, myLanguageLevel); if (conflicts.size() == 1) return conflicts.get(0); checkPrimitiveVarargs(conflicts, myActualParameterTypes.length); @@ -95,13 +99,13 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ checkAccessStaticLevels(conflicts, false); if (conflicts.size() == 1) return conflicts.get(0); - THashSet<CandidateInfo> uniques = new THashSet<CandidateInfo>(conflicts); + Set<CandidateInfo> uniques = new THashSet<CandidateInfo>(conflicts); if (uniques.size() == 1) return uniques.iterator().next(); return null; } - private void checkLambdaApplicable(List<CandidateInfo> conflicts) { - if (!PsiUtil.isLanguageLevel8OrHigher(myArgumentsList)) return; + private void checkLambdaApplicable(@NotNull List<CandidateInfo> conflicts, @NotNull LanguageLevel languageLevel) { + if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) return; for (int i = 0; i < myActualParameterTypes.length; i++) { PsiType parameterType = myActualParameterTypes[i]; if (parameterType instanceof PsiLambdaExpressionType) { @@ -137,7 +141,9 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ LambdaUtil.checkMoreSpecificReturnType(conflicts, myActualParameterTypes); } - public void checkSpecifics(List<CandidateInfo> conflicts, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel) { + public void checkSpecifics(@NotNull List<CandidateInfo> conflicts, + @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel, + @NotNull LanguageLevel languageLevel) { final boolean applicable = applicabilityLevel > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE; int conflictsCount = conflicts.size(); @@ -150,7 +156,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ ProgressManager.checkCanceled(); final CandidateInfo conflict = newConflictsArray[j]; assert conflict != method; - switch (isMoreSpecific(method, conflict, applicabilityLevel)) { + switch (isMoreSpecific(method, conflict, applicabilityLevel, languageLevel)) { case FIRST: conflicts.remove(conflict); break; @@ -187,7 +193,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ } } - private void checkSameSignatures(final List<CandidateInfo> conflicts) { + private void checkSameSignatures(@NotNull List<CandidateInfo> conflicts, @NotNull LanguageLevel languageLevel) { // candidates should go in order of class hierarchy traversal // in order for this to work Map<MethodSignature, CandidateInfo> signatures = new THashMap<MethodSignature, CandidateInfo>(conflicts.size()); @@ -302,6 +308,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ final PsiType returnType = eSubstitutor.substitute(existingMethod.getReturnType()); final PsiType returnType1 = cSubstitutor.substitute(method.getReturnType()); if (returnType != null && returnType1 != null && !returnType1.equals(returnType) && TypeConversionUtil.isAssignable(returnType, returnType1, false)) { + if (class1.isInterface() && !existingClass.isInterface()) continue; conflicts.remove(existing); } else { conflicts.remove(i); @@ -449,9 +456,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ return allowUncheckedConversion ? Specifics.NEITHER : null; } - private boolean isBoxingHappened(PsiType argType, PsiType parameterType) { + private static boolean isBoxingHappened(PsiType argType, PsiType parameterType, @NotNull LanguageLevel languageLevel) { if (argType == null) return parameterType instanceof PsiPrimitiveType; - final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(myArgumentsList); if (parameterType instanceof PsiClassType) { parameterType = ((PsiClassType)parameterType).setLanguageLevel(languageLevel); } @@ -459,7 +465,10 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ return TypeConversionUtil.boxingConversionApplicable(parameterType, argType); } - private Specifics isMoreSpecific(final CandidateInfo info1, final CandidateInfo info2, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel) { + private Specifics isMoreSpecific(final CandidateInfo info1, + final CandidateInfo info2, + @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel, + @NotNull LanguageLevel languageLevel) { PsiMethod method1 = (PsiMethod)info1.getElement(); PsiMethod method2 = (PsiMethod)info2.getElement(); final PsiClass class1 = method1.getContainingClass(); @@ -503,8 +512,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ PsiType type2 = classSubstitutor2.substitute(types2[i]); PsiType argType = i < myActualParameterTypes.length ? myActualParameterTypes[i] : null; - boxingHappened[0] += isBoxingHappened(argType, type1) ? 1 : 0; - boxingHappened[1] += isBoxingHappened(argType, type2) ? 1 : 0; + boxingHappened[0] += isBoxingHappened(argType, type1, languageLevel) ? 1 : 0; + boxingHappened[1] += isBoxingHappened(argType, type2, languageLevel) ? 1 : 0; } if (boxingHappened[0] == 0 && boxingHappened[1] > 0) return Specifics.FIRST; if (boxingHappened[0] > 0 && boxingHappened[1] == 0) return Specifics.SECOND; @@ -519,11 +528,11 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ if (typeParameters1.length == 0 || typeParameters2.length == 0) { if (typeParameters1.length > 0) { final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myArgumentsList.getProject()).getResolveHelper(); - methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, types1, types2, resolveHelper); + methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, types1, types2, resolveHelper, languageLevel); } else if (typeParameters2.length > 0) { final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myArgumentsList.getProject()).getResolveHelper(); - methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, types2, types1, resolveHelper); + methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, types2, types1, resolveHelper, languageLevel); } } else { @@ -625,6 +634,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ } private static Specifics chooseHigherDimension(PsiType type1, PsiType type2) { + if (type1 != null && type1.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return null; + if (type2 != null && type2.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return null; int d1 = type1 != null ? type1.getArrayDimensions() : 0; int d2 = type2 != null ? type2.getArrayDimensions() : 0; if (d1 > d2) { @@ -703,11 +714,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ return null; } - private PsiSubstitutor calculateMethodSubstitutor(final PsiTypeParameter[] typeParameters, - final PsiType[] types1, - final PsiType[] types2, - final PsiResolveHelper resolveHelper) { - PsiSubstitutor substitutor = resolveHelper.inferTypeArguments(typeParameters, types1, types2, PsiUtil.getLanguageLevel(myArgumentsList)); + private static PsiSubstitutor calculateMethodSubstitutor(final PsiTypeParameter[] typeParameters, + final PsiType[] types1, + final PsiType[] types2, + final PsiResolveHelper resolveHelper, + @NotNull LanguageLevel languageLevel) { + PsiSubstitutor substitutor = resolveHelper.inferTypeArguments(typeParameters, types1, types2, languageLevel); for (PsiTypeParameter typeParameter : typeParameters) { ProgressManager.checkCanceled(); LOG.assertTrue(typeParameter != null); diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/ConflictFilterProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/ConflictFilterProcessor.java index 6a226eb6ec9f..f46dd70fc398 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/processor/ConflictFilterProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/ConflictFilterProcessor.java @@ -43,12 +43,13 @@ public class ConflictFilterProcessor extends FilterScopeProcessor<CandidateInfo> @NotNull ElementFilter filter, @NotNull PsiConflictResolver[] resolvers, @NotNull List<CandidateInfo> container, - @NotNull PsiElement place) { + @NotNull PsiElement place, + PsiFile placeFile) { super(filter, container); myResolvers = resolvers; myName = name; myPlace = place; - myPlaceFile = place.getContainingFile(); + myPlaceFile = placeFile; } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java index e38ba9808905..ad0e7358842c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java @@ -33,12 +33,12 @@ import java.util.List; public class MethodCandidatesProcessor extends MethodsProcessor{ protected boolean myHasAccessibleStaticCorrectCandidate = false; - public MethodCandidatesProcessor(@NotNull PsiElement place, @NotNull PsiConflictResolver[] resolvers, @NotNull List<CandidateInfo> container) { - super(resolvers, container, place); + public MethodCandidatesProcessor(@NotNull PsiElement place, PsiFile placeFile, @NotNull PsiConflictResolver[] resolvers, @NotNull List<CandidateInfo> container) { + super(resolvers, container, place, placeFile); } - public MethodCandidatesProcessor(@NotNull PsiElement place) { - super(new PsiConflictResolver[]{DuplicateConflictResolver.INSTANCE}, new SmartList<CandidateInfo>(), place); + public MethodCandidatesProcessor(@NotNull PsiElement place, PsiFile placeFile) { + super(new PsiConflictResolver[]{DuplicateConflictResolver.INSTANCE}, new SmartList<CandidateInfo>(), place, placeFile); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java index 95ac928952de..736433a089c4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java @@ -20,27 +20,30 @@ import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.scope.JavaScopeProcessorEvent; import com.intellij.psi.scope.PsiConflictResolver; import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; public class MethodResolverProcessor extends MethodCandidatesProcessor { private boolean myStopAcceptingCandidates = false; - public MethodResolverProcessor(@NotNull PsiMethodCallExpression place){ - this(place, new PsiConflictResolver[]{new JavaMethodsConflictResolver(place.getArgumentList())}); + public MethodResolverProcessor(@NotNull PsiMethodCallExpression place, @NotNull PsiFile placeFile){ + this(place, placeFile, new PsiConflictResolver[]{new JavaMethodsConflictResolver(place.getArgumentList(), + PsiUtil.getLanguageLevel(placeFile))}); setArgumentList(place.getArgumentList()); obtainTypeArguments(place); } - public MethodResolverProcessor(PsiClass classConstr, @NotNull PsiExpressionList argumentList, @NotNull PsiElement place) { - super(place, new PsiConflictResolver[]{new JavaMethodsConflictResolver(argumentList)}, new SmartList<CandidateInfo>()); + public MethodResolverProcessor(PsiClass classConstr, @NotNull PsiExpressionList argumentList, @NotNull PsiElement place, @NotNull PsiFile placeFile) { + super(place, placeFile, new PsiConflictResolver[]{new JavaMethodsConflictResolver(argumentList, + PsiUtil.getLanguageLevel(placeFile))}, new SmartList<CandidateInfo>()); setIsConstructor(true); setAccessClass(classConstr); setArgumentList(argumentList); } - public MethodResolverProcessor(@NotNull PsiElement place, @NotNull PsiConflictResolver[] resolvers) { - super(place, resolvers, new SmartList<CandidateInfo>()); + public MethodResolverProcessor(@NotNull PsiElement place, @NotNull PsiFile placeFile, @NotNull PsiConflictResolver[] resolvers) { + super(place, placeFile, resolvers, new SmartList<CandidateInfo>()); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodsProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodsProcessor.java index 79873741a08a..47e8b8a6d81a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodsProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodsProcessor.java @@ -46,10 +46,14 @@ public abstract class MethodsProcessor extends ConflictFilterProcessor implement protected PsiClass myAccessClass = null; private PsiExpressionList myArgumentList; private PsiType[] myTypeArguments; - private LanguageLevel myLanguageLevel; - - public MethodsProcessor(@NotNull PsiConflictResolver[] resolvers, @NotNull List<CandidateInfo> container, @NotNull PsiElement place) { - super(null, ourFilter, resolvers, container, place); + private final LanguageLevel myLanguageLevel; + + public MethodsProcessor(@NotNull PsiConflictResolver[] resolvers, + @NotNull List<CandidateInfo> container, + @NotNull PsiElement place, + @NotNull PsiFile placeFile) { + super(null, ourFilter, resolvers, container, place, placeFile); + myLanguageLevel = PsiUtil.getLanguageLevel(placeFile); } public PsiExpressionList getArgumentList() { @@ -58,14 +62,14 @@ public abstract class MethodsProcessor extends ConflictFilterProcessor implement public void setArgumentList(@Nullable PsiExpressionList argList) { myArgumentList = argList; - myLanguageLevel = PsiUtil.getLanguageLevel(argList == null ? myPlace : argList); } - protected LanguageLevel getLanguageLevel() { + @NotNull + public LanguageLevel getLanguageLevel() { return myLanguageLevel; } - public void obtainTypeArguments(PsiCallExpression callExpression) { + public void obtainTypeArguments(@NotNull PsiCallExpression callExpression) { final PsiType[] typeArguments = callExpression.getTypeArguments(); if (typeArguments.length > 0) { setTypeArguments(typeArguments); diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java b/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java index 46036ea6e6ff..8556ee13e513 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java @@ -81,9 +81,6 @@ public class PsiScopesUtil { if (scope == maxScope) break; prevParent = scope; scope = prevParent.getContext(); - if (scope != null && scope != prevParent.getParent() && !scope.isValid()) { - break; - } processor.handleEvent(JavaScopeProcessorEvent.CHANGE_LEVEL, null); } @@ -131,9 +128,7 @@ public class PsiScopesUtil { } else if (type instanceof PsiDisjunctionType) { final PsiType lub = ((PsiDisjunctionType)type).getLeastUpperBound(); - if (lub != null) { - processTypeDeclarations(lub, place, processor); - } + processTypeDeclarations(lub, place, processor); } else { final JavaResolveResult result = PsiUtil.resolveGenericsClassInType(type); @@ -222,12 +217,15 @@ public class PsiScopesUtil { return true; } - public static void setupAndRunProcessor(MethodsProcessor processor, PsiCallExpression call, boolean dummyImplicitConstructor) - throws MethodProcessorSetupFailedException { + public static void setupAndRunProcessor(@NotNull MethodsProcessor processor, + @NotNull PsiCallExpression call, + boolean dummyImplicitConstructor) + throws MethodProcessorSetupFailedException { if (call instanceof PsiMethodCallExpression) { final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)call; final PsiJavaCodeReferenceElement ref = methodCall.getMethodExpression(); + processor.setArgumentList(methodCall.getArgumentList()); processor.obtainTypeArguments(methodCall); if (!ref.isQualified() || ref.getReferenceNameElement() instanceof PsiKeyword) { @@ -307,12 +305,15 @@ public class PsiScopesUtil { final PsiElement referenceName = methodCall.getMethodExpression().getReferenceNameElement(); final PsiManager manager = call.getManager(); final PsiElement qualifier = ref.getQualifier(); - + if (referenceName == null) { + // e.g. "manager.(beginTransaction)" + throw new MethodProcessorSetupFailedException("Can't resolve method name for this expression"); + } if (referenceName instanceof PsiIdentifier && qualifier instanceof PsiExpression) { PsiType type = ((PsiExpression)qualifier).getType(); if (type != null && qualifier instanceof PsiReferenceExpression) { final PsiElement resolve = ((PsiReferenceExpression)qualifier).resolve(); - if (resolve instanceof PsiVariable && ((PsiVariable)resolve).hasModifierProperty(PsiModifier.FINAL)) { + if (resolve instanceof PsiVariable && ((PsiVariable)resolve).hasModifierProperty(PsiModifier.FINAL) && ((PsiVariable)resolve).hasInitializer()) { final PsiExpression initializer = ((PsiVariable)resolve).getInitializer(); if (initializer instanceof PsiNewExpression) { final PsiAnonymousClass anonymousClass = ((PsiNewExpression)initializer).getAnonymousClass(); @@ -405,9 +406,9 @@ public class PsiScopesUtil { return true; } - private static boolean processQualifierResult(JavaResolveResult qualifierResult, - final MethodsProcessor processor, - PsiMethodCallExpression methodCall) throws MethodProcessorSetupFailedException { + private static boolean processQualifierResult(@NotNull JavaResolveResult qualifierResult, + @NotNull MethodsProcessor processor, + @NotNull PsiMethodCallExpression methodCall) throws MethodProcessorSetupFailedException { PsiElement resolve = qualifierResult.getElement(); if (resolve == null) { diff --git a/java/java-psi-impl/src/com/intellij/refactoring/extractMethod/InputVariables.java b/java/java-psi-impl/src/com/intellij/refactoring/extractMethod/InputVariables.java deleted file mode 100644 index 369613c46040..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/extractMethod/InputVariables.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * User: anna - * Date: 22-Jun-2009 - */ -package com.intellij.refactoring.extractMethod; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.controlFlow.ControlFlow; -import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.refactoring.util.VariableData; -import com.intellij.refactoring.util.duplicates.DuplicatesFinder; -import com.intellij.util.ArrayUtil; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class InputVariables { - private final List<VariableData> myInputVariables; - - private List<? extends PsiVariable> myInitialParameters; - private final Project myProject; - private final LocalSearchScope myScope; - - private ParametersFolder myFolding; - private boolean myFoldingAvailable; - - public InputVariables(final List<? extends PsiVariable> inputVariables, - Project project, - LocalSearchScope scope, - boolean foldingAvailable) { - myInitialParameters = inputVariables; - myProject = project; - myScope = scope; - myFoldingAvailable = foldingAvailable; - myFolding = new ParametersFolder(); - myInputVariables = wrapInputVariables(inputVariables); - } - - /** - * copy use only - */ - public InputVariables(List<VariableData> inputVariables, - Project project, - LocalSearchScope scope) { - myProject = project; - myScope = scope; - myInputVariables = new ArrayList<VariableData>(inputVariables); - } - - public boolean isFoldable() { - return myFolding.isFoldable(); - } - - public ArrayList<VariableData> wrapInputVariables(final List<? extends PsiVariable> inputVariables) { - final ArrayList<VariableData> inputData = new ArrayList<VariableData>(inputVariables.size()); - for (PsiVariable var : inputVariables) { - String name = var.getName(); - if (!(var instanceof PsiParameter)) { - JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(myProject); - VariableKind kind = codeStyleManager.getVariableKind(var); - name = codeStyleManager.variableNameToPropertyName(name, kind); - name = codeStyleManager.propertyNameToVariableName(name, VariableKind.PARAMETER); - } - PsiType type = var.getType(); - if (type instanceof PsiEllipsisType) { - type = ((PsiEllipsisType)type).toArrayType(); - } - final Map<PsiCodeBlock, PsiType> casts = new HashMap<PsiCodeBlock, PsiType>(); - for (PsiReference reference : ReferencesSearch.search(var, myScope)) { - final PsiElement element = reference.getElement(); - final PsiElement parent = element.getParent(); - final PsiCodeBlock block = PsiTreeUtil.getParentOfType(parent, PsiCodeBlock.class); - if (parent instanceof PsiTypeCastExpression) { - final PsiType currentType = casts.get(block); - final PsiType castType = ((PsiTypeCastExpression)parent).getType(); - casts.put(block, casts.containsKey(block) && currentType == null ? null : getBroaderType(currentType, castType)); - } else { - casts.put(block, null); - } - } - if (!casts.containsValue(null)) { - PsiType currentType = null; - for (PsiType psiType : casts.values()) { - currentType = getBroaderType(currentType, psiType); - if (currentType == null) { - break; - } - } - if (currentType != null) { - currentType = checkTopLevelInstanceOf(currentType); - if (currentType != null) { - type = currentType; - } - } - } - - VariableData data = new VariableData(var, type); - data.name = name; - data.passAsParameter = true; - inputData.add(data); - - if (myFoldingAvailable) myFolding.isParameterFoldable(data, myScope, inputVariables); - } - - - if (myFoldingAvailable) { - final Set<VariableData> toDelete = new HashSet<VariableData>(); - for (int i = inputData.size() - 1; i >=0; i--) { - final VariableData data = inputData.get(i); - if (myFolding.isParameterSafeToDelete(data, myScope)) { - toDelete.add(data); - } - } - inputData.removeAll(toDelete); - } - - - return inputData; - } - - @Nullable - private PsiType checkTopLevelInstanceOf(final PsiType currentType) { - final PsiElement[] scope = myScope.getScope(); - if (scope.length == 1 && scope[0] instanceof PsiIfStatement) { - final PsiExpression condition = ((PsiIfStatement)scope[0]).getCondition(); - if (condition != null) { - class CheckInstanceOf { - boolean check(PsiInstanceOfExpression expr) { - final PsiTypeElement checkType = expr.getCheckType(); - return checkType == null || !checkType.getType().equals(currentType); - } - } - CheckInstanceOf checker = new CheckInstanceOf(); - final PsiInstanceOfExpression[] expressions = PsiTreeUtil.getChildrenOfType(condition, PsiInstanceOfExpression.class); - if (expressions != null) { - for (PsiInstanceOfExpression instanceOfExpression : expressions) { - if (!checker.check(instanceOfExpression)) return null; - } - } else if (condition instanceof PsiInstanceOfExpression) { - if (!checker.check((PsiInstanceOfExpression)condition)) return null; - } - } - } - return currentType; - } - - @Nullable - private static PsiType getBroaderType(PsiType currentType, PsiType castType) { - if (currentType != null) { - if (castType != null) { - if (TypeConversionUtil.isAssignable(castType, currentType)) { - return castType; - } else if (!TypeConversionUtil.isAssignable(currentType, castType)) { - for (PsiType superType : castType.getSuperTypes()) { - if (TypeConversionUtil.isAssignable(superType, currentType)) { - return superType; - } - } - return null; - } - } - } - else { - return castType; - } - return currentType; - } - - public List<VariableData> getInputVariables() { - return myInputVariables; - } - - public PsiExpression replaceWrappedReferences(PsiElement[] elements, PsiExpression expression) { - if (!myFoldingAvailable) return expression; - - boolean update = elements[0] == expression; - for (VariableData inputVariable : myInputVariables) { - myFolding.foldParameterUsagesInBody(inputVariable, elements, myScope); - } - return update ? (PsiExpression)elements[0] : expression; - } - - public boolean toDeclareInsideBody(PsiVariable variable) { - final ArrayList<VariableData> knownVars = new ArrayList<VariableData>(myInputVariables); - for (VariableData data : knownVars) { - if (data.variable.equals(variable)) { - return false; - } - } - return !myFolding.wasExcluded(variable); - } - - public boolean contains(PsiVariable variable) { - for (VariableData data : myInputVariables) { - if (data.variable.equals(variable)) return true; - } - return false; - } - - public void removeParametersUsedInExitsOnly(PsiElement codeFragment, - Collection<PsiStatement> exitStatements, - ControlFlow controlFlow, - int startOffset, - int endOffset) { - final LocalSearchScope scope = new LocalSearchScope(codeFragment); - Variables: - for (Iterator<VariableData> iterator = myInputVariables.iterator(); iterator.hasNext();) { - final VariableData data = iterator.next(); - for (PsiReference ref : ReferencesSearch.search(data.variable, scope)) { - PsiElement element = ref.getElement(); - int elementOffset = controlFlow.getStartOffset(element); - if (elementOffset >= startOffset && elementOffset <= endOffset) { - if (!isInExitStatements(element, exitStatements)) continue Variables; - } - } - iterator.remove(); - } - } - - private static boolean isInExitStatements(PsiElement element, Collection<PsiStatement> exitStatements) { - for (PsiStatement exitStatement : exitStatements) { - if (PsiTreeUtil.isAncestor(exitStatement, element, false)) return true; - } - return false; - } - - - public InputVariables copy() { - final InputVariables inputVariables = new InputVariables(myInputVariables, myProject, myScope); - inputVariables.myFoldingAvailable = myFoldingAvailable; - inputVariables.myFolding = myFolding; - inputVariables.myInitialParameters = myInitialParameters; - return inputVariables; - } - - - public void appendCallArguments(VariableData data, StringBuilder buffer) { - if (myFoldingAvailable) { - buffer.append(myFolding.getGeneratedCallArgument(data)); - } else { - if (!TypeConversionUtil.isAssignable(data.type, data.variable.getType())) { - buffer.append("(").append(data.type.getCanonicalText()).append(")"); - } - buffer.append(data.variable.getName()); - } - } - - public void setFoldingAvailable(boolean foldingAvailable) { - myFoldingAvailable = foldingAvailable; - - myFolding.clear(); - myInputVariables.clear(); - myInputVariables.addAll(wrapInputVariables(myInitialParameters)); - } - - public void annotateWithParameter(PsiJavaCodeReferenceElement reference) { - for (VariableData data : myInputVariables) { - final PsiElement element = reference.resolve(); - if (data.variable.equals(element)) { - PsiType type = data.variable.getType(); - final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(reference, PsiMethodCallExpression.class); - if (methodCallExpression != null) { - int idx = ArrayUtil.find(methodCallExpression.getArgumentList().getExpressions(), reference); - if (idx > -1) { - final PsiMethod psiMethod = methodCallExpression.resolveMethod(); - if (psiMethod != null) { - final PsiParameter[] parameters = psiMethod.getParameterList().getParameters(); - if (idx >= parameters.length) { //vararg parameter - idx = parameters.length - 1; - if (idx >= 0) { //incomplete code - type = parameters[idx].getType(); - } - } - if (type instanceof PsiEllipsisType) { - type = ((PsiEllipsisType)type).getComponentType(); - } - } - } - } - if (!myFoldingAvailable || !myFolding.annotateWithParameter(data, reference)) { - reference.putUserData(DuplicatesFinder.PARAMETER, Pair.create(data.variable, type)); - } - } - } - } - - public boolean isFoldingSelectedByDefault() { - return myFolding.isFoldingSelectedByDefault(); - } -}
\ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java b/java/java-psi-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java deleted file mode 100644 index eac9b18ac2fe..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * User: anna - * Date: 23-Jun-2009 - */ -package com.intellij.refactoring.extractMethod; - -import com.intellij.codeInsight.PsiEquivalenceUtil; -import com.intellij.openapi.util.Pair; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; -import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.SearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.refactoring.util.VariableData; -import com.intellij.refactoring.util.duplicates.DuplicatesFinder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class ParametersFolder { - private final Map<PsiVariable, PsiExpression> myExpressions = new HashMap<PsiVariable, PsiExpression>(); - private final Map<PsiVariable, List<PsiExpression>> myMentionedInExpressions = new HashMap<PsiVariable, List<PsiExpression>>(); - private final Set<String> myUsedNames = new HashSet<String>(); - - private final Set<PsiVariable> myDeleted = new HashSet<PsiVariable>(); - private boolean myFoldingSelectedByDefault = false; - - - public void clear() { - myExpressions.clear(); - myMentionedInExpressions.clear(); - myUsedNames.clear(); - myDeleted.clear(); - } - - public boolean isParameterSafeToDelete(@NotNull VariableData data, @NotNull LocalSearchScope scope) { - Next: - for (PsiReference reference : ReferencesSearch.search(data.variable, scope)) { - PsiElement expression = reference.getElement(); - while (expression != null) { - for (PsiExpression psiExpression : myExpressions.values()) { - if (PsiEquivalenceUtil.areElementsEquivalent(expression, psiExpression)) { - continue Next; - } - } - expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class); - } - return false; - } - final PsiExpression psiExpression = myExpressions.get(data.variable); - if (psiExpression == null) return true; - for (PsiVariable variable : myExpressions.keySet()) { - if (variable != data.variable && !myDeleted.contains(variable)) { - final PsiExpression expr = myExpressions.get(variable); - if (expr != null && PsiEquivalenceUtil.areElementsEquivalent(expr, psiExpression)) { - myDeleted.add(data.variable); - return true; - } - } - } - return false; - } - - public void foldParameterUsagesInBody(@NotNull VariableData data, PsiElement[] elements, SearchScope scope) { - if (myDeleted.contains(data.variable)) return; - final PsiExpression psiExpression = myExpressions.get(data.variable); - if (psiExpression == null) return; - final Set<PsiExpression> eqExpressions = new HashSet<PsiExpression>(); - for (PsiReference reference : ReferencesSearch.search(data.variable, scope)) { - final PsiExpression expression = findEquivalent(psiExpression, reference.getElement()); - if (expression != null && expression.isValid()) { - eqExpressions.add(expression); - } - } - - for (PsiExpression expression : eqExpressions) { - final PsiExpression refExpression = - JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(data.variable.getName(), expression); - final PsiElement replaced = expression.replace(refExpression); - for (int i = 0, psiElementsLength = elements.length; i < psiElementsLength; i++) { - PsiElement psiElement = elements[i]; - if (expression == psiElement) { - elements[i] = replaced; - break; - } - } - } - } - - public boolean isParameterFoldable(@NotNull VariableData data, - @NotNull LocalSearchScope scope, - @NotNull final List<? extends PsiVariable> inputVariables) { - final List<PsiExpression> mentionedInExpressions = getMentionedExpressions(data.variable, scope, inputVariables); - if (mentionedInExpressions == null) return false; - - int currentRank = 0; - PsiExpression mostRanked = null; - for (int i = mentionedInExpressions.size() - 1; i >= 0; i--) { - PsiExpression expression = mentionedInExpressions.get(i); - if (expression instanceof PsiArrayAccessExpression) { - mostRanked = expression; - if (!isConditional(expression, scope)) { - myFoldingSelectedByDefault = true; - break; - } - } - final int r = findUsedVariables(data, inputVariables, expression).size(); - if (currentRank < r) { - currentRank = r; - mostRanked = expression; - } - } - - if (mostRanked != null) { - myExpressions.put(data.variable, mostRanked); - data.type = mostRanked.getType(); - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(mostRanked.getProject()); - final SuggestedNameInfo nameInfo = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, mostRanked, data.type); - if (nameInfo.names.length > 0) { - data.name = nameInfo.names[0]; - } - setUniqueName(data); - } - - return mostRanked != null; - } - - private static boolean isConditional(PsiElement expr, LocalSearchScope scope) { - while (expr != null) { - final PsiElement parent = expr.getParent(); - if (parent != null && scope.containsRange(parent.getContainingFile(), parent.getTextRange())) { - if (parent instanceof PsiIfStatement) { - if (((PsiIfStatement)parent).getCondition() != expr) return true; - } else if (parent instanceof PsiConditionalExpression) { - if (((PsiConditionalExpression)parent).getCondition() != expr) return true; - } else if (parent instanceof PsiSwitchStatement) { - if (((PsiSwitchStatement)parent).getExpression() != expr) return true; - } - } else { - return false; - } - expr = parent; - } - return false; - } - - private void setUniqueName(VariableData data) { - int idx = 1; - while (myUsedNames.contains(data.name)) { - data.name += idx; - } - myUsedNames.add(data.name); - } - - private static Set<PsiVariable> findUsedVariables(VariableData data, final List<? extends PsiVariable> inputVariables, - PsiExpression expression) { - final Set<PsiVariable> found = new HashSet<PsiVariable>(); - expression.accept(new JavaRecursiveElementVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression referenceExpression) { - super.visitReferenceExpression(referenceExpression); - PsiElement resolved = referenceExpression.resolve(); - if (resolved instanceof PsiVariable && inputVariables.contains(resolved)) { - found.add((PsiVariable)resolved); - } - } - }); - found.remove(data.variable); - return found; - } - - public boolean isFoldable() { - return !myExpressions.isEmpty(); - } - - @Nullable - private List<PsiExpression> getMentionedExpressions(PsiVariable var, LocalSearchScope scope, final List<? extends PsiVariable> inputVariables) { - if (myMentionedInExpressions.containsKey(var)) return myMentionedInExpressions.get(var); - final PsiElement[] scopeElements = scope.getScope(); - List<PsiExpression> expressions = null; - for (PsiReference reference : ReferencesSearch.search(var, scope)) { - PsiElement expression = reference.getElement(); - if (expressions == null) { - expressions = new ArrayList<PsiExpression>(); - while (expression != null) { - if (isAccessedForWriting((PsiExpression)expression)) return null; - for (PsiElement scopeElement : scopeElements) { - if (PsiTreeUtil.isAncestor(expression, scopeElement, true)) { - expression = null; - break; - } - } - if (expression == null) break; - - final PsiType expressionType = ((PsiExpression)expression).getType(); - if (expressionType != null && expressionType != PsiType.VOID && !(expression.getParent() instanceof PsiExpressionStatement)) { - if (dependsOnLocals(expression, inputVariables)) { - break; - } - expressions.add((PsiExpression)expression); - } - expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class); - } - } - else { - for (Iterator<PsiExpression> iterator = expressions.iterator(); iterator.hasNext();) { - if (findEquivalent(iterator.next(), expression) == null) { - iterator.remove(); - } - } - } - } - myMentionedInExpressions.put(var, expressions); - return expressions; - } - - private static boolean isAccessedForWriting(PsiExpression expression) { - final PsiExpression[] exprWithWriteAccessInside = new PsiExpression[1]; - expression.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitElement(PsiElement element) { - if (exprWithWriteAccessInside[0] != null) return; - super.visitElement(element); - } - - @Override - public void visitExpression(PsiExpression expression) { - if (PsiUtil.isAccessedForWriting(expression)) { - exprWithWriteAccessInside[0] = expression; - } - super.visitExpression(expression); - } - }); - return exprWithWriteAccessInside[0] != null; - } - - private static boolean dependsOnLocals(final PsiElement expression, final List<? extends PsiVariable> inputVariables) { - final boolean[] localVarsUsed = new boolean[]{false}; - expression.accept(new JavaRecursiveElementWalkingVisitor(){ - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - final PsiElement resolved = expression.resolve(); - if (resolved instanceof PsiVariable) { - final PsiVariable variable = (PsiVariable)resolved; - if (!inputVariables.contains(variable)) { - localVarsUsed[0] = true; - return; - } - } - super.visitReferenceExpression(expression); - } - }); - return localVarsUsed[0]; - } - - @NotNull - public String getGeneratedCallArgument(@NotNull VariableData data) { - return myExpressions.containsKey(data.variable) ? myExpressions.get(data.variable).getText() : data.variable.getName(); - } - - public boolean annotateWithParameter(@NotNull VariableData data, @NotNull PsiElement element) { - final PsiExpression psiExpression = myExpressions.get(data.variable); - if (psiExpression != null) { - final PsiExpression expression = findEquivalent(psiExpression, element); - if (expression != null) { - expression.putUserData(DuplicatesFinder.PARAMETER, Pair.create(data.variable, expression.getType())); - return true; - } - } - return false; - } - - @Nullable - private static PsiExpression findEquivalent(PsiExpression expr, PsiElement element) { - PsiElement expression = element; - while (expression != null) { - if (PsiEquivalenceUtil.areElementsEquivalent(expression, expr)) { - return (PsiExpression)expression; - } - expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class); - } - return null; - } - - public boolean wasExcluded(PsiVariable variable) { - return myDeleted.contains(variable) || (myMentionedInExpressions.containsKey(variable) && myExpressions.get(variable) == null); - } - - public boolean isFoldingSelectedByDefault() { - return myFoldingSelectedByDefault; - } -}
\ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/VariableData.java b/java/java-psi-impl/src/com/intellij/refactoring/util/VariableData.java deleted file mode 100644 index 0fd6cc0569e4..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/VariableData.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util; - -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiVariable; -import com.intellij.psi.SmartTypePointerManager; -import org.jetbrains.annotations.NotNull; - -public class VariableData { - public final PsiVariable variable; - public PsiType type; - public String name; - public boolean passAsParameter; - - public VariableData(@NotNull PsiVariable var) { - variable = var; - type = var.getType(); - } - - public VariableData(@NotNull PsiVariable var, @NotNull PsiType type) { - variable = var; - this.type = SmartTypePointerManager.getInstance(var.getProject()).createSmartTypePointer(type).getType(); - } -} diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/BreakReturnValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/BreakReturnValue.java deleted file mode 100644 index 6b4652cccce3..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/BreakReturnValue.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * User: anna - * Date: 23-Oct-2008 - */ -package com.intellij.refactoring.util.duplicates; - -import org.jetbrains.annotations.NonNls; - -public class BreakReturnValue extends GotoReturnValue{ - public boolean isEquivalent(final ReturnValue other) { - return other instanceof BreakReturnValue; - } - - @NonNls - public String getGotoStatement() { - return "if(a) break;"; - } -}
\ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ConditionalReturnStatementValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ConditionalReturnStatementValue.java deleted file mode 100644 index 3878619c6db9..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ConditionalReturnStatementValue.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.codeInsight.PsiEquivalenceUtil; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; - -/** - * @author ven - */ -public class ConditionalReturnStatementValue implements ReturnValue { - PsiExpression myReturnValue; - - public ConditionalReturnStatementValue(final PsiExpression returnValue) { - myReturnValue = returnValue; - } - - public boolean isEquivalent(ReturnValue other) { - if (!(other instanceof ConditionalReturnStatementValue)) return false; - PsiExpression otherReturnValue = ((ConditionalReturnStatementValue) other).myReturnValue; - if (otherReturnValue == null || myReturnValue == null) return myReturnValue == null && otherReturnValue == null; - return PsiEquivalenceUtil.areElementsEquivalent(myReturnValue, otherReturnValue); - } - - public PsiStatement createReplacement(final PsiMethod extractedMethod, PsiMethodCallExpression methodCallExpression) throws IncorrectOperationException { - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(methodCallExpression.getProject()).getElementFactory(); - PsiIfStatement statement; - if (myReturnValue == null) { - statement = (PsiIfStatement)elementFactory.createStatementFromText("if(a) return;", null); - } - else { - statement = (PsiIfStatement)elementFactory.createStatementFromText("if(a) return b;", null); - final PsiReturnStatement thenBranch = (PsiReturnStatement)statement.getThenBranch(); - assert thenBranch != null; - final PsiExpression returnValue = thenBranch.getReturnValue(); - assert returnValue != null; - returnValue.replace(myReturnValue); - } - - final PsiExpression condition = statement.getCondition(); - assert condition != null; - condition.replace(methodCallExpression); - return (PsiStatement)CodeStyleManager.getInstance(statement.getManager().getProject()).reformat(statement); - } -} diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ContinueReturnValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ContinueReturnValue.java deleted file mode 100644 index 6bbf6321c835..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ContinueReturnValue.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * User: anna - * Date: 23-Oct-2008 - */ -package com.intellij.refactoring.util.duplicates; - -import org.jetbrains.annotations.NonNls; - -public class ContinueReturnValue extends GotoReturnValue { - public boolean isEquivalent(final ReturnValue other) { - return other instanceof ContinueReturnValue; - } - - - @NonNls - public String getGotoStatement() { - return "if (a) continue;"; - } -}
\ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java deleted file mode 100644 index 75403848cbe8..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.codeInsight.PsiEquivalenceUtil; -import com.intellij.lang.ASTNode; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; -import com.intellij.psi.*; -import com.intellij.psi.controlFlow.*; -import com.intellij.psi.impl.source.PsiImmediateClassType; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.*; -import com.intellij.refactoring.extractMethod.InputVariables; -import com.intellij.refactoring.util.RefactoringChangeUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.IntArrayList; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -/** - * @author dsl - */ -public class DuplicatesFinder { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.duplicates.DuplicatesFinder"); - public static final Key<Pair<PsiVariable, PsiType>> PARAMETER = Key.create("PARAMETER"); - private final PsiElement[] myPattern; - private InputVariables myParameters; - private final List<? extends PsiVariable> myOutputParameters; - private final List<PsiElement> myPatternAsList; - private boolean myMultipleExitPoints = false; - @Nullable private final ReturnValue myReturnValue; - - public DuplicatesFinder(PsiElement[] pattern, - InputVariables parameters, - @Nullable ReturnValue returnValue, - @NotNull List<? extends PsiVariable> outputParameters - ) { - myReturnValue = returnValue; - LOG.assertTrue(pattern.length > 0); - myPattern = pattern; - myPatternAsList = Arrays.asList(myPattern); - myParameters = parameters; - myOutputParameters = outputParameters; - - final PsiElement codeFragment = ControlFlowUtil.findCodeFragment(pattern[0]); - try { - final ControlFlow controlFlow = ControlFlowFactory.getInstance(codeFragment.getProject()).getControlFlow(codeFragment, new LocalsControlFlowPolicy(codeFragment), false); - - int startOffset; - int i = 0; - do { - startOffset = controlFlow.getStartOffset(pattern[i++]); - } while(startOffset < 0 && i < pattern.length); - - int endOffset; - int j = pattern.length - 1; - do { - endOffset = controlFlow.getEndOffset(pattern[j--]); - } while(endOffset < 0 && j >= 0); - - IntArrayList exitPoints = new IntArrayList(); - final Collection<PsiStatement> exitStatements = ControlFlowUtil - .findExitPointsAndStatements(controlFlow, startOffset, endOffset, exitPoints, ControlFlowUtil.DEFAULT_EXIT_STATEMENTS_CLASSES); - myMultipleExitPoints = exitPoints.size() > 1; - - if (myMultipleExitPoints) { - myParameters.removeParametersUsedInExitsOnly(codeFragment, exitStatements, controlFlow, startOffset, endOffset); - } - } - catch (AnalysisCanceledException e) { - } - } - - public DuplicatesFinder(final PsiElement[] pattern, - final InputVariables psiParameters, - final List<? extends PsiVariable> psiVariables) { - this(pattern, psiParameters, null, psiVariables); - } - - - - - public List<Match> findDuplicates(PsiElement scope) { - annotatePattern(); - final ArrayList<Match> result = new ArrayList<Match>(); - findPatternOccurrences(result, scope); - deannotatePattern(); - return result; - } - - @Nullable - public Match isDuplicate(PsiElement element, boolean ignoreParameterTypes) { - annotatePattern(); - Match match = isDuplicateFragment(element, ignoreParameterTypes); - deannotatePattern(); - return match; - } - - private void annotatePattern() { - for (final PsiElement patternComponent : myPattern) { - patternComponent.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - final PsiElement element = reference.resolve(); - if (element instanceof PsiVariable) { - final PsiVariable variable = (PsiVariable)element; - PsiType type = variable.getType(); - myParameters.annotateWithParameter(reference); - if (myOutputParameters.contains(element)) { - reference.putUserData(PARAMETER, Pair.create(variable, type)); - } - } - PsiElement qualifier = reference.getQualifier(); - if (qualifier != null) { - qualifier.accept(this); - } - } - }); - } - } - - private void deannotatePattern() { - for (final PsiElement patternComponent : myPattern) { - patternComponent.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - if (reference.getUserData(PARAMETER) != null) { - reference.putUserData(PARAMETER, null); - } - } - }); - } - } - - private void findPatternOccurrences(List<Match> array, PsiElement scope) { - PsiElement[] children = scope.getChildren(); - for (PsiElement child : children) { - final Match match = isDuplicateFragment(child, false); - if (match != null) { - array.add(match); - continue; - } - findPatternOccurrences(array, child); - } - } - - - @Nullable - private Match isDuplicateFragment(PsiElement candidate, boolean ignoreParameterTypes) { - for (PsiElement pattern : myPattern) { - if (PsiTreeUtil.isAncestor(pattern, candidate, false)) return null; - } - PsiElement sibling = candidate; - ArrayList<PsiElement> candidates = new ArrayList<PsiElement>(); - for (final PsiElement element : myPattern) { - if (sibling == null) return null; - if (!canBeEquivalent(element, sibling)) return null; - candidates.add(sibling); - sibling = PsiTreeUtil.skipSiblingsForward(sibling, PsiWhiteSpace.class, PsiComment.class); - } - LOG.assertTrue(myPattern.length == candidates.size()); - if (myPattern.length == 1 && myPattern[0] instanceof PsiExpression) { - if (candidates.get(0) instanceof PsiExpression) { - final PsiExpression candidateExpression = (PsiExpression)candidates.get(0); - if (PsiUtil.isAccessedForWriting(candidateExpression)) return null; - final PsiType patternType = ((PsiExpression)myPattern[0]).getType(); - final PsiType candidateType = candidateExpression.getType(); - PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; - final PsiMethod method = PsiTreeUtil.getParentOfType(myPattern[0], PsiMethod.class); - if (method != null) { - final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(candidate.getProject()).getResolveHelper(); - substitutor = resolveHelper.inferTypeArguments(method.getTypeParameters(), new PsiType[]{patternType}, - new PsiType[]{candidateType}, PsiUtil.getLanguageLevel(method)); - } - if (!canTypesBeEquivalent(substitutor.substitute(patternType), candidateType)) return null; - } - else { - return null; - } - - } - final Match match = new Match(candidates.get(0), candidates.get(candidates.size() - 1), ignoreParameterTypes); - for (int i = 0; i < myPattern.length; i++) { - if (!matchPattern(myPattern[i], candidates.get(i), candidates, match)) return null; - } - - if (checkPostVariableUsages(candidates, match)) return null; - - return match; - } - - private boolean checkPostVariableUsages(final ArrayList<PsiElement> candidates, final Match match) { - final PsiElement codeFragment = ControlFlowUtil.findCodeFragment(candidates.get(0)); - try { - final ControlFlow controlFlow = ControlFlowFactory.getInstance(codeFragment.getProject()).getControlFlow(codeFragment, new LocalsControlFlowPolicy(codeFragment), false); - - int startOffset; - int i = 0; - do { - startOffset = controlFlow.getStartOffset(candidates.get(i++)); - } while(startOffset < 0 && i < candidates.size()); - - int endOffset; - int j = candidates.size() - 1; - do { - endOffset = controlFlow.getEndOffset(candidates.get(j--)); - } while(endOffset < 0 && j >= 0); - - final IntArrayList exitPoints = new IntArrayList(); - ControlFlowUtil.findExitPointsAndStatements(controlFlow, startOffset, endOffset, exitPoints, ControlFlowUtil.DEFAULT_EXIT_STATEMENTS_CLASSES); - final PsiVariable[] outVariables = ControlFlowUtil.getOutputVariables(controlFlow, startOffset, endOffset, exitPoints.toArray()); - - if (outVariables.length > 0) { - if (outVariables.length == 1) { - ReturnValue returnValue = match.getReturnValue(); - if (returnValue == null) { - returnValue = myReturnValue; - } - if (returnValue instanceof VariableReturnValue) { - final ReturnValue value = match.getOutputVariableValue(((VariableReturnValue)returnValue).getVariable()); - if (value != null) { - if (value.isEquivalent(new VariableReturnValue(outVariables[0]))) return false; - if (value instanceof ExpressionReturnValue) { - final PsiExpression expression = ((ExpressionReturnValue)value).getExpression(); - if (expression instanceof PsiReferenceExpression) { - final PsiElement variable = ((PsiReferenceExpression)expression).resolve(); - return variable == null || !PsiEquivalenceUtil.areElementsEquivalent(variable, outVariables[0]); - } - } - } - } - } - return true; - } - } - catch (AnalysisCanceledException e) { - } - return false; - } - - private static boolean canTypesBeEquivalent(PsiType type1, PsiType type2) { - if (type1 == null || type2 == null) return false; - if (!type2.isAssignableFrom(type1)) { - if (type1 instanceof PsiImmediateClassType && type2 instanceof PsiImmediateClassType) { - final PsiClass psiClass1 = ((PsiImmediateClassType)type1).resolve(); - final PsiClass psiClass2 = ((PsiImmediateClassType)type2).resolve(); - if (!(psiClass1 instanceof PsiAnonymousClass && - psiClass2 instanceof PsiAnonymousClass && - psiClass1.getManager().areElementsEquivalent(((PsiAnonymousClass)psiClass1).getBaseClassType().resolve(), - ((PsiAnonymousClass)psiClass2).getBaseClassType().resolve()))) { - return false; - } - } - else { - return false; - } - } - return true; - } - - private static boolean canBeEquivalent(final PsiElement pattern, PsiElement candidate) { - if (pattern instanceof PsiReturnStatement && candidate instanceof PsiExpressionStatement) return true; - if (pattern instanceof PsiReturnStatement && candidate instanceof PsiDeclarationStatement) return true; - if (pattern instanceof PsiThisExpression && candidate instanceof PsiReferenceExpression) return true; - final ASTNode node1 = pattern.getNode(); - final ASTNode node2 = candidate.getNode(); - if (node1 == null || node2 == null) return false; - return node1.getElementType() == node2.getElementType(); - } - - private boolean matchPattern(PsiElement pattern, - PsiElement candidate, - List<PsiElement> candidates, - Match match) { - if (pattern == null || candidate == null) return pattern == candidate; - if (pattern.getUserData(PARAMETER) != null) { - final Pair<PsiVariable, PsiType> parameter = pattern.getUserData(PARAMETER); - return match.putParameter(parameter, candidate); - } - - if (!canBeEquivalent(pattern, candidate)) return false; // Q : is it correct to check implementation classes? - - if (pattern instanceof PsiExpressionList && candidate instanceof PsiExpressionList) { //check varargs - final PsiExpression[] expressions = ((PsiExpressionList)pattern).getExpressions(); - final PsiExpression[] childExpressions = ((PsiExpressionList)candidate).getExpressions(); - if (expressions.length > 0 && expressions[expressions.length - 1] instanceof PsiReferenceExpression) { - final PsiElement resolved = ((PsiReferenceExpression)expressions[expressions.length - 1]).resolve(); - if (resolved instanceof PsiParameter && ((PsiParameter)resolved).getType() instanceof PsiEllipsisType) { - for(int i = 0; i < expressions.length - 1; i++) { - final Pair<PsiVariable, PsiType> parameter = expressions[i].getUserData(PARAMETER); - if (parameter == null) { - if (!matchPattern(expressions[i], childExpressions[i], candidates, match)) { - return false; - } - } else if (!match.putParameter(parameter, childExpressions[i])) return false; - } - final Pair<PsiVariable, PsiType> param = expressions[expressions.length - 1].getUserData(PARAMETER); - if (param == null) return false; - for(int i = expressions.length - 1; i < childExpressions.length; i++) { - if (!match.putParameter(param, childExpressions[i])) return false; - } - return true; - } - } - } - - if (pattern instanceof PsiAssignmentExpression) { - final PsiExpression lExpression = ((PsiAssignmentExpression)pattern).getLExpression(); - if (lExpression.getType() instanceof PsiPrimitiveType && - lExpression instanceof PsiReferenceExpression && - ((PsiReferenceExpression)lExpression).resolve() instanceof PsiParameter) { - return false; - } - } else if (pattern instanceof PsiPrefixExpression) { - if (checkParameterModification(((PsiPrefixExpression)pattern).getOperand(), ((PsiPrefixExpression)pattern).getOperationTokenType(), - ((PsiPrefixExpression)candidate).getOperand())) return false; - } else if (pattern instanceof PsiPostfixExpression) { - if (checkParameterModification(((PsiPostfixExpression)pattern).getOperand(), ((PsiPostfixExpression)pattern).getOperationTokenType(), - ((PsiPostfixExpression)candidate).getOperand())) return false; - } - - if (pattern instanceof PsiJavaCodeReferenceElement) { - final PsiElement resolveResult1 = ((PsiJavaCodeReferenceElement)pattern).resolve(); - final PsiElement resolveResult2 = ((PsiJavaCodeReferenceElement)candidate).resolve(); - if (resolveResult1 instanceof PsiClass && resolveResult2 instanceof PsiClass) return true; - if (isUnder(resolveResult1, myPatternAsList) && isUnder(resolveResult2, candidates)) { - traverseParameter(resolveResult1, resolveResult2, match); - return match.putDeclarationCorrespondence(resolveResult1, resolveResult2); - } - final PsiElement qualifier2 = ((PsiJavaCodeReferenceElement)candidate).getQualifier(); - if (!equivalentResolve(resolveResult1, resolveResult2, qualifier2)) { - return false; - } - PsiElement qualifier1 = ((PsiJavaCodeReferenceElement)pattern).getQualifier(); - if (qualifier1 instanceof PsiReferenceExpression && qualifier2 instanceof PsiReferenceExpression && - !match.areCorrespond(((PsiReferenceExpression)qualifier1).resolve(), ((PsiReferenceExpression)qualifier2).resolve())) { - return false; - } - - } - - if (pattern instanceof PsiTypeCastExpression) { - final PsiTypeElement castTypeElement1 = ((PsiTypeCastExpression)pattern).getCastType(); - final PsiTypeElement castTypeElement2 = ((PsiTypeCastExpression)candidate).getCastType(); - if (castTypeElement1 != null && castTypeElement2 != null) { - final PsiType type1 = TypeConversionUtil.erasure(castTypeElement1.getType()); - final PsiType type2 = TypeConversionUtil.erasure(castTypeElement2.getType()); - if (!type1.equals(type2)) return false; - } - } else if (pattern instanceof PsiNewExpression) { - final PsiType type1 = ((PsiNewExpression)pattern).getType(); - final PsiType type2 = ((PsiNewExpression)candidate).getType(); - if (type1 == null || type2 == null) return false; - final PsiJavaCodeReferenceElement classReference1 = ((PsiNewExpression)pattern).getClassReference(); - final PsiJavaCodeReferenceElement classReference2 = ((PsiNewExpression)candidate).getClassReference(); - if (classReference1 != null && classReference2 != null) { - final PsiElement resolved1 = classReference1.resolve(); - final PsiElement resolved2 = classReference2.resolve(); - if (!pattern.getManager().areElementsEquivalent(resolved1, resolved2)) return false; - } - else { - if (!canTypesBeEquivalent(type1, type2)) return false; - } - } else if (pattern instanceof PsiClassObjectAccessExpression) { - final PsiTypeElement operand1 = ((PsiClassObjectAccessExpression)pattern).getOperand(); - final PsiTypeElement operand2 = ((PsiClassObjectAccessExpression)candidate).getOperand(); - return operand1.getType().equals(operand2.getType()); - } else if (pattern instanceof PsiInstanceOfExpression) { - final PsiTypeElement operand1 = ((PsiInstanceOfExpression)pattern).getCheckType(); - final PsiTypeElement operand2 = ((PsiInstanceOfExpression)candidate).getCheckType(); - if (operand1 == null || operand2 == null) return false; - if (!operand1.getType().equals(operand2.getType())) return false; - } else if (pattern instanceof PsiReturnStatement) { - final PsiReturnStatement patternReturnStatement = (PsiReturnStatement)pattern; - return matchReturnStatement(patternReturnStatement, candidate, candidates, match); - } else if (pattern instanceof PsiContinueStatement) { - match.registerReturnValue(new ContinueReturnValue()); - } else if (pattern instanceof PsiBreakStatement) { - match.registerReturnValue(new BreakReturnValue()); - }else if (pattern instanceof PsiMethodCallExpression) { - final PsiMethod patternMethod = ((PsiMethodCallExpression)pattern).resolveMethod(); - final PsiMethod candidateMethod = ((PsiMethodCallExpression)candidate).resolveMethod(); - if (patternMethod != null && candidateMethod != null) { - if (!MethodSignatureUtil.areSignaturesEqual(patternMethod, candidateMethod)) return false; - } - } else if (pattern instanceof PsiReferenceExpression) { - final PsiReferenceExpression patternRefExpr = (PsiReferenceExpression)pattern; - final PsiReferenceExpression candidateRefExpr = (PsiReferenceExpression)candidate; - final PsiExpression patternQualifier = patternRefExpr.getQualifierExpression(); - final PsiExpression candidateQualifier = candidateRefExpr.getQualifierExpression(); - if (patternQualifier == null) { - PsiClass contextClass = PsiTreeUtil.getParentOfType(pattern, PsiClass.class); - if (candidateQualifier instanceof PsiReferenceExpression) { - final PsiElement resolved = ((PsiReferenceExpression)candidateQualifier).resolve(); - if (resolved instanceof PsiClass && contextClass != null && InheritanceUtil.isInheritorOrSelf(contextClass, (PsiClass)resolved, true)) { - return true; - } - } - return contextClass != null && match.registerInstanceExpression(candidateQualifier, contextClass); - } else { - if (candidateQualifier == null) { - if (patternQualifier instanceof PsiThisExpression) { - final PsiJavaCodeReferenceElement qualifier = ((PsiThisExpression)patternQualifier).getQualifier(); - if (candidate instanceof PsiReferenceExpression) { - PsiElement contextClass = qualifier == null ? PsiTreeUtil.getParentOfType(pattern, PsiClass.class) : qualifier.resolve(); - return contextClass instanceof PsiClass && match.registerInstanceExpression(((PsiReferenceExpression)candidate).getQualifierExpression(), - (PsiClass)contextClass); - } - } else { - final PsiType type = patternQualifier.getType(); - PsiClass contextClass = type instanceof PsiClassType ? ((PsiClassType)type).resolve() : null; - try { - final Pair<PsiVariable, PsiType> parameter = patternQualifier.getUserData(PARAMETER); - - if (parameter != null) { - final PsiClass thisClass = RefactoringChangeUtil.getThisClass(parameter.first); - - if (contextClass != null && InheritanceUtil.isInheritorOrSelf(thisClass, contextClass, true)) { - contextClass = thisClass; - } - final PsiClass thisCandidate = RefactoringChangeUtil.getThisClass(candidate); - if (thisCandidate != null && InheritanceUtil.isInheritorOrSelf(thisCandidate, contextClass, true)) { - contextClass = thisCandidate; - } - return contextClass != null && match.putParameter(parameter, RefactoringChangeUtil - .createThisExpression(patternQualifier.getManager(), contextClass)); - } else if (patternQualifier instanceof PsiReferenceExpression) { - final PsiElement resolved = ((PsiReferenceExpression)patternQualifier).resolve(); - if (resolved instanceof PsiClass) { - final PsiClass classContext = PsiTreeUtil.getParentOfType(candidate, PsiClass.class); - if (classContext != null && InheritanceUtil.isInheritorOrSelf(classContext, (PsiClass)resolved, true)) { - return true; - } - } - } - - return false; - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } else { - if (patternQualifier instanceof PsiThisExpression && candidateQualifier instanceof PsiThisExpression) { - final PsiJavaCodeReferenceElement thisPatternQualifier = ((PsiThisExpression)patternQualifier).getQualifier(); - final PsiElement patternContextClass = thisPatternQualifier == null ? PsiTreeUtil.getParentOfType(patternQualifier, PsiClass.class) : thisPatternQualifier.resolve(); - final PsiJavaCodeReferenceElement thisCandidateQualifier = ((PsiThisExpression)candidateQualifier).getQualifier(); - final PsiElement candidateContextClass = thisCandidateQualifier == null ? PsiTreeUtil.getParentOfType(candidateQualifier, PsiClass.class) : thisCandidateQualifier.resolve(); - return patternContextClass == candidateContextClass; - } - } - } - } else if (pattern instanceof PsiThisExpression) { - final PsiJavaCodeReferenceElement qualifier = ((PsiThisExpression)pattern).getQualifier(); - final PsiElement contextClass = qualifier == null ? PsiTreeUtil.getParentOfType(pattern, PsiClass.class) : qualifier.resolve(); - if (candidate instanceof PsiReferenceExpression) { - final PsiElement parent = candidate.getParent(); - return parent instanceof PsiReferenceExpression && contextClass instanceof PsiClass && match.registerInstanceExpression(((PsiReferenceExpression)parent).getQualifierExpression(), - (PsiClass)contextClass); - } else if (candidate instanceof PsiThisExpression) { - final PsiJavaCodeReferenceElement candidateQualifier = ((PsiThisExpression)candidate).getQualifier(); - final PsiElement candidateContextClass = candidateQualifier == null ? PsiTreeUtil.getParentOfType(candidate, PsiClass.class) : candidateQualifier.resolve(); - return contextClass == candidateContextClass; - } - } else if (pattern instanceof PsiSuperExpression) { - final PsiJavaCodeReferenceElement qualifier = ((PsiSuperExpression)pattern).getQualifier(); - final PsiElement contextClass = qualifier == null ? PsiTreeUtil.getParentOfType(pattern, PsiClass.class) : qualifier.resolve(); - if (candidate instanceof PsiSuperExpression) { - final PsiJavaCodeReferenceElement candidateQualifier = ((PsiSuperExpression)candidate).getQualifier(); - return contextClass == (candidateQualifier != null ? candidateQualifier.resolve() : PsiTreeUtil.getParentOfType(candidate, PsiClass.class)); - } - } - - PsiElement[] children1 = getFilteredChildren(pattern); - PsiElement[] children2 = getFilteredChildren(candidate); - if (children1.length != children2.length) return false; - - - for (int i = 0; i < children1.length; i++) { - PsiElement child1 = children1[i]; - PsiElement child2 = children2[i]; - if (!matchPattern(child1, child2, candidates, match)) return false; - } - - if (children1.length == 0) { - if (pattern.getParent() instanceof PsiVariable && ((PsiVariable)pattern.getParent()).getNameIdentifier() == pattern) { - return match.putDeclarationCorrespondence(pattern.getParent(), candidate.getParent()); - } - if (!pattern.textMatches(candidate)) return false; - } - - return true; - } - - private static boolean checkParameterModification(final PsiExpression expression, - final IElementType sign, - PsiExpression candidate) { - if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).resolve() instanceof PsiParameter && - (sign.equals(JavaTokenType.MINUSMINUS)|| sign.equals(JavaTokenType.PLUSPLUS))) { - if (candidate instanceof PsiReferenceExpression && ((PsiReferenceExpression)candidate).resolve() instanceof PsiParameter) { - return false; - } - return true; - } - return false; - } - - private static void traverseParameter(PsiElement pattern, PsiElement candidate, Match match) { - if (pattern == null || candidate == null) return; - if (pattern.getUserData(PARAMETER) != null) { - final Pair<PsiVariable, PsiType> parameter = pattern.getUserData(PARAMETER); - match.putParameter(parameter, candidate); - return; - } - - PsiElement[] children1 = getFilteredChildren(pattern); - PsiElement[] children2 = getFilteredChildren(candidate); - if (children1.length != children2.length) return; - - for (int i = 0; i < children1.length; i++) { - PsiElement child1 = children1[i]; - PsiElement child2 = children2[i]; - traverseParameter(child1, child2, match); - } - } - - private boolean matchReturnStatement(final PsiReturnStatement patternReturnStatement, - PsiElement candidate, - List<PsiElement> candidates, - Match match) { - if (candidate instanceof PsiExpressionStatement) { - final PsiExpression expression = ((PsiExpressionStatement)candidate).getExpression(); - if (expression instanceof PsiAssignmentExpression) { - final PsiExpression returnValue = patternReturnStatement.getReturnValue(); - final PsiExpression rExpression = ((PsiAssignmentExpression)expression).getRExpression(); - if (!matchPattern(returnValue, rExpression, candidates, match)) return false; - final PsiExpression lExpression = ((PsiAssignmentExpression)expression).getLExpression(); - return match.registerReturnValue(new ExpressionReturnValue(lExpression)); - } - else return false; - } - else if (candidate instanceof PsiDeclarationStatement) { - final PsiElement[] declaredElements = ((PsiDeclarationStatement)candidate).getDeclaredElements(); - if (declaredElements.length != 1) return false; - if (!(declaredElements[0] instanceof PsiVariable)) return false; - final PsiVariable variable = (PsiVariable)declaredElements[0]; - if (!matchPattern(patternReturnStatement.getReturnValue(), variable.getInitializer(), candidates, match)) return false; - return match.registerReturnValue(new VariableReturnValue(variable)); - } - else if (candidate instanceof PsiReturnStatement) { - final PsiExpression returnValue = ((PsiReturnStatement)candidate).getReturnValue(); - if (myMultipleExitPoints) { - return match.registerReturnValue(new ConditionalReturnStatementValue(returnValue)); - } - else { - final PsiElement classOrLambda = PsiTreeUtil.getParentOfType(returnValue, PsiClass.class, PsiLambdaExpression.class); - final PsiElement commonParent = PsiTreeUtil.findCommonParent(match.getMatchStart(), match.getMatchEnd()); - if (classOrLambda == null || !PsiTreeUtil.isAncestor(commonParent, classOrLambda, false)) { - if (returnValue != null && !match.registerReturnValue(ReturnStatementReturnValue.INSTANCE)) return false; //do not register return value for return; statement - } - return matchPattern(patternReturnStatement.getReturnValue(), returnValue, candidates, match); - } - } - else return false; - } - - private static boolean equivalentResolve(final PsiElement resolveResult1, final PsiElement resolveResult2, PsiElement qualifier2) { - final boolean b = Comparing.equal(resolveResult1, resolveResult2); - if (b) return b; - if (resolveResult1 instanceof PsiMethod && resolveResult2 instanceof PsiMethod) { - final PsiMethod method1 = (PsiMethod)resolveResult1; - final PsiMethod method2 = (PsiMethod)resolveResult2; - if (ArrayUtil.find(method1.findSuperMethods(), method2) >= 0) return true; - if (ArrayUtil.find(method2.findSuperMethods(), method1) >= 0) return true; - - if (method1.getName().equals(method2.getName())) { - PsiClass class2 = method2.getContainingClass(); - if (qualifier2 instanceof PsiReferenceExpression) { - final PsiType type = ((PsiReferenceExpression)qualifier2).getType(); - if (type instanceof PsiClassType){ - final PsiClass resolvedClass = PsiUtil.resolveClassInType(type); - if (!(resolvedClass instanceof PsiTypeParameter)) { - class2 = resolvedClass; - } - } - } - - if (class2 != null && PsiUtil.isAccessible(method1, class2, null)) { - final PsiMethod[] methods = class2.getAllMethods(); - if (ArrayUtil.find(methods, method1) != -1) return true; - } - } - return false; - } - else { - return false; - } - } - - private static boolean isUnder(PsiElement element, List<PsiElement> parents) { - if (element == null) return false; - for (final PsiElement parent : parents) { - if (PsiTreeUtil.isAncestor(parent, element, false)) return true; - } - return false; - } - - private static PsiElement[] getFilteredChildren(PsiElement element1) { - PsiElement[] children1 = element1.getChildren(); - ArrayList<PsiElement> array = new ArrayList<PsiElement>(); - for (PsiElement child : children1) { - if (!(child instanceof PsiWhiteSpace) && !(child instanceof PsiComment)) { - if (child instanceof PsiBlockStatement) { - Collections.addAll(array, getFilteredChildren(child)); - continue; - } else if (child instanceof PsiCodeBlock) { - final PsiStatement[] statements = ((PsiCodeBlock)child).getStatements(); - if (statements.length == 1) { - array.add(statements[0]); - continue; - } - } - array.add(child); - } - } - return PsiUtilCore.toPsiElementArray(array); - } - -} diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ExpressionReturnValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ExpressionReturnValue.java deleted file mode 100644 index d8555bd75b67..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ExpressionReturnValue.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.codeInsight.PsiEquivalenceUtil; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; - -/** - * @author dsl - */ -public class ExpressionReturnValue implements ReturnValue { - private final PsiExpression myExpression; - - public ExpressionReturnValue(PsiExpression expression) { - myExpression = expression; - } - - public PsiExpression getExpression() { - return myExpression; - } - - public boolean isEquivalent(ReturnValue other) { - if (!(other instanceof ExpressionReturnValue)) return false; - return PsiEquivalenceUtil.areElementsEquivalent(myExpression, ((ExpressionReturnValue)other).myExpression); - } - - public PsiStatement createReplacement(final PsiMethod extractedMethod, final PsiMethodCallExpression methodCallExpression) - throws IncorrectOperationException { - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(methodCallExpression.getProject()).getElementFactory(); - final CodeStyleManager styleManager = CodeStyleManager.getInstance(methodCallExpression.getProject()); - PsiExpressionStatement expressionStatement; - expressionStatement = (PsiExpressionStatement)elementFactory.createStatementFromText("x = y();", null); - expressionStatement = (PsiExpressionStatement)styleManager.reformat(expressionStatement); - final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expressionStatement.getExpression(); - assignmentExpression.getLExpression().replace(getExpression()); - assignmentExpression.getRExpression().replace(methodCallExpression); - return expressionStatement; - } -} diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/FieldReturnValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/FieldReturnValue.java deleted file mode 100644 index 6ddb9e6f403f..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/FieldReturnValue.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; - -/** - * @author dsl - */ -public class FieldReturnValue implements ReturnValue { - private final PsiField myField; - - public FieldReturnValue(PsiField psiField) { - myField = psiField; - } - - public boolean isEquivalent(ReturnValue other) { - if (!(other instanceof FieldReturnValue)) return false; - return myField == ((FieldReturnValue)other).myField; - } - - public PsiField getField() { - return myField; - } - - public PsiStatement createReplacement(final PsiMethod extractedMethod, final PsiMethodCallExpression methodCallExpression) throws IncorrectOperationException { - - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(methodCallExpression.getProject()).getElementFactory(); - final CodeStyleManager styleManager = CodeStyleManager.getInstance(methodCallExpression.getProject()); - PsiExpressionStatement expressionStatement; - expressionStatement = (PsiExpressionStatement)elementFactory.createStatementFromText("x = y();", null); - expressionStatement = (PsiExpressionStatement)styleManager.reformat(expressionStatement); - final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expressionStatement.getExpression(); - assignmentExpression.getLExpression().replace(elementFactory.createExpressionFromText(myField.getName(), myField)); - assignmentExpression.getRExpression().replace(methodCallExpression); - return expressionStatement; - - } -}
\ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/GotoReturnValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/GotoReturnValue.java deleted file mode 100644 index 7727411e3f1d..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/GotoReturnValue.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * User: anna - * Date: 24-Oct-2008 - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.Nullable; - -public abstract class GotoReturnValue implements ReturnValue { - @Nullable - public PsiStatement createReplacement(final PsiMethod extractedMethod, final PsiMethodCallExpression methodCallExpression) throws - IncorrectOperationException { - if (!TypeConversionUtil.isBooleanType(extractedMethod.getReturnType())) return null; - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(methodCallExpression.getProject()).getElementFactory(); - final PsiIfStatement statement = (PsiIfStatement)elementFactory.createStatementFromText(getGotoStatement(), null); - final PsiExpression condition = statement.getCondition(); - assert condition != null; - condition.replace(methodCallExpression); - return (PsiStatement)CodeStyleManager.getInstance(statement.getManager().getProject()).reformat(statement); - } - - @NonNls - public abstract String getGotoStatement(); -}
\ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/Match.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/Match.java deleted file mode 100644 index ef633f70fa50..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/Match.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.codeInsight.PsiEquivalenceUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.controlFlow.*; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.HashMap; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -/** - * @author dsl - */ -public final class Match { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.duplicates.Match"); - private final PsiElement myMatchStart; - private final PsiElement myMatchEnd; - private final Map<PsiVariable, List<PsiElement>> myParameterValues = new HashMap<PsiVariable, List<PsiElement>>(); - private final Map<PsiVariable, ArrayList<PsiElement>> myParameterOccurrences = new HashMap<PsiVariable, ArrayList<PsiElement>>(); - private final Map<PsiElement, PsiElement> myDeclarationCorrespondence = new HashMap<PsiElement, PsiElement>(); - private ReturnValue myReturnValue = null; - private Ref<PsiExpression> myInstanceExpression = null; - final Map<PsiVariable, PsiType> myChangedParams = new HashMap<PsiVariable, PsiType>(); - private final boolean myIgnoreParameterTypes; - - Match(PsiElement start, PsiElement end, boolean ignoreParameterTypes) { - LOG.assertTrue(start.getParent() == end.getParent()); - myMatchStart = start; - myMatchEnd = end; - myIgnoreParameterTypes = ignoreParameterTypes; - } - - - public PsiElement getMatchStart() { - return myMatchStart; - } - - public PsiElement getMatchEnd() { - return myMatchEnd; - } - - @Nullable - public List<PsiElement> getParameterValues(PsiVariable parameter) { - return myParameterValues.get(parameter); - } - - /** - * Returns either local variable declaration or expression - * @param outputParameter - * @return - */ - public ReturnValue getOutputVariableValue(PsiVariable outputParameter) { - final PsiElement decl = myDeclarationCorrespondence.get(outputParameter); - if (decl instanceof PsiVariable) { - return new VariableReturnValue((PsiVariable)decl); - } - final List<PsiElement> parameterValue = getParameterValues(outputParameter); - if (parameterValue != null && parameterValue.size() == 1 && parameterValue.get(0) instanceof PsiExpression) { - return new ExpressionReturnValue((PsiExpression) parameterValue.get(0)); - } - else { - return null; - } - } - - - boolean putParameter(Pair<PsiVariable, PsiType> parameter, PsiElement value) { - final PsiVariable psiVariable = parameter.first; - - if (myDeclarationCorrespondence.get(psiVariable) == null) { - final boolean [] valueDependsOnReplacedScope = new boolean[1]; - value.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceExpression(final PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement resolved = expression.resolve(); - if (resolved != null && Comparing.equal(resolved.getContainingFile(), getMatchEnd().getContainingFile())) { - final TextRange range = checkRange(resolved); - final TextRange startRange = checkRange(getMatchStart()); - final TextRange endRange = checkRange(getMatchEnd()); - if (startRange.getStartOffset() <= range.getStartOffset() && range.getEndOffset() <= endRange.getEndOffset()) { - valueDependsOnReplacedScope[0] = true; - } - } - } - }); - if (valueDependsOnReplacedScope[0]) return false; - } - - final List<PsiElement> currentValue = myParameterValues.get(psiVariable); - final boolean isVararg = psiVariable instanceof PsiParameter && ((PsiParameter)psiVariable).isVarArgs(); - if (!(value instanceof PsiExpression)) return false; - final PsiType type = ((PsiExpression)value).getType(); - final PsiType parameterType = parameter.second; - if (type == null) return false; - if (currentValue == null) { - if (parameterType instanceof PsiClassType && ((PsiClassType)parameterType).resolve() instanceof PsiTypeParameter) { - final PsiTypeParameter typeParameter = (PsiTypeParameter)((PsiClassType)parameterType).resolve(); - LOG.assertTrue(typeParameter != null); - for (PsiClassType classType : typeParameter.getExtendsListTypes()) { - if (!classType.isAssignableFrom(type)) return false; - } - } - else { - if (isVararg) { - if (!((PsiEllipsisType)psiVariable.getType()).getComponentType().isAssignableFrom(type) && !((PsiEllipsisType)psiVariable.getType()).toArrayType().equals(type)) { - myChangedParams.put(psiVariable, new PsiEllipsisType(parameterType)); - } - } else { - if (!myIgnoreParameterTypes && !parameterType.isAssignableFrom(type)) return false; //todo - } - } - final List<PsiElement> values = new ArrayList<PsiElement>(); - values.add(value); - myParameterValues.put(psiVariable, values); - final ArrayList<PsiElement> elements = new ArrayList<PsiElement>(); - myParameterOccurrences.put(psiVariable, elements); - return true; - } - else { - for (PsiElement val : currentValue) { - if (!isVararg && !PsiEquivalenceUtil.areElementsEquivalent(val, value)) { - return false; - } - } - if (isVararg) { - if (!parameterType.isAssignableFrom(type)) return false; - if (!((PsiEllipsisType)psiVariable.getType()).toArrayType().equals(type)){ - currentValue.add(value); - } - } - myParameterOccurrences.get(psiVariable).add(value); - return true; - } - } - - public ReturnValue getReturnValue() { - return myReturnValue; - } - - boolean registerReturnValue(ReturnValue returnValue) { - if (myReturnValue == null) { - myReturnValue = returnValue; - return true; - } - else { - return myReturnValue.isEquivalent(returnValue); - } - } - - boolean registerInstanceExpression(PsiExpression instanceExpression, final PsiClass contextClass) { - if (myInstanceExpression == null) { - if (instanceExpression != null) { - final PsiType type = instanceExpression.getType(); - if (!(type instanceof PsiClassType)) return false; - final PsiClass hisClass = ((PsiClassType) type).resolve(); - if (hisClass == null || !InheritanceUtil.isInheritorOrSelf(hisClass, contextClass, true)) return false; - } - myInstanceExpression = Ref.create(instanceExpression); - return true; - } - else { - if (myInstanceExpression.get() == null) { - myInstanceExpression.set(instanceExpression); - - return instanceExpression == null; - } - else { - if (instanceExpression != null) { - return PsiEquivalenceUtil.areElementsEquivalent(instanceExpression, myInstanceExpression.get()); - } - else { - return myInstanceExpression.get() == null || myInstanceExpression.get() instanceof PsiThisExpression; - } - } - } - } - - boolean putDeclarationCorrespondence(PsiElement patternDeclaration, @NotNull PsiElement matchDeclaration) { - PsiElement originalValue = myDeclarationCorrespondence.get(patternDeclaration); - if (originalValue == null) { - myDeclarationCorrespondence.put(patternDeclaration, matchDeclaration); - return true; - } - else { - return originalValue == matchDeclaration; - } - } - - boolean areCorrespond(PsiElement patternDeclaration, PsiElement matchDeclaration) { - if (matchDeclaration == null || patternDeclaration == null) return false; - PsiElement originalValue = myDeclarationCorrespondence.get(patternDeclaration); - return originalValue == null || originalValue == matchDeclaration; - } - - private PsiElement replaceWith(final PsiStatement statement) throws IncorrectOperationException { - final PsiElement matchStart = getMatchStart(); - final PsiElement matchEnd = getMatchEnd(); - final PsiElement element = matchStart.getParent().addBefore(statement, matchStart); - matchStart.getParent().deleteChildRange(matchStart, matchEnd); - return element; - } - - public PsiElement replaceByStatement(final PsiMethod extractedMethod, final PsiMethodCallExpression methodCallExpression, final PsiVariable outputVariable) throws IncorrectOperationException { - PsiStatement statement = null; - if (outputVariable != null) { - ReturnValue returnValue = getOutputVariableValue(outputVariable); - if (returnValue == null && outputVariable instanceof PsiField) { - returnValue = new FieldReturnValue((PsiField)outputVariable); - } - if (returnValue == null) return null; - statement = returnValue.createReplacement(extractedMethod, methodCallExpression); - } - else if (getReturnValue() != null) { - statement = getReturnValue().createReplacement(extractedMethod, methodCallExpression); - } - if (statement == null) { - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(methodCallExpression.getProject()).getElementFactory(); - PsiExpressionStatement expressionStatement = (PsiExpressionStatement) elementFactory.createStatementFromText("x();", null); - final CodeStyleManager styleManager = CodeStyleManager.getInstance(methodCallExpression.getManager()); - expressionStatement = (PsiExpressionStatement)styleManager.reformat(expressionStatement); - expressionStatement.getExpression().replace(methodCallExpression); - statement = expressionStatement; - } - return replaceWith(statement); - } - - public PsiExpression getInstanceExpression() { - if (myInstanceExpression == null) { - return null; - } - else { - return myInstanceExpression.get(); - } - } - - public PsiElement replace(final PsiMethod extractedMethod, final PsiMethodCallExpression methodCallExpression, PsiVariable outputVariable) throws IncorrectOperationException { - declareLocalVariables(); - if (getMatchStart() == getMatchEnd() && getMatchStart() instanceof PsiExpression) { - return replaceWithExpression(methodCallExpression); - } - else { - return replaceByStatement(extractedMethod, methodCallExpression, outputVariable); - } - } - - private void declareLocalVariables() throws IncorrectOperationException { - final PsiElement codeFragment = ControlFlowUtil.findCodeFragment(getMatchStart()); - try { - final Project project = getMatchStart().getProject(); - final ControlFlow controlFlow = ControlFlowFactory.getInstance(project) - .getControlFlow(codeFragment, new LocalsControlFlowPolicy(codeFragment)); - final int endOffset = controlFlow.getEndOffset(getMatchEnd()); - final int startOffset = controlFlow.getStartOffset(getMatchStart()); - final List<PsiVariable> usedVariables = ControlFlowUtil.getUsedVariables(controlFlow, endOffset, controlFlow.getSize()); - Collection<ControlFlowUtil.VariableInfo> reassigned = ControlFlowUtil.getInitializedTwice(controlFlow, endOffset, controlFlow.getSize()); - final Collection<PsiVariable> outVariables = ControlFlowUtil.getWrittenVariables(controlFlow, startOffset, endOffset, false); - for (PsiVariable variable : usedVariables) { - if (!outVariables.contains(variable)) { - final PsiIdentifier identifier = variable.getNameIdentifier(); - if (identifier != null) { - final TextRange textRange = checkRange(identifier); - final TextRange startRange = checkRange(getMatchStart()); - final TextRange endRange = checkRange(getMatchEnd()); - if (textRange.getStartOffset() >= startRange.getStartOffset() && textRange.getEndOffset() <= endRange.getEndOffset()) { - final String name = variable.getName(); - LOG.assertTrue(name != null); - PsiDeclarationStatement statement = - JavaPsiFacade.getInstance(project).getElementFactory().createVariableDeclarationStatement(name, variable.getType(), null); - if (reassigned.contains(new ControlFlowUtil.VariableInfo(variable, null))) { - final PsiElement[] psiElements = statement.getDeclaredElements(); - final PsiModifierList modifierList = ((PsiVariable)psiElements[0]).getModifierList(); - LOG.assertTrue(modifierList != null); - modifierList.setModifierProperty(PsiModifier.FINAL, false); - } - getMatchStart().getParent().addBefore(statement, getMatchStart()); - } - } - } - } - } - catch (AnalysisCanceledException e) { - //skip match - } - } - - private static TextRange checkRange(final PsiElement element) { - final TextRange endRange = element.getTextRange(); - LOG.assertTrue(endRange != null, element); - return endRange; - } - - public PsiElement replaceWithExpression(final PsiExpression psiExpression) throws IncorrectOperationException { - final PsiElement matchStart = getMatchStart(); - LOG.assertTrue(matchStart == getMatchEnd()); - if (psiExpression instanceof PsiMethodCallExpression && matchStart instanceof PsiReferenceExpression && matchStart.getParent() instanceof PsiMethodCallExpression) { - return JavaCodeStyleManager.getInstance(matchStart.getProject()).shortenClassReferences(matchStart.replace(((PsiMethodCallExpression)psiExpression).getMethodExpression())); - } - return JavaCodeStyleManager.getInstance(matchStart.getProject()).shortenClassReferences(matchStart.replace(psiExpression)); - } - - TextRange getTextRange() { - final TextRange startRange = checkRange(getMatchStart()); - final TextRange endRange = checkRange(getMatchEnd()); - return new TextRange(startRange.getStartOffset(), endRange.getEndOffset()); - } - - @Nullable - public PsiType getChangedReturnType(final PsiMethod psiMethod) { - final PsiType returnType = psiMethod.getReturnType(); - if (returnType != null) { - PsiElement parent = getMatchEnd().getParent(); - - if (parent instanceof PsiExpression) { - if (parent instanceof PsiMethodCallExpression) { - JavaResolveResult result = ((PsiMethodCallExpression)parent).resolveMethodGenerics(); - final PsiMethod method = (PsiMethod)result.getElement(); - if (method != null) { - PsiType type = method.getReturnType(); - if (type != null) { - type = result.getSubstitutor().substitute(type); - if (weakerType(psiMethod, returnType, type)) { - return type; - } - } - } - } - else if (parent instanceof PsiReferenceExpression) { - final JavaResolveResult result = ((PsiReferenceExpression)parent).advancedResolve(false); - final PsiElement element = result.getElement(); - if (element instanceof PsiMember) { - final PsiClass psiClass = ((PsiMember)element).getContainingClass(); - if (psiClass != null && psiClass.isPhysical()) { - final JavaPsiFacade facade = JavaPsiFacade.getInstance(parent.getProject()); - final PsiClassType expressionType = facade.getElementFactory().createType(psiClass, result.getSubstitutor()); - if (weakerType(psiMethod, returnType, expressionType)) { - return expressionType; - } - } - } - } - } - else if (parent instanceof PsiExpressionList) { - final PsiExpression[] expressions = ((PsiExpressionList)parent).getExpressions(); - final PsiElement call = parent.getParent(); - if (call instanceof PsiMethodCallExpression) { - final JavaResolveResult result = ((PsiMethodCallExpression)call).resolveMethodGenerics(); - final PsiMethod method = (PsiMethod)result.getElement(); - if (method != null) { - final int idx = ArrayUtil.find(expressions, getMatchEnd()); - final PsiParameter[] psiParameters = method.getParameterList().getParameters(); - if (idx >= 0 && idx < psiParameters.length) { - PsiType type = result.getSubstitutor().substitute(psiParameters[idx].getType()); - if (type instanceof PsiEllipsisType) { - type = ((PsiEllipsisType)type).getComponentType(); - } - if (weakerType(psiMethod, returnType, type)){ - return type; - } - } - } - } - } - else if (parent instanceof PsiLocalVariable) { - final PsiType localVariableType = ((PsiLocalVariable)parent).getType(); - if (weakerType(psiMethod, returnType, localVariableType)) return localVariableType; - } - else if (parent instanceof PsiReturnStatement) { - final PsiMethod replacedMethod = PsiTreeUtil.getParentOfType(parent, PsiMethod.class); - LOG.assertTrue(replacedMethod != null); - final PsiType replacedMethodReturnType = replacedMethod.getReturnType(); - if (weakerType(psiMethod, returnType, replacedMethodReturnType)) { - return replacedMethodReturnType; - } - } - - } - return null; - } - - private static boolean weakerType(final PsiMethod psiMethod, final PsiType returnType, final PsiType currentType) { - final PsiTypeParameter[] typeParameters = psiMethod.getTypeParameters(); - final PsiSubstitutor substitutor = - JavaPsiFacade.getInstance(psiMethod.getProject()).getResolveHelper().inferTypeArguments(typeParameters, new PsiType[]{returnType}, new PsiType[]{currentType}, PsiUtil.getLanguageLevel(psiMethod)); - - return !TypeConversionUtil.isAssignable(currentType, substitutor.substitute(returnType)); - } - - public PsiFile getFile() { - return getMatchStart().getContainingFile(); - } -} diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ReturnStatementReturnValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ReturnStatementReturnValue.java deleted file mode 100644 index ea66c8636463..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ReturnStatementReturnValue.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; - -/** - * @author dsl - */ -public class ReturnStatementReturnValue implements ReturnValue { - public static final ReturnStatementReturnValue INSTANCE = new ReturnStatementReturnValue(); - - private ReturnStatementReturnValue() {} - - public boolean isEquivalent(ReturnValue other) { - return other instanceof ReturnStatementReturnValue; - } - - public PsiStatement createReplacement(final PsiMethod extractedMethod, final PsiMethodCallExpression methodCallExpression) throws IncorrectOperationException { - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(methodCallExpression.getProject()).getElementFactory(); - final CodeStyleManager styleManager = CodeStyleManager.getInstance(methodCallExpression.getProject()); - PsiReturnStatement returnStatement = (PsiReturnStatement)elementFactory.createStatementFromText("return x;", null); - returnStatement = (PsiReturnStatement) styleManager.reformat(returnStatement); - returnStatement.getReturnValue().replace(methodCallExpression); - return returnStatement; - } -} diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ReturnValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ReturnValue.java deleted file mode 100644 index 896ea60c3f98..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/ReturnValue.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiMethodCallExpression; -import com.intellij.psi.PsiStatement; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.Nullable; - -/** - * @author dsl - */ -public interface ReturnValue { - boolean isEquivalent(ReturnValue other); - - @Nullable - PsiStatement createReplacement(final PsiMethod extractedMethod, PsiMethodCallExpression methodCallExpression) throws IncorrectOperationException; -} diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/VariableReturnValue.java b/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/VariableReturnValue.java deleted file mode 100644 index 75edb10c4853..000000000000 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/duplicates/VariableReturnValue.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.refactoring.util.duplicates; - -import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; - -/** - * @author dsl - */ -public class VariableReturnValue implements ReturnValue { - private final PsiVariable myVariable; - - public VariableReturnValue(PsiVariable variable) { - myVariable = variable; - } - - public boolean isEquivalent(ReturnValue other) { - if (!(other instanceof VariableReturnValue)) return false; - return myVariable == ((VariableReturnValue)other).myVariable; - } - - public PsiVariable getVariable() { - return myVariable; - } - - public PsiStatement createReplacement(final PsiMethod extractedMethod, final PsiMethodCallExpression methodCallExpression) throws IncorrectOperationException { - final PsiDeclarationStatement statement; - - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(methodCallExpression.getProject()).getElementFactory(); - final CodeStyleManager styleManager = CodeStyleManager.getInstance(methodCallExpression.getProject()); - statement = (PsiDeclarationStatement)styleManager.reformat( - elementFactory.createVariableDeclarationStatement(myVariable.getName(), myVariable.getType(), methodCallExpression) - ); - ((PsiVariable)statement.getDeclaredElements()[0]).getModifierList().replace(myVariable.getModifierList()); - return statement; - } -} |