private static void putInMap(
     PsiClass aClass,
     Map<MethodSignature, HierarchicalMethodSignature> result,
     Map<MethodSignature, HierarchicalMethodSignatureImpl> map,
     HierarchicalMethodSignature hierarchicalMethodSignature,
     MethodSignature signature) {
   if (!PsiUtil.isAccessible(
       aClass.getProject(), hierarchicalMethodSignature.getMethod(), aClass, aClass)) return;
   HierarchicalMethodSignatureImpl existing = map.get(signature);
   if (existing == null) {
     HierarchicalMethodSignatureImpl copy = copy(hierarchicalMethodSignature);
     LOG.assertTrue(copy.getMethod().isValid());
     map.put(signature, copy);
   } else if (isReturnTypeIsMoreSpecificThan(hierarchicalMethodSignature, existing)
       && isSuperMethod(aClass, hierarchicalMethodSignature, existing)) {
     HierarchicalMethodSignatureImpl newSuper = copy(hierarchicalMethodSignature);
     mergeSupers(newSuper, existing);
     LOG.assertTrue(newSuper.getMethod().isValid());
     map.put(signature, newSuper);
   } else if (isSuperMethod(aClass, existing, hierarchicalMethodSignature)) {
     mergeSupers(existing, hierarchicalMethodSignature);
   }
   // just drop an invalid method declaration there - to highlight accordingly
   else if (!result.containsKey(signature)) {
     LOG.assertTrue(hierarchicalMethodSignature.getMethod().isValid());
     result.put(signature, hierarchicalMethodSignature);
   }
 }
Exemple #2
0
 public static boolean nameCanBeImported(@NotNull String fqName, @NotNull PsiElement context) {
   final PsiClass containingClass = PsiTreeUtil.getParentOfType(context, PsiClass.class);
   if (containingClass != null) {
     if (fqName.equals(containingClass.getQualifiedName())) {
       return true;
     }
     final String shortName = ClassUtil.extractClassName(fqName);
     final PsiClass[] innerClasses = containingClass.getAllInnerClasses();
     for (PsiClass innerClass : innerClasses) {
       if (innerClass.hasModifierProperty(PsiModifier.PRIVATE)) {
         continue;
       }
       if (innerClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
         if (!ClassUtils.inSamePackage(innerClass, containingClass)) {
           continue;
         }
       }
       final String className = innerClass.getName();
       if (shortName.equals(className)) {
         return false;
       }
     }
     PsiField field = containingClass.findFieldByName(shortName, false);
     if (field != null) {
       return false;
     }
     field = containingClass.findFieldByName(shortName, true);
     if (field != null
         && PsiUtil.isAccessible(containingClass.getProject(), field, containingClass, null)) {
       return false;
     }
   }
   final PsiJavaFile file = PsiTreeUtil.getParentOfType(context, PsiJavaFile.class);
   if (file == null) {
     return false;
   }
   if (hasExactImportConflict(fqName, file)) {
     return false;
   }
   if (hasOnDemandImportConflict(fqName, file, true)) {
     return false;
   }
   if (containsConflictingReference(file, fqName)) {
     return false;
   }
   if (containsConflictingClass(fqName, file)) {
     return false;
   }
   return !containsConflictingClassName(fqName, file);
 }
  private static boolean isSuperMethod(
      PsiClass aClass,
      HierarchicalMethodSignature hierarchicalMethodSignature,
      HierarchicalMethodSignature superSignatureHierarchical) {
    PsiMethod superMethod = superSignatureHierarchical.getMethod();
    PsiClass superClass = superMethod.getContainingClass();
    PsiClass containingClass = hierarchicalMethodSignature.getMethod().getContainingClass();
    if (!superMethod.isConstructor()) {
      if (!aClass.equals(superClass)) {
        if (PsiUtil.isAccessible(aClass.getProject(), superMethod, aClass, aClass)) {
          if (MethodSignatureUtil.isSubsignature(
              superSignatureHierarchical, hierarchicalMethodSignature)) {
            if (superClass != null) {
              if (superClass.isInterface()
                  || CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) {
                if (superMethod.hasModifierProperty(PsiModifier.DEFAULT)
                    || hierarchicalMethodSignature
                        .getMethod()
                        .hasModifierProperty(PsiModifier.DEFAULT)) {
                  return !InheritanceUtil.isInheritorOrSelf(superClass, containingClass, true);
                }
                return true;
              }

              if (containingClass != null) {
                if (containingClass.isInterface()) {
                  return false;
                }

                if (!aClass.isInterface()
                    && !InheritanceUtil.isInheritorOrSelf(superClass, containingClass, true)) {
                  return true;
                }
              }
            }
          }
        }
      }
    }
    return false;
  }
  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;
  }