public void testRunningAllInPackage() throws IOException, ExecutionException { Module module1 = getModule1(); GlobalSearchScope module1AndLibraries = GlobalSearchScope.moduleWithLibrariesScope(module1); PsiClass testCase = findClass(TestCase.class.getName(), module1AndLibraries); PsiClass psiClass = findTestA(module1); PsiClass psiClass2 = findTestA(getModule2()); PsiClass derivedTest = findClass(module1, "test1.DerivedTest"); PsiClass baseTestCase = findClass("junit.framework.ThirdPartyClass", module1AndLibraries); PsiClass testB = findClass(getModule3(), "test1.TestB"); assertNotNull(testCase); assertNotNull(derivedTest); assertNotNull(psiClass); assertTrue(psiClass.isInheritor(testCase, false)); assertEquals(baseTestCase, derivedTest.getSuperClass()); assertTrue(baseTestCase.isInheritor(testCase, true)); assertTrue(derivedTest.isInheritor(testCase, true)); PsiPackage psiPackage = JUnitUtil.getContainingPackage(psiClass); JUnitConfiguration configuration = createConfiguration(psiPackage, module1); JavaParameters parameters = checkCanRun(configuration); List<String> lines = extractAllInPackageTests(parameters, psiPackage); Assertion.compareUnordered( new Object[] { "", psiClass.getQualifiedName(), psiClass2.getQualifiedName(), derivedTest.getQualifiedName(), RT_INNER_TEST_NAME, testB.getQualifiedName() }, lines); }
private void doMoveClass(PsiSubstitutor substitutor, MemberInfo info) { PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); PsiClass aClass = (PsiClass) info.getMember(); if (Boolean.FALSE.equals(info.getOverrides())) { final PsiReferenceList sourceReferenceList = info.getSourceReferenceList(); LOG.assertTrue(sourceReferenceList != null); PsiJavaCodeReferenceElement ref = mySourceClass.equals(sourceReferenceList.getParent()) ? RefactoringUtil.removeFromReferenceList(sourceReferenceList, aClass) : RefactoringUtil.findReferenceToClass(sourceReferenceList, aClass); if (ref != null && !myTargetSuperClass.isInheritor(aClass, false)) { RefactoringUtil.replaceMovedMemberTypeParameters( ref, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); final PsiReferenceList referenceList = myIsTargetInterface ? myTargetSuperClass.getExtendsList() : myTargetSuperClass.getImplementsList(); assert referenceList != null; referenceList.add(ref); } } else { RefactoringUtil.replaceMovedMemberTypeParameters( aClass, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); fixReferencesToStatic(aClass); final PsiMember movedElement = (PsiMember) myTargetSuperClass.add( convertClassToLanguage(aClass, myTargetSuperClass.getLanguage())); myMembersAfterMove.add(movedElement); aClass.delete(); } }
@Nullable private static PsiMethodCallExpression checkMethodResolvable( PsiMethodCallExpression methodCall, PsiMethod targetMethod, PsiReferenceExpression context, PsiClass aClass) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(targetMethod.getProject()).getElementFactory(); final PsiElement resolved = methodCall.getMethodExpression().resolve(); if (resolved != targetMethod) { PsiClass containingClass; if (resolved instanceof PsiMethod) { containingClass = ((PsiMethod) resolved).getContainingClass(); } else if (resolved instanceof PsiClass) { containingClass = (PsiClass) resolved; } else { return null; } if (containingClass != null && containingClass.isInheritor(aClass, false)) { final PsiExpression newMethodExpression = factory.createExpressionFromText("super." + targetMethod.getName(), context); methodCall.getMethodExpression().replace(newMethodExpression); } else { methodCall = null; } } return methodCall; }
public static boolean inheritsITestListener(@NotNull PsiClass psiClass) { final Project project = psiClass.getProject(); final PsiClass aListenerClass = JavaPsiFacade.getInstance(project) .findClass(ITestNGListener.class.getName(), GlobalSearchScope.allScope(project)); return aListenerClass != null && psiClass.isInheritor(aListenerClass, true); }
public void testEnum() throws Exception { setupLoadingFilter(); final PsiClass enumClass = myJavaFacade.findClass("enums.OurEnum", GlobalSearchScope.moduleScope(myModule)); assertNotNull(enumClass); assertTrue(enumClass.isEnum()); final PsiClass superClass = enumClass.getSuperClass(); assertNotNull(superClass); assertEquals("java.lang.Enum", superClass.getQualifiedName()); assertTrue(enumClass.isInheritor(superClass, false)); final PsiClassType[] superTypes = enumClass.getSuperTypes(); assertEquals(1, superTypes.length); assertEquals("java.lang.Enum<enums.OurEnum>", superTypes[0].getCanonicalText()); final PsiClass[] supers = enumClass.getSupers(); assertEquals(1, supers.length); assertEquals("java.lang.Enum", supers[0].getQualifiedName()); final PsiClassType[] extendsListTypes = enumClass.getExtendsListTypes(); assertEquals(1, extendsListTypes.length); assertEquals("java.lang.Enum<enums.OurEnum>", extendsListTypes[0].getCanonicalText()); final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, enumClass, PsiSubstitutor.EMPTY); assertEquals( "java.lang.Enum<enums.OurEnum>", myJavaFacade .getElementFactory() .createType(superClass, superClassSubstitutor) .getCanonicalText()); teardownLoadingFilter(); }
private void checkSimpleClasses(PsiType ltype, PsiType rtype, GrBinaryExpression expression) { if (!(rtype instanceof PsiClassType)) return; if (!(ltype instanceof PsiClassType)) return; PsiClass lclass = ((PsiClassType) ltype).resolve(); PsiClass rclass = ((PsiClassType) rtype).resolve(); if (lclass == null || rclass == null) return; if (expression.getManager().areElementsEquivalent(lclass, rclass)) return; if (lclass.isInterface() || rclass.isInterface()) return; if (lclass.isInheritor(rclass, true) || rclass.isInheritor(lclass, true)) return; registerError(expression, ltype, rtype); }
private static void addSuper(final Set<PsiClass> supers, final PsiClass classToAdd) { for (Iterator<PsiClass> iterator = supers.iterator(); iterator.hasNext(); ) { PsiClass superClass = iterator.next(); if (InheritanceUtil.isInheritorOrSelf(superClass, classToAdd, true)) return; if (classToAdd.isInheritor(superClass, true)) iterator.remove(); } supers.add(classToAdd); }
private boolean isAmbiguousInherited(PsiClass containingClass1) { PsiClass psiClass = PsiTreeUtil.getParentOfType(myPlace, PsiClass.class); while (psiClass != null) { if (psiClass.isInheritor(containingClass1, false)) { return true; } psiClass = psiClass.getContainingClass(); } return false; }
public String getConflictingConjunctsMessage() { final PsiType[] conjuncts = getConjuncts(); for (int i = 0; i < conjuncts.length; i++) { PsiClass conjunct = PsiUtil.resolveClassInClassTypeOnly(conjuncts[i]); if (conjunct != null && !conjunct.isInterface()) { for (int i1 = i + 1; i1 < conjuncts.length; i1++) { PsiClass oppositeConjunct = PsiUtil.resolveClassInClassTypeOnly(conjuncts[i1]); if (oppositeConjunct != null && !oppositeConjunct.isInterface()) { if (!conjunct.isInheritor(oppositeConjunct, true) && !oppositeConjunct.isInheritor(conjunct, true)) { return conjuncts[i].getPresentableText() + " and " + conjuncts[i1].getPresentableText(); } } } } } return null; }
@Nullable private ProblemDescriptor createDescription( @NotNull PsiTypeCastExpression cast, @NotNull InspectionManager manager, boolean onTheFly) { PsiExpression operand = cast.getOperand(); PsiTypeElement castType = cast.getCastType(); if (operand == null || castType == null) return null; PsiElement parent = cast.getParent(); while (parent instanceof PsiParenthesizedExpression) { parent = parent.getParent(); } if (parent instanceof PsiReferenceExpression) { if (IGNORE_ANNOTATED_METHODS) { final PsiElement gParent = parent.getParent(); if (gParent instanceof PsiMethodCallExpression) { final PsiMethod psiMethod = ((PsiMethodCallExpression) gParent).resolveMethod(); if (psiMethod != null && NullableNotNullManager.isNotNull(psiMethod)) { final PsiClass superClass = PsiUtil.resolveClassInType(operand.getType()); final PsiClass containingClass = psiMethod.getContainingClass(); if (containingClass != null && superClass != null && containingClass.isInheritor(superClass, true)) { for (PsiMethod method : psiMethod.findSuperMethods(superClass)) { if (NullableNotNullManager.isNullable(method)) { return null; } } } } } } } else if (parent instanceof PsiExpressionList) { final PsiElement gParent = parent.getParent(); if (gParent instanceof PsiMethodCallExpression && IGNORE_SUSPICIOUS_METHOD_CALLS) { final String message = SuspiciousCollectionsMethodCallsInspection.getSuspiciousMethodCallMessage( (PsiMethodCallExpression) gParent, operand.getType(), true, new ArrayList<PsiMethod>(), new IntArrayList()); if (message != null) { return null; } } } String message = InspectionsBundle.message( "inspection.redundant.cast.problem.descriptor", "<code>" + operand.getText() + "</code>", "<code>#ref</code> #loc"); return manager.createProblemDescriptor( castType, message, myQuickFixAction, ProblemHighlightType.LIKE_UNUSED_SYMBOL, onTheFly); }
@Override public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) { for (PsiType type : getBounds(InferenceBound.UPPER)) { PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(type); if (psiClass != null) { if (getManager().areElementsEquivalent(baseClass, psiClass)) return true; if (checkDeep && psiClass.isInheritor(baseClass, true)) return true; } } return super.isInheritor(baseClass, checkDeep); }
/** * Returns true if the given associated activity class is either found in the given set of * classes, or (less likely) extends any of the classes in that set */ private static boolean containsOrExtends( @NotNull Set<PsiClass> resolvedClasses, @NotNull PsiClass relatedActivity) { if (resolvedClasses.contains(relatedActivity)) { return true; } for (PsiClass resolvedClass : resolvedClasses) { if (relatedActivity.isInheritor(resolvedClass, false)) { return true; } } return false; }
private static void getLeastUpperClassesInner( PsiClass aClass, PsiClass bClass, Set<PsiClass> supers, Set<PsiClass> visited) { if (bClass.isInheritor(aClass, true)) { addSuper(supers, aClass); } else { final PsiClass[] aSupers = aClass.getSupers(); for (PsiClass aSuper : aSupers) { if (visited.add(aSuper)) { getLeastUpperClassesInner(aSuper, bClass, supers, visited); } } } }
public static boolean isSuperMethod( @NotNull PsiMethod superMethodCandidate, @NotNull PsiMethod derivedMethod) { PsiClass superClassCandidate = superMethodCandidate.getContainingClass(); PsiClass derivedClass = derivedMethod.getContainingClass(); if (derivedClass == null || superClassCandidate == null) return false; if (!derivedClass.isInheritor(superClassCandidate, true)) return false; final PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor( superClassCandidate, derivedClass, PsiSubstitutor.EMPTY); final MethodSignature superSignature = superMethodCandidate.getSignature(superSubstitutor); final MethodSignature derivedSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); return isSubsignature(superSignature, derivedSignature); }
@Override public ProblemDescriptor[] checkClass( @NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) { final Project project = aClass.getProject(); final PsiIdentifier nameIdentifier = aClass.getNameIdentifier(); final Module module = ModuleUtil.findModuleForPsiElement(aClass); if (nameIdentifier == null || module == null || !PsiUtil.isInstanciatable(aClass)) return null; final PsiClass base = JavaPsiFacade.getInstance(project) .findClass(INTENTION, GlobalSearchScope.allScope(project)); if (base == null || !aClass.isInheritor(base, true)) return null; String descriptionDir = getDescriptionDirName(aClass); if (StringUtil.isEmptyOrSpaces(descriptionDir)) { return null; } for (PsiDirectory description : getIntentionDescriptionsDirs(module)) { PsiDirectory dir = description.findSubdirectory(descriptionDir); if (dir == null) continue; final PsiFile descr = dir.findFile("description.html"); if (descr != null) { if (!hasBeforeAndAfterTemplate(dir.getVirtualFile())) { PsiElement problem = aClass.getNameIdentifier(); ProblemDescriptor problemDescriptor = manager.createProblemDescriptor( problem == null ? nameIdentifier : problem, "Intention must have 'before.*.template' and 'after.*.template' beside 'description.html'", isOnTheFly, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); return new ProblemDescriptor[] {problemDescriptor}; } return null; } } final PsiElement problem = aClass.getNameIdentifier(); final ProblemDescriptor problemDescriptor = manager.createProblemDescriptor( problem == null ? nameIdentifier : problem, "Intention does not have a description", isOnTheFly, new LocalQuickFix[] {new CreateHtmlDescriptionFix(descriptionDir, module, true)}, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); return new ProblemDescriptor[] {problemDescriptor}; }
private Domination dominates( PsiClass aClass, boolean accessible, String fqName, ClassCandidateInfo info) { final PsiClass otherClass = info.getElement(); assert otherClass != null; String otherQName = otherClass.getQualifiedName(); if (fqName.equals(otherQName)) { return Domination.DOMINATED_BY; } final PsiClass containingClass1 = aClass.getContainingClass(); final PsiClass containingClass2 = otherClass.getContainingClass(); if (containingClass1 != null && containingClass2 != null && containingClass2.isInheritor(containingClass1, true) && !isImported(myCurrentFileContext)) { // shadowing return Domination.DOMINATED_BY; } boolean infoAccessible = info.isAccessible(); if (infoAccessible && !accessible) { return Domination.DOMINATED_BY; } if (!infoAccessible && accessible) { return Domination.DOMINATES; } // everything wins over class from default package boolean isDefault = StringUtil.getPackageName(fqName).length() == 0; boolean otherDefault = otherQName != null && StringUtil.getPackageName(otherQName).length() == 0; if (isDefault && !otherDefault) { return Domination.DOMINATED_BY; } if (!isDefault && otherDefault) { return Domination.DOMINATES; } // single import wins over on-demand boolean myOnDemand = isOnDemand(myCurrentFileContext, aClass); boolean otherOnDemand = isOnDemand(info.getCurrentFileResolveScope(), otherClass); if (myOnDemand && !otherOnDemand) { return Domination.DOMINATED_BY; } if (!myOnDemand && otherOnDemand) { return Domination.DOMINATES; } return Domination.EQUAL; }
@Override public ProblemDescriptor[] checkClass( @NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) { final Project project = aClass.getProject(); final PsiIdentifier nameIdentifier = aClass.getNameIdentifier(); final Module module = ModuleUtilCore.findModuleForPsiElement(aClass); if (nameIdentifier == null || module == null || !PsiUtil.isInstantiable(aClass)) return null; final PsiClass base = JavaPsiFacade.getInstance(project).findClass(getClassName(), aClass.getResolveScope()); if (base == null || !aClass.isInheritor(base, true)) return null; String descriptionDir = DescriptionCheckerUtil.getDescriptionDirName(aClass); if (StringUtil.isEmptyOrSpaces(descriptionDir)) { return null; } for (PsiDirectory description : getDescriptionsDirs(module)) { PsiDirectory dir = description.findSubdirectory(descriptionDir); if (dir == null) continue; final PsiFile descr = dir.findFile("description.html"); if (descr != null) { if (!hasBeforeAndAfterTemplate(dir.getVirtualFile())) { PsiElement problem = aClass.getNameIdentifier(); ProblemDescriptor problemDescriptor = manager.createProblemDescriptor( problem == null ? nameIdentifier : problem, getHasNotBeforeAfterError(), isOnTheFly, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false); return new ProblemDescriptor[] {problemDescriptor}; } return null; } } final PsiElement problem = aClass.getNameIdentifier(); final ProblemDescriptor problemDescriptor = manager.createProblemDescriptor( problem == null ? nameIdentifier : problem, getHasNotDescriptionError(), isOnTheFly, new LocalQuickFix[] {getFix(module, descriptionDir)}, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); return new ProblemDescriptor[] {problemDescriptor}; }
@Override protected void visitClassMemberReferenceElement(GrMember classMember, GrReferenceElement ref) { if (classMember != null && !willBeMoved(classMember, myMovedMembers)) { final PsiClass containingClass = classMember.getContainingClass(); if (containingClass != null && !PsiUtil.isAccessibleFromPackage(classMember, myTargetPackage) && (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || classMember.hasModifierProperty(PsiModifier.PROTECTED) && !mySubClass.isInheritor(containingClass, true))) { myConflicts.putValue( myMember, RefactoringUIUtil.getDescription(classMember, true) + " won't be accessible"); } } }
@PsiUtil.AccessLevel private static int getEffectiveLevel( @NotNull PsiElement element, @NotNull PsiFile file, @NotNull PsiFile memberFile, PsiClass memberClass, PsiPackage memberPackage) { PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); if (memberClass != null && PsiTreeUtil.isAncestor(aClass, memberClass, false) || aClass != null && PsiTreeUtil.isAncestor(memberClass, aClass, false)) { // access from the same file can be via private // except when used in annotation: // @Ann(value = C.VAL) class C { public static final String VAL = "xx"; } PsiAnnotation annotation = PsiTreeUtil.getParentOfType(element, PsiAnnotation.class); if (annotation != null && annotation.getParent() instanceof PsiModifierList && annotation.getParent().getParent() == aClass) { return PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL; } return PsiUtil.ACCESS_LEVEL_PRIVATE; } // if (file == memberFile) { // return PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL; // } PsiDirectory directory = file.getContainingDirectory(); PsiPackage aPackage = directory == null ? null : JavaDirectoryService.getInstance().getPackage(directory); if (aPackage == memberPackage || aPackage != null && memberPackage != null && Comparing.strEqual( aPackage.getQualifiedName(), memberPackage.getQualifiedName())) { return PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL; } if (aClass != null && memberClass != null && aClass.isInheritor(memberClass, true)) { // access from subclass can be via protected, except for constructors PsiElement resolved = element instanceof PsiReference ? ((PsiReference) element).resolve() : null; boolean isConstructor = resolved instanceof PsiClass && element.getParent() instanceof PsiNewExpression || resolved instanceof PsiMethod && ((PsiMethod) resolved).isConstructor(); if (!isConstructor) { return PsiUtil.ACCESS_LEVEL_PROTECTED; } } return PsiUtil.ACCESS_LEVEL_PUBLIC; }
private static void addResultFromReference( final PsiReference reference, final PsiClass methodClass, final PsiManager manager, final PsiClass aClass, final Processor<UsageInfo> results, final FindUsagesOptions options) { PsiElement refElement = reference.getElement(); if (refElement instanceof PsiReferenceExpression) { PsiClass usedClass = getFieldOrMethodAccessedClass((PsiReferenceExpression) refElement, methodClass); if (usedClass != null) { if (manager.areElementsEquivalent(usedClass, aClass) || usedClass.isInheritor(aClass, true)) { addResult(results, refElement, options); } } } }
public static boolean isJUnitTestCase(PsiClass aClass) { final Project project = aClass.getProject(); final GlobalSearchScope scope = GlobalSearchScope.allScope(project); final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); final PsiClass testCase = psiFacade.findClass("junit.framework.TestCase", scope); if (testCase == null) { return false; } if (aClass.isInheritor(testCase, true)) { return true; } final PsiMethod[] methods = aClass.getMethods(); for (PsiMethod method : methods) { //noinspection HardCodedStringLiteral if (AnnotationUtil.isAnnotated(method, "org.junit.Test", true)) { return true; } } return false; }
@Nullable private SiblingInfo findSibling(PsiClass inheritor, PsiClass anInterface, PsiMethod method) { for (PsiMethod superMethod : anInterface.findMethodsByName(method.getName(), true)) { PsiElement navigationElement = superMethod.getNavigationElement(); if (!(navigationElement instanceof PsiMethod)) continue; // Kotlin superMethod = (PsiMethod) navigationElement; ProgressManager.checkCanceled(); PsiClass superInterface = superMethod.getContainingClass(); if (superInterface == null || myContainingClass.isInheritor(superInterface, true)) { // if containingClass implements the superInterface then it's not a sibling inheritance // but a pretty boring the usual one continue; } if (isOverridden(inheritor, method, superMethod, superInterface)) { return new SiblingInfo(superMethod, inheritor); } } return null; }
@NotNull private static Collection<PsiClass> findRelatedActivities( @NotNull XmlFile file, @NotNull AndroidFacet facet, @NotNull DomFileDescription<?> description) { if (description instanceof LayoutDomFileDescription) { final Computable<List<GotoRelatedItem>> computable = AndroidGotoRelatedProvider.getLazyItemsForXmlFile(file, facet); if (computable == null) { return Collections.emptyList(); } final List<GotoRelatedItem> items = computable.compute(); if (items.isEmpty()) { return Collections.emptyList(); } final PsiClass activityClass = findActivityClass(facet.getModule()); if (activityClass == null) { return Collections.emptyList(); } final List<PsiClass> result = new ArrayList<PsiClass>(); for (GotoRelatedItem item : items) { final PsiElement element = item.getElement(); if (element instanceof PsiClass) { final PsiClass aClass = (PsiClass) element; if (aClass.isInheritor(activityClass, true)) { result.add(aClass); } } } return result; } else { return findRelatedActivitiesForMenu(file, facet); } }
protected void initialize() { myDefaultConstructor = null; final PsiClass psiClass = getElement(); LOG.assertTrue(psiClass != null); PsiElement psiParent = psiClass.getParent(); if (psiParent instanceof PsiFile) { if (isSyntheticJSP()) { final RefFileImpl refFile = (RefFileImpl) getRefManager().getReference(JspPsiUtil.getJspFile(psiClass)); LOG.assertTrue(refFile != null); refFile.add(this); } else if (psiParent instanceof PsiJavaFile) { PsiJavaFile psiFile = (PsiJavaFile) psiParent; String packageName = psiFile.getPackageName(); if (!"".equals(packageName)) { ((RefPackageImpl) getRefJavaManager().getPackage(packageName)).add(this); } else { ((RefPackageImpl) getRefJavaManager().getDefaultPackage()).add(this); } } final Module module = ModuleUtil.findModuleForPsiElement(psiClass); LOG.assertTrue(module != null); final RefModuleImpl refModule = ((RefModuleImpl) getRefManager().getRefModule(module)); LOG.assertTrue(refModule != null); refModule.add(this); } else { while (!(psiParent instanceof PsiClass || psiParent instanceof PsiMethod || psiParent instanceof PsiField)) { psiParent = psiParent.getParent(); } RefElement refParent = getRefManager().getReference(psiParent); LOG.assertTrue(refParent != null); ((RefElementImpl) refParent).add(this); } setAbstract(psiClass.hasModifierProperty(PsiModifier.ABSTRACT)); setAnonymous(psiClass instanceof PsiAnonymousClass); setIsLocal(!(isAnonymous() || psiParent instanceof PsiClass || psiParent instanceof PsiFile)); setInterface(psiClass.isInterface()); initializeSuperReferences(psiClass); PsiMethod[] psiMethods = psiClass.getMethods(); PsiField[] psiFields = psiClass.getFields(); setUtilityClass(psiMethods.length > 0 || psiFields.length > 0); for (PsiField psiField : psiFields) { getRefManager().getReference(psiField); } if (!isApplet()) { final PsiClass servlet = getRefJavaManager().getServlet(); setServlet(servlet != null && psiClass.isInheritor(servlet, true)); } if (!isApplet() && !isServlet()) { setTestCase(TestUtil.isTestClass(psiClass)); for (RefClass refBase : getBaseClasses()) { ((RefClassImpl) refBase).setTestCase(true); } } for (PsiMethod psiMethod : psiMethods) { RefMethod refMethod = (RefMethod) getRefManager().getReference(psiMethod); if (refMethod != null) { if (psiMethod.isConstructor()) { if (psiMethod.getParameterList().getParametersCount() > 0 || !psiMethod.hasModifierProperty(PsiModifier.PRIVATE)) { setUtilityClass(false); } addConstructor(refMethod); if (psiMethod.getParameterList().getParametersCount() == 0) { setDefaultConstructor((RefMethodImpl) refMethod); } } else { if (!psiMethod.hasModifierProperty(PsiModifier.STATIC)) { setUtilityClass(false); } } } } if (getConstructors().size() == 0 && !isInterface() && !isAnonymous()) { RefImplicitConstructorImpl refImplicitConstructor = new RefImplicitConstructorImpl(this); setDefaultConstructor(refImplicitConstructor); addConstructor(refImplicitConstructor); } if (isInterface()) { for (int i = 0; i < psiFields.length && isUtilityClass(); i++) { PsiField psiField = psiFields[i]; if (!psiField.hasModifierProperty(PsiModifier.STATIC)) { setUtilityClass(false); } } } final PsiClass applet = getRefJavaManager().getApplet(); setApplet(applet != null && psiClass.isInheritor(applet, true)); getRefManager().fireNodeInitialized(this); }
private static Map<MethodSignature, HierarchicalMethodSignature> buildMethodHierarchy( PsiClass aClass, PsiSubstitutor substitutor, final boolean includePrivates, final Set<PsiClass> visited, boolean isInRawContext) { Map<MethodSignature, HierarchicalMethodSignature> result = new LinkedHashMap<MethodSignature, HierarchicalMethodSignature>(); final Map<MethodSignature, List<PsiMethod>> sameParameterErasureMethods = new THashMap<MethodSignature, List<PsiMethod>>( MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); Map<MethodSignature, HierarchicalMethodSignatureImpl> map = new THashMap<MethodSignature, HierarchicalMethodSignatureImpl>( new TObjectHashingStrategy<MethodSignature>() { @Override public int computeHashCode(MethodSignature signature) { return MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY.computeHashCode( signature); } @Override public boolean equals(MethodSignature o1, MethodSignature o2) { if (!MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY.equals(o1, o2)) return false; List<PsiMethod> list = sameParameterErasureMethods.get(o1); boolean toCheckReturnType = list != null && list.size() > 1; if (!toCheckReturnType) return true; PsiType returnType1 = ((MethodSignatureBackedByPsiMethod) o1).getMethod().getReturnType(); PsiType returnType2 = ((MethodSignatureBackedByPsiMethod) o2).getMethod().getReturnType(); if (returnType1 == null && returnType2 == null) return true; if (returnType1 == null || returnType2 == null) return false; PsiType erasure1 = TypeConversionUtil.erasure(o1.getSubstitutor().substitute(returnType1)); PsiType erasure2 = TypeConversionUtil.erasure(o2.getSubstitutor().substitute(returnType2)); return erasure1.equals(erasure2); } }); for (PsiMethod method : aClass.getMethods()) { if (!method.isValid()) { throw new PsiInvalidElementAccessException( method, "class.valid=" + aClass.isValid() + "; name=" + method.getName()); } if (!includePrivates && method.hasModifierProperty(PsiModifier.PRIVATE)) continue; final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, substitutor, isInRawContext); HierarchicalMethodSignatureImpl newH = new HierarchicalMethodSignatureImpl(signature); List<PsiMethod> list = sameParameterErasureMethods.get(signature); if (list == null) { list = new SmartList<PsiMethod>(); sameParameterErasureMethods.put(signature, list); } list.add(method); LOG.assertTrue(newH.getMethod().isValid()); result.put(signature, newH); map.put(signature, newH); } for (PsiClassType superType : aClass.getSuperTypes()) { PsiClassType.ClassResolveResult superTypeResolveResult = superType.resolveGenerics(); PsiClass superClass = superTypeResolveResult.getElement(); if (superClass == null) continue; if (!visited.add(superClass)) continue; // cyclic inheritance final PsiSubstitutor superSubstitutor = superTypeResolveResult.getSubstitutor(); PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext); final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0; Map<MethodSignature, HierarchicalMethodSignature> superResult = buildMethodHierarchy(superClass, finalSubstitutor, false, visited, isInRawContextSuper); visited.remove(superClass); List<Pair<MethodSignature, HierarchicalMethodSignature>> flattened = new ArrayList<Pair<MethodSignature, HierarchicalMethodSignature>>(); for (Map.Entry<MethodSignature, HierarchicalMethodSignature> entry : superResult.entrySet()) { HierarchicalMethodSignature hms = entry.getValue(); MethodSignature signature = entry.getKey(); PsiClass containingClass = hms.getMethod().getContainingClass(); List<HierarchicalMethodSignature> supers = new ArrayList<HierarchicalMethodSignature>(hms.getSuperSignatures()); for (HierarchicalMethodSignature aSuper : supers) { PsiClass superContainingClass = aSuper.getMethod().getContainingClass(); if (containingClass != null && superContainingClass != null && !containingClass.isInheritor(superContainingClass, true)) { // methods must be inherited from unrelated classes, so flatten hierarchy here // class C implements SAM1, SAM2 { void methodimpl() {} } // hms.getSuperSignatures().remove(aSuper); flattened.add( new Pair<MethodSignature, HierarchicalMethodSignature>(signature, aSuper)); } } putInMap(aClass, result, map, hms, signature); } for (Pair<MethodSignature, HierarchicalMethodSignature> pair : flattened) { putInMap(aClass, result, map, pair.second, pair.first); } } for (Map.Entry<MethodSignature, HierarchicalMethodSignatureImpl> entry : map.entrySet()) { HierarchicalMethodSignatureImpl hierarchicalMethodSignature = entry.getValue(); MethodSignature methodSignature = entry.getKey(); if (result.get(methodSignature) == null && PsiUtil.isAccessible( aClass.getProject(), hierarchicalMethodSignature.getMethod(), aClass, aClass)) { LOG.assertTrue(hierarchicalMethodSignature.getMethod().isValid()); result.put(methodSignature, hierarchicalMethodSignature); } } return result; }
protected void generateFindViewById() { PsiClass activityClass = JavaPsiFacade.getInstance(mProject) .findClass("android.app.Activity", new EverythingGlobalScope(mProject)); PsiClass compatActivityClass = JavaPsiFacade.getInstance(mProject) .findClass( "android.support.v7.app.AppCompatActivity", new EverythingGlobalScope(mProject)); PsiClass fragmentClass = JavaPsiFacade.getInstance(mProject) .findClass("android.app.Fragment", new EverythingGlobalScope(mProject)); PsiClass supportFragmentClass = JavaPsiFacade.getInstance(mProject) .findClass("android.support.v4.app.Fragment", new EverythingGlobalScope(mProject)); // Check for Activity class if ((activityClass != null && mClass.isInheritor(activityClass, true)) || (compatActivityClass != null && mClass.isInheritor(compatActivityClass, true)) || mClass.getName().contains("Activity")) { if (mClass.findMethodsByName("onCreate", false).length == 0) { // Add an empty stub of onCreate() StringBuilder method = new StringBuilder(); method.append( "@Override protected void onCreate(android.os.Bundle savedInstanceState) {\n"); method.append("super.onCreate(savedInstanceState);\n"); method.append("\t// TODO: add setContentView(...) and run LayoutCreator again\n"); method.append("}"); mClass.add(mFactory.createMethodFromText(method.toString(), mClass)); } else { PsiStatement setContentViewStatement = null; boolean hasInitViewStatement = false; PsiMethod onCreate = mClass.findMethodsByName("onCreate", false)[0]; for (PsiStatement statement : onCreate.getBody().getStatements()) { // Search for setContentView() if (statement.getFirstChild() instanceof PsiMethodCallExpression) { PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) statement.getFirstChild()).getMethodExpression(); if (methodExpression.getText().equals("setContentView")) { setContentViewStatement = statement; } else if (methodExpression.getText().equals("initView")) { hasInitViewStatement = true; } } } if (!hasInitViewStatement && setContentViewStatement != null) { // Insert initView() after setContentView() onCreate .getBody() .addAfter( mFactory.createStatementFromText("initView();", mClass), setContentViewStatement); } generatorLayoutCode("this", null); } // Check for Fragment class } else if ((fragmentClass != null && mClass.isInheritor(fragmentClass, true)) || (supportFragmentClass != null && mClass.isInheritor(supportFragmentClass, true))) { if (mClass.findMethodsByName("onCreateView", false).length == 0) { // Add an empty stub of onCreateView() StringBuilder method = new StringBuilder(); method.append( "@Override public View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup container, android.os.Bundle savedInstanceState) {\n"); method.append( "\t// TODO: inflate a fragment like bottom ... and run LayoutCreator again\n"); method.append("View view = View.inflate(getActivity(), R.layout.frag_layout, null);"); method.append("return view;"); method.append("}"); mClass.add(mFactory.createMethodFromText(method.toString(), mClass)); } else { PsiReturnStatement returnStatement = null; String returnValue = null; boolean hasInitViewStatement = false; PsiMethod onCreateView = mClass.findMethodsByName("onCreateView", false)[0]; for (PsiStatement statement : onCreateView.getBody().getStatements()) { if (statement instanceof PsiReturnStatement) { returnStatement = (PsiReturnStatement) statement; returnValue = returnStatement.getReturnValue().getText(); } else if (statement.getFirstChild() instanceof PsiMethodCallExpression) { PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) statement.getFirstChild()).getMethodExpression(); if (methodExpression.getText().equals("initView")) { hasInitViewStatement = true; } } } if (!hasInitViewStatement && returnStatement != null && returnValue != null) { // Insert initView() before return statement onCreateView .getBody() .addBefore( mFactory.createStatementFromText("initView(" + returnValue + ");", mClass), returnStatement); } generatorLayoutCode("getContext()", returnValue); } } }
@Override public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { if (!LambdaUtil.isFunctionalType(myT)) { return false; } final PsiType groundTargetType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(myT); final PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(groundTargetType); final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(classResolveResult); if (interfaceMethod == null) { return false; } final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, classResolveResult); final PsiParameter[] targetParameters = interfaceMethod.getParameterList().getParameters(); final PsiType interfaceMethodReturnType = interfaceMethod.getReturnType(); final PsiType returnType = substitutor.substitute(interfaceMethodReturnType); final PsiType[] typeParameters = myExpression.getTypeParameters(); final PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult = PsiMethodReferenceUtil.getQualifierResolveResult(myExpression); if (!myExpression.isExact()) { for (PsiParameter parameter : targetParameters) { if (!session.isProperType(substitutor.substitute(parameter.getType()))) { return false; } } } else { final PsiMember applicableMember = myExpression.getPotentiallyApplicableMember(); LOG.assertTrue(applicableMember != null); final PsiClass applicableMemberContainingClass = applicableMember.getContainingClass(); final PsiClass containingClass = qualifierResolveResult.getContainingClass(); PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor(); psiSubstitutor = applicableMemberContainingClass == null || containingClass == null || myExpression.isConstructor() ? psiSubstitutor : TypeConversionUtil.getSuperClassSubstitutor( applicableMemberContainingClass, containingClass, psiSubstitutor); PsiType applicableMethodReturnType = applicableMember instanceof PsiMethod ? ((PsiMethod) applicableMember).getReturnType() : null; int idx = 0; for (PsiTypeParameter param : ((PsiTypeParameterListOwner) applicableMember).getTypeParameters()) { if (idx < typeParameters.length) { psiSubstitutor = psiSubstitutor.put(param, typeParameters[idx++]); } } final PsiParameter[] parameters = applicableMember instanceof PsiMethod ? ((PsiMethod) applicableMember).getParameterList().getParameters() : PsiParameter.EMPTY_ARRAY; if (targetParameters.length == parameters.length + 1) { specialCase(session, constraints, substitutor, targetParameters, true); for (int i = 1; i < targetParameters.length; i++) { constraints.add( new TypeCompatibilityConstraint( session.substituteWithInferenceVariables( psiSubstitutor.substitute(parameters[i - 1].getType())), substitutor.substitute(targetParameters[i].getType()))); } } else if (targetParameters.length == parameters.length) { for (int i = 0; i < targetParameters.length; i++) { constraints.add( new TypeCompatibilityConstraint( session.substituteWithInferenceVariables( psiSubstitutor.substitute(parameters[i].getType())), substitutor.substitute(targetParameters[i].getType()))); } } else { return false; } if (returnType != PsiType.VOID && returnType != null) { if (applicableMethodReturnType == PsiType.VOID) { return false; } if (applicableMethodReturnType != null) { constraints.add( new TypeCompatibilityConstraint( returnType, session.substituteWithInferenceVariables( psiSubstitutor.substitute(applicableMethodReturnType)))); } else if (applicableMember instanceof PsiClass || applicableMember instanceof PsiMethod && ((PsiMethod) applicableMember).isConstructor()) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(applicableMember.getProject()); if (containingClass != null) { final PsiType classType = session.substituteWithInferenceVariables( elementFactory.createType(containingClass, psiSubstitutor)); constraints.add(new TypeCompatibilityConstraint(returnType, classType)); } } } return true; } final Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap(); final PsiType added = map.put(myExpression, session.startWithFreshVars(groundTargetType)); final JavaResolveResult resolve; try { resolve = myExpression.advancedResolve(true); } finally { if (added == null) { map.remove(myExpression); } } final PsiElement element = resolve.getElement(); if (element == null) { return false; } if (PsiType.VOID.equals(returnType) || returnType == null) { return true; } if (element instanceof PsiMethod) { final PsiMethod method = (PsiMethod) element; final PsiType referencedMethodReturnType; final PsiClass containingClass = method.getContainingClass(); LOG.assertTrue(containingClass != null, method); PsiClass qContainingClass = qualifierResolveResult.getContainingClass(); PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor(); if (qContainingClass != null) { if (PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) { psiSubstitutor = PsiSubstitutor.EMPTY; } if (qContainingClass.isInheritor(containingClass, true)) { psiSubstitutor = TypeConversionUtil.getClassSubstitutor( containingClass, qContainingClass, PsiSubstitutor.EMPTY); LOG.assertTrue(psiSubstitutor != null); } } if (method.isConstructor()) { referencedMethodReturnType = JavaPsiFacade.getElementFactory(method.getProject()) .createType(containingClass, PsiSubstitutor.EMPTY); } else { referencedMethodReturnType = method.getReturnType(); } LOG.assertTrue(referencedMethodReturnType != null, method); if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) || PsiUtil.getEnclosingStaticElement(myExpression, containingClass) != null) { session.initBounds(myExpression, containingClass.getTypeParameters()); } session.initBounds(myExpression, method.getTypeParameters()); // if i) the method reference elides NonWildTypeArguments, // ii) the compile-time declaration is a generic method, and // iii) the return type of the compile-time declaration mentions at least one of the method's // type parameters; if (typeParameters.length == 0 && method.getTypeParameters().length > 0) { final PsiClass interfaceClass = classResolveResult.getElement(); LOG.assertTrue(interfaceClass != null); if (PsiPolyExpressionUtil.mentionsTypeParameters( referencedMethodReturnType, ContainerUtil.newHashSet(method.getTypeParameters()))) { // the constraint reduces to the bound set B3 which would be used to determine the method // reference's invocation type // when targeting the return type of the function type, as defined in 18.5.2. session.collectApplicabilityConstraints( myExpression, ((MethodCandidateInfo) resolve), groundTargetType); session.registerReturnTypeConstraints(referencedMethodReturnType, returnType); return true; } } if (PsiType.VOID.equals(referencedMethodReturnType)) { return false; } int idx = 0; for (PsiTypeParameter param : method.getTypeParameters()) { if (idx < typeParameters.length) { psiSubstitutor = psiSubstitutor.put(param, typeParameters[idx++]); } } final PsiParameter[] parameters = method.getParameterList().getParameters(); if (targetParameters.length == parameters.length + 1 && !method.isVarArgs() && PsiPolyExpressionUtil.mentionsTypeParameters( referencedMethodReturnType, ContainerUtil.newHashSet( containingClass.getTypeParameters()))) { // todo specification bug? specialCase(session, constraints, substitutor, targetParameters, false); } constraints.add( new TypeCompatibilityConstraint( returnType, session.substituteWithInferenceVariables( psiSubstitutor.substitute(referencedMethodReturnType)))); } return true; }
private Domination dominates( PsiClass aClass, boolean accessible, String fqName, ClassCandidateInfo info) { final PsiClass otherClass = info.getElement(); assert otherClass != null; String otherQName = otherClass.getQualifiedName(); if (fqName.equals(otherQName)) { return Domination.DOMINATED_BY; } final PsiClass containingClass1 = aClass.getContainingClass(); final PsiClass containingClass2 = otherClass.getContainingClass(); if (myAccessClass != null && !Comparing.equal(containingClass1, containingClass2)) { if (myAccessClass.equals(containingClass1)) return Domination.DOMINATES; if (myAccessClass.equals(containingClass2)) return Domination.DOMINATED_BY; } // JLS 8.5: // A class may inherit two or more type declarations with the same name, either from two // interfaces or from its superclass and an interface. // It is a compile-time error to attempt to refer to any ambiguously inherited class or // interface by its simple name. if (containingClass1 != null && containingClass2 != null && containingClass2.isInheritor(containingClass1, true) && !isImported(myCurrentFileContext)) { if (!isAmbiguousInherited(containingClass1)) { // shadowing return Domination.DOMINATED_BY; } } boolean infoAccessible = info.isAccessible() && isAccessible(otherClass); if (infoAccessible && !accessible) { return Domination.DOMINATED_BY; } if (!infoAccessible && accessible) { return Domination.DOMINATES; } // everything wins over class from default package boolean isDefault = StringUtil.getPackageName(fqName).length() == 0; boolean otherDefault = otherQName != null && StringUtil.getPackageName(otherQName).length() == 0; if (isDefault && !otherDefault) { return Domination.DOMINATED_BY; } if (!isDefault && otherDefault) { return Domination.DOMINATES; } // single import wins over on-demand boolean myOnDemand = isOnDemand(myCurrentFileContext, aClass); boolean otherOnDemand = isOnDemand(info.getCurrentFileResolveScope(), otherClass); if (myOnDemand && !otherOnDemand) { return Domination.DOMINATED_BY; } if (!myOnDemand && otherOnDemand) { return Domination.DOMINATES; } return Domination.EQUAL; }
@NotNull private static LookupElement castQualifier( @NotNull LookupElement item, @Nullable final PsiTypeLookupItem castTypeItem, @Nullable PsiType plainQualifier, JavaCompletionProcessor processor) { if (castTypeItem == null) { return item; } if (plainQualifier != null) { Object o = item.getObject(); if (o instanceof PsiMethod) { PsiType castType = castTypeItem.getType(); if (plainQualifier instanceof PsiClassType && castType instanceof PsiClassType) { PsiMethod method = (PsiMethod) o; PsiClassType.ClassResolveResult plainResult = ((PsiClassType) plainQualifier).resolveGenerics(); PsiClass plainClass = plainResult.getElement(); if (plainClass != null && plainClass.findMethodBySignature(method, true) != null) { PsiClass castClass = ((PsiClassType) castType).resolveGenerics().getElement(); if (castClass == null || !castClass.isInheritor(plainClass, true)) { return item; } PsiSubstitutor plainSub = plainResult.getSubstitutor(); PsiSubstitutor castSub = TypeConversionUtil.getSuperClassSubstitutor(plainClass, (PsiClassType) castType); PsiType returnType = method.getReturnType(); if (method.getSignature(plainSub).equals(method.getSignature(castSub))) { PsiType typeAfterCast = toRaw(castSub.substitute(returnType)); PsiType typeDeclared = toRaw(plainSub.substitute(returnType)); if (typeAfterCast != null && typeDeclared != null && typeAfterCast.isAssignableFrom(typeDeclared) && processor.isAccessible(plainClass.findMethodBySignature(method, true))) { return item; } } } } } else if (containsMember(plainQualifier, o)) { return item; } } return LookupElementDecorator.withInsertHandler( item, new InsertHandlerDecorator<LookupElement>() { @Override public void handleInsert( InsertionContext context, LookupElementDecorator<LookupElement> item) { final Document document = context.getEditor().getDocument(); context.commitDocument(); final PsiFile file = context.getFile(); final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset( file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false); if (ref != null) { final PsiElement qualifier = ref.getQualifier(); if (qualifier != null) { final CommonCodeStyleSettings settings = context.getCodeStyleSettings(); final String parenSpace = settings.SPACE_WITHIN_PARENTHESES ? " " : ""; document.insertString(qualifier.getTextRange().getEndOffset(), parenSpace + ")"); final String spaceWithin = settings.SPACE_WITHIN_CAST_PARENTHESES ? " " : ""; final String prefix = "(" + parenSpace + "(" + spaceWithin; final String spaceAfter = settings.SPACE_AFTER_TYPE_CAST ? " " : ""; final int exprStart = qualifier.getTextRange().getStartOffset(); document.insertString(exprStart, prefix + spaceWithin + ")" + spaceAfter); CompletionUtil.emulateInsertion(context, exprStart + prefix.length(), castTypeItem); PsiDocumentManager.getInstance(file.getProject()) .doPostponedOperationsAndUnblockDocument(document); context.getEditor().getCaretModel().moveToOffset(context.getTailOffset()); } } item.getDelegate().handleInsert(context); } }); }
private Specifics isMoreSpecific( @NotNull MethodCandidateInfo info1, @NotNull MethodCandidateInfo info2, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel, @NotNull LanguageLevel languageLevel) { PsiMethod method1 = info1.getElement(); PsiMethod method2 = info2.getElement(); final PsiClass class1 = method1.getContainingClass(); final PsiClass class2 = method2.getContainingClass(); final PsiParameter[] params1 = method1.getParameterList().getParameters(); final PsiParameter[] params2 = method2.getParameterList().getParameters(); final PsiTypeParameter[] typeParameters1 = method1.getTypeParameters(); final PsiTypeParameter[] typeParameters2 = method2.getTypeParameters(); final PsiSubstitutor classSubstitutor1 = info1.getSubstitutor(false); // substitutions for method type parameters will be ignored final PsiSubstitutor classSubstitutor2 = info2.getSubstitutor(false); final int max = Math.max(params1.length, params2.length); PsiType[] types1 = PsiType.createArray(max); PsiType[] types2 = PsiType.createArray(max); final boolean varargsPosition = applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS; for (int i = 0; i < max; i++) { ProgressManager.checkCanceled(); PsiType type1 = params1.length > 0 ? params1[Math.min(i, params1.length - 1)].getType() : null; PsiType type2 = params2.length > 0 ? params2[Math.min(i, params2.length - 1)].getType() : null; if (varargsPosition) { if (type1 instanceof PsiEllipsisType && type2 instanceof PsiEllipsisType && params1.length == params2.length && class1 != null && (!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7) || ((PsiArrayType) type1) .getComponentType() .equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || ((PsiArrayType) type2) .getComponentType() .equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) { type1 = ((PsiEllipsisType) type1).toArrayType(); type2 = ((PsiEllipsisType) type2).toArrayType(); } else { type1 = type1 instanceof PsiEllipsisType ? ((PsiArrayType) type1).getComponentType() : type1; type2 = type2 instanceof PsiEllipsisType ? ((PsiArrayType) type2).getComponentType() : type2; } } types1[i] = type1; types2[i] = type2; } boolean sameBoxing = true; int[] boxingHappened = new int[2]; for (int i = 0; i < types1.length; i++) { ProgressManager.checkCanceled(); PsiType type1 = classSubstitutor1.substitute(types1[i]); PsiType type2 = classSubstitutor2.substitute(types2[i]); PsiType argType = i < getActualParameterTypes().length ? getActualParameterTypes()[i] : null; boolean boxingInFirst = false; if (isBoxingHappened(argType, type1, languageLevel)) { boxingHappened[0] += 1; boxingInFirst = true; } boolean boxingInSecond = false; if (isBoxingHappened(argType, type2, languageLevel)) { boxingHappened[1] += 1; boxingInSecond = true; } sameBoxing &= boxingInFirst == boxingInSecond; } if (boxingHappened[0] == 0 && boxingHappened[1] > 0) return Specifics.FIRST; if (boxingHappened[0] > 0 && boxingHappened[1] == 0) return Specifics.SECOND; if (sameBoxing) { final PsiSubstitutor siteSubstitutor1 = info1.getSiteSubstitutor(); final PsiSubstitutor siteSubstitutor2 = info2.getSiteSubstitutor(); final PsiType[] types2AtSite = typesAtSite(types2, siteSubstitutor2); final PsiType[] types1AtSite = typesAtSite(types1, siteSubstitutor1); final PsiSubstitutor methodSubstitutor1 = calculateMethodSubstitutor( typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel); boolean applicable12 = isApplicableTo( types2AtSite, method1, languageLevel, varargsPosition, methodSubstitutor1, method2); final PsiSubstitutor methodSubstitutor2 = calculateMethodSubstitutor( typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel); boolean applicable21 = isApplicableTo( types1AtSite, method2, languageLevel, varargsPosition, methodSubstitutor2, method1); if (!myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { final boolean typeArgsApplicable12 = GenericsUtil.isTypeArgumentsApplicable( typeParameters1, methodSubstitutor1, myArgumentsList, !applicable21); final boolean typeArgsApplicable21 = GenericsUtil.isTypeArgumentsApplicable( typeParameters2, methodSubstitutor2, myArgumentsList, !applicable12); if (!typeArgsApplicable12) { applicable12 = false; } if (!typeArgsApplicable21) { applicable21 = false; } } if (applicable12 || applicable21) { if (applicable12 && !applicable21) return Specifics.SECOND; if (applicable21 && !applicable12) return Specifics.FIRST; final boolean abstract1 = method1.hasModifierProperty(PsiModifier.ABSTRACT); final boolean abstract2 = method2.hasModifierProperty(PsiModifier.ABSTRACT); if (abstract1 && !abstract2) { return Specifics.SECOND; } if (abstract2 && !abstract1) { return Specifics.FIRST; } } if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && myArgumentsList instanceof PsiExpressionList && (typeParameters1.length == 0 || typeParameters2.length == 0)) { boolean toCompareFunctional = false; if (types1.length > 0 && types2.length > 0) { for (int i = 0; i < getActualParametersLength(); i++) { final PsiType type1 = types1[Math.min(i, types1.length - 1)]; final PsiType type2 = types2[Math.min(i, types2.length - 1)]; // from 15.12.2.5 Choosing the Most Specific Method // In addition, a functional interface type S is more specific than a functional // interface type T for an expression exp // if T is not a subtype of S and one of the following conditions apply. if (LambdaUtil.isFunctionalType(type1) && !TypeConversionUtil.erasure(type1).isAssignableFrom(type2) && LambdaUtil.isFunctionalType(type2) && !TypeConversionUtil.erasure(type2).isAssignableFrom(type1)) { types1AtSite[Math.min(i, types1.length - 1)] = PsiType.NULL; types2AtSite[Math.min(i, types2.length - 1)] = PsiType.NULL; toCompareFunctional = true; } } } if (toCompareFunctional) { final boolean applicable12ignoreFunctionalType = isApplicableTo( types2AtSite, method1, languageLevel, varargsPosition, calculateMethodSubstitutor( typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel), null); final boolean applicable21ignoreFunctionalType = isApplicableTo( types1AtSite, method2, languageLevel, varargsPosition, calculateMethodSubstitutor( typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel), null); if (applicable12ignoreFunctionalType || applicable21ignoreFunctionalType) { Specifics specifics = null; for (int i = 0; i < getActualParametersLength(); i++) { if (types1AtSite[Math.min(i, types1.length - 1)] == PsiType.NULL && types2AtSite[Math.min(i, types2.length - 1)] == PsiType.NULL) { Specifics specific = isFunctionalTypeMoreSpecific( info1, info2, ((PsiExpressionList) myArgumentsList).getExpressions()[i], i); if (specific == Specifics.NEITHER) { specifics = Specifics.NEITHER; break; } if (specifics == null) { specifics = specific; } else if (specifics != specific) { specifics = Specifics.NEITHER; break; } } } if (!applicable12ignoreFunctionalType && applicable21ignoreFunctionalType) { return specifics == Specifics.FIRST ? Specifics.FIRST : Specifics.NEITHER; } if (!applicable21ignoreFunctionalType && applicable12ignoreFunctionalType) { return specifics == Specifics.SECOND ? Specifics.SECOND : Specifics.NEITHER; } return specifics; } } } } else if (varargsPosition) { final PsiType lastParamType1 = classSubstitutor1.substitute(types1[types1.length - 1]); final PsiType lastParamType2 = classSubstitutor2.substitute(types2[types1.length - 1]); final boolean assignable1 = TypeConversionUtil.isAssignable(lastParamType2, lastParamType1); final boolean assignable2 = TypeConversionUtil.isAssignable(lastParamType1, lastParamType2); if (assignable1 && !assignable2) { return Specifics.FIRST; } if (assignable2 && !assignable1) { return Specifics.SECOND; } } if (class1 != class2) { if (class2.isInheritor(class1, true) || class1.isInterface() && !class2.isInterface()) { if (MethodSignatureUtil.isSubsignature( method1.getSignature(info1.getSubstitutor(false)), method2.getSignature(info2.getSubstitutor(false)))) { return Specifics.SECOND; } else if (method1.hasModifierProperty(PsiModifier.STATIC) && method2.hasModifierProperty(PsiModifier.STATIC) && boxingHappened[0] == 0) { return Specifics.SECOND; } } else if (MethodSignatureUtil.areErasedParametersEqual( method1.getSignature(PsiSubstitutor.EMPTY), method2.getSignature(PsiSubstitutor.EMPTY)) && MethodSignatureUtil.isSubsignature( method2.getSignature(info2.getSubstitutor(false)), method1.getSignature(info1.getSubstitutor(false)))) { return Specifics.FIRST; } else if (class1.isInheritor(class2, true) || class2.isInterface()) { if (method1.hasModifierProperty(PsiModifier.STATIC) && method2.hasModifierProperty(PsiModifier.STATIC) && boxingHappened[0] == 0) { return Specifics.FIRST; } } } final boolean raw1 = PsiUtil.isRawSubstitutor(method1, classSubstitutor1); final boolean raw2 = PsiUtil.isRawSubstitutor(method2, classSubstitutor2); if (raw1 ^ raw2) { return raw1 ? Specifics.SECOND : Specifics.FIRST; } final boolean varargs1 = info1.isVarargs(); final boolean varargs2 = info2.isVarargs(); if (varargs1 ^ varargs2) { return varargs1 ? Specifics.SECOND : Specifics.FIRST; } return Specifics.NEITHER; }