Example #1
0
 private static boolean isOverrideObjectDirect(@NotNull PsiMethod method) {
   List<HierarchicalMethodSignature> superSignatures =
       method.getHierarchicalMethodSignature().getSuperSignatures();
   if (superSignatures.size() == 1) {
     PsiClass containingClass = superSignatures.get(0).getMethod().getContainingClass();
     String qualifiedName = containingClass != null ? containingClass.getQualifiedName() : "";
     if (qualifiedName != null && qualifiedName.equals(JAVA_LANG_OBJECT)) {
       return true;
     }
   }
   return false;
 }
Example #2
0
 private static boolean isInheritFromObject(@NotNull PsiMethod method) {
   List<HierarchicalMethodSignature> superSignatures =
       method.getHierarchicalMethodSignature().getSuperSignatures();
   for (HierarchicalMethodSignature s : superSignatures) {
     PsiClass containingClass = s.getMethod().getContainingClass();
     String qualifiedName = containingClass != null ? containingClass.getQualifiedName() : "";
     if (qualifiedName != null && qualifiedName.equals(JAVA_LANG_OBJECT)) {
       return true;
     }
   }
   return false;
 }
Example #3
0
 private static boolean normalCase(@NotNull PsiMethod method) {
   int counter = 0;
   for (HierarchicalMethodSignature s :
       method.getHierarchicalMethodSignature().getSuperSignatures()) {
     PsiClass containingClass = s.getMethod().getContainingClass();
     String qualifiedName = containingClass != null ? containingClass.getQualifiedName() : "";
     if (qualifiedName != null && !qualifiedName.equals(JAVA_LANG_OBJECT)) {
       counter++;
     }
   }
   return counter > 0;
 }
  // uses hierarchy signature tree if available, traverses class structure by itself otherwise
  public static boolean processDirectSuperMethodsSmart(
      @NotNull PsiMethod method, @NotNull Processor<PsiMethod> superMethodProcessor) {
    // boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod);

    PsiClass aClass = method.getContainingClass();
    if (aClass == null) return false;

    if (!canHaveSuperMethod(method, true, false)) return false;

    Map<MethodSignature, HierarchicalMethodSignature> cachedMap =
        SIGNATURES_KEY.getCachedValueOrNull(aClass);
    if (cachedMap != null) {
      HierarchicalMethodSignature signature =
          cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY));
      if (signature != null) {
        List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures();
        for (HierarchicalMethodSignature superSignature : superSignatures) {
          if (!superMethodProcessor.process(superSignature.getMethod())) return false;
        }
        return true;
      }
    }

    PsiClassType[] directSupers = aClass.getSuperTypes();
    for (PsiClassType directSuper : directSupers) {
      PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics();
      if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) {
        // generics
        break;
      }
      PsiClass directSuperClass = resolveResult.getElement();
      if (directSuperClass == null) continue;
      PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false);
      for (PsiMethod candidate : candidates) {
        if (PsiUtil.canBeOverriden(candidate)) {
          if (!superMethodProcessor.process(candidate)) return false;
        }
      }
      return true;
    }

    List<HierarchicalMethodSignature> superSignatures =
        method.getHierarchicalMethodSignature().getSuperSignatures();
    for (HierarchicalMethodSignature superSignature : superSignatures) {
      if (!superMethodProcessor.process(superSignature.getMethod())) return false;
    }
    return true;
  }
    private void checkMember(@NotNull final PsiMember member) {
      if (member.hasModifierProperty(PsiModifier.PRIVATE)
          || member.hasModifierProperty(PsiModifier.NATIVE)) return;
      if (member instanceof PsiMethod && member instanceof SyntheticElement || !member.isPhysical())
        return;

      if (member instanceof PsiMethod) {
        PsiMethod method = (PsiMethod) member;
        if (!method.getHierarchicalMethodSignature().getSuperSignatures().isEmpty()) {
          log(member.getName() + " overrides");
          return; // overrides
        }
        if (MethodUtils.isOverridden(method)) {
          log(member.getName() + " overridden");
          return;
        }
      }
      if (member instanceof PsiEnumConstant) return;
      if (member instanceof PsiClass
          && (member instanceof PsiAnonymousClass
              || member instanceof PsiTypeParameter
              || member instanceof PsiSyntheticClass
              || PsiUtil.isLocalClass((PsiClass) member))) {
        return;
      }
      final PsiClass memberClass = member.getContainingClass();
      if (memberClass != null
          && (memberClass.isInterface()
              || memberClass.isEnum()
              || memberClass.isAnnotationType()
              || PsiUtil.isLocalClass(memberClass) && member instanceof PsiClass)) {
        return;
      }
      final PsiFile memberFile = member.getContainingFile();
      Project project = memberFile.getProject();

      if (myDeadCodeInspection.isEntryPoint(member)) {
        log(member.getName() + " is entry point");
        return;
      }

      PsiModifierList memberModifierList = member.getModifierList();
      if (memberModifierList == null) return;
      final int currentLevel = PsiUtil.getAccessLevel(memberModifierList);
      final AtomicInteger maxLevel = new AtomicInteger(PsiUtil.ACCESS_LEVEL_PRIVATE);
      final AtomicBoolean foundUsage = new AtomicBoolean();
      PsiDirectory memberDirectory = memberFile.getContainingDirectory();
      final PsiPackage memberPackage =
          memberDirectory == null
              ? null
              : JavaDirectoryService.getInstance().getPackage(memberDirectory);
      log(member.getName() + ": checking effective level for " + member);
      boolean result =
          UnusedSymbolUtil.processUsages(
              project,
              memberFile,
              member,
              new EmptyProgressIndicator(),
              null,
              new Processor<UsageInfo>() {
                @Override
                public boolean process(UsageInfo info) {
                  foundUsage.set(true);
                  PsiFile psiFile = info.getFile();
                  if (psiFile == null) return true;
                  if (!(psiFile instanceof PsiJavaFile)) {
                    log("     refd from " + psiFile.getName() + "; set to public");
                    maxLevel.set(PsiUtil.ACCESS_LEVEL_PUBLIC);
                    if (memberClass != null) {
                      childMembersAreUsedOutsideMyPackage.add(memberClass);
                    }
                    return false; // referenced from XML, has to be public
                  }
                  // int offset = info.getNavigationOffset();
                  // if (offset == -1) return true;
                  PsiElement element = info.getElement();
                  if (element == null) return true;
                  @PsiUtil.AccessLevel
                  int level =
                      getEffectiveLevel(element, psiFile, memberFile, memberClass, memberPackage);
                  log(
                      "    ref in file "
                          + psiFile.getName()
                          + "; level = "
                          + PsiUtil.getAccessModifier(level)
                          + "; ("
                          + element
                          + ")");
                  while (true) {
                    int oldLevel = maxLevel.get();
                    if (level <= oldLevel || maxLevel.compareAndSet(oldLevel, level)) break;
                  }
                  if (level == PsiUtil.ACCESS_LEVEL_PUBLIC && memberClass != null) {
                    childMembersAreUsedOutsideMyPackage.add(memberClass);
                  }

                  return level != PsiUtil.ACCESS_LEVEL_PUBLIC;
                }
              });

      if (!foundUsage.get()) {
        log(member.getName() + " unused; ignore");
        return; // do not propose private for unused method
      }
      int max = maxLevel.get();
      if (max == PsiUtil.ACCESS_LEVEL_PRIVATE && memberClass == null) {
        max = PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL;
      }

      log(member.getName() + ": effective level is '" + PsiUtil.getAccessModifier(max) + "'");

      if (max < currentLevel) {
        if (max == PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL
            && member instanceof PsiClass
            && childMembersAreUsedOutsideMyPackage.contains(member)) {
          log(member.getName() + "  children used outside my package; ignore");
          return; // e.g. some public method is used outside my package (without importing class)
        }
        PsiElement toHighlight =
            currentLevel == PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL
                ? ((PsiNameIdentifierOwner) member).getNameIdentifier()
                : ContainerUtil.find(
                    memberModifierList.getChildren(),
                    new Condition<PsiElement>() {
                      @Override
                      public boolean value(PsiElement element) {
                        return element instanceof PsiKeyword
                            && element.getText().equals(PsiUtil.getAccessModifier(currentLevel));
                      }
                    });
        assert toHighlight != null
            : member
                + " ; "
                + ((PsiNameIdentifierOwner) member).getNameIdentifier()
                + "; "
                + memberModifierList.getText();
        myHolder.registerProblem(
            toHighlight,
            "Access can be " + PsiUtil.getAccessModifier(max),
            new ChangeModifierFix(PsiUtil.getAccessModifier(max)));
      }
    }
  // uses hierarchy signature tree if available, traverses class structure by itself otherwise
  public static boolean isSuperMethodSmart(
      @NotNull PsiMethod method, @NotNull PsiMethod superMethod) {
    // boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod);

    if (method == superMethod) return false;
    PsiClass aClass = method.getContainingClass();
    PsiClass superClass = superMethod.getContainingClass();

    if (aClass == null || superClass == null || superClass == aClass) return false;

    if (!canHaveSuperMethod(method, true, false)) return false;

    PsiMethod[] superMethods = null;
    Map<MethodSignature, HierarchicalMethodSignature> cachedMap =
        SIGNATURES_KEY.getCachedValueOrNull(aClass);
    if (cachedMap != null) {
      HierarchicalMethodSignature signature =
          cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY));
      if (signature != null) {
        superMethods =
            MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures());
      }
    }
    if (superMethods == null) {
      PsiClassType[] directSupers = aClass.getSuperTypes();
      List<PsiMethod> found = null;
      boolean canceled = false;
      for (PsiClassType directSuper : directSupers) {
        PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics();
        if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) {
          // generics
          canceled = true;
          break;
        }
        PsiClass directSuperClass = resolveResult.getElement();
        if (directSuperClass == null) continue;
        PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false);
        if (candidates.length != 0) {
          if (found == null) found = new ArrayList<PsiMethod>();
          for (PsiMethod candidate : candidates) {
            if (PsiUtil.canBeOverriden(candidate)) found.add(candidate);
          }
        }
      }
      superMethods =
          canceled
              ? null
              : found == null ? PsiMethod.EMPTY_ARRAY : found.toArray(new PsiMethod[found.size()]);
    }
    if (superMethods == null) {
      superMethods =
          MethodSignatureUtil.convertMethodSignaturesToMethods(
              method.getHierarchicalMethodSignature().getSuperSignatures());
    }

    for (PsiMethod superCandidate : superMethods) {
      if (superMethod.equals(superCandidate) || isSuperMethodSmart(superCandidate, superMethod))
        return true;
    }
    return false;
  }
  protected void checkSameSignatures(@NotNull List<CandidateInfo> conflicts) {
    // 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());
    Set<PsiMethod> superMethods = new HashSet<PsiMethod>();
    for (CandidateInfo conflict : conflicts) {
      final PsiMethod method = ((MethodCandidateInfo) conflict).getElement();
      for (HierarchicalMethodSignature methodSignature :
          method.getHierarchicalMethodSignature().getSuperSignatures()) {
        final PsiMethod superMethod = methodSignature.getMethod();
        final PsiClass aClass = superMethod.getContainingClass();
        if (aClass != null
            && !CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) {
          superMethods.add(superMethod);
        }
      }
    }
    nextConflict:
    for (int i = 0; i < conflicts.size(); i++) {
      ProgressManager.checkCanceled();
      CandidateInfo info = conflicts.get(i);
      PsiMethod method = (PsiMethod) info.getElement();

      if (!method.hasModifierProperty(PsiModifier.STATIC) && superMethods.contains(method)) {
        conflicts.remove(i);
        i--;
        continue;
      }

      PsiClass class1 = method.getContainingClass();
      PsiSubstitutor infoSubstitutor = ((MethodCandidateInfo) info).getSubstitutor(false);
      MethodSignature signature = method.getSignature(infoSubstitutor);
      CandidateInfo existing = signatures.get(signature);

      if (existing == null) {
        signatures.put(signature, info);
        continue;
      }
      PsiMethod existingMethod = (PsiMethod) existing.getElement();
      PsiClass existingClass = existingMethod.getContainingClass();
      if (class1 != null
          && existingClass != null) { // prefer interface methods to methods from Object
        if (class1.isInterface()
            && CommonClassNames.JAVA_LANG_OBJECT.equals(existingClass.getQualifiedName())) {
          signatures.put(signature, info);
          continue;
        } else if (existingClass.isInterface()
            && CommonClassNames.JAVA_LANG_OBJECT.equals(class1.getQualifiedName())) {
          conflicts.remove(info);
          i--;
          continue;
        }
      }
      if (method == existingMethod) {
        PsiElement scope1 = info.getCurrentFileResolveScope();
        PsiElement scope2 = existing.getCurrentFileResolveScope();
        if (scope1 instanceof PsiClass
            && scope2 instanceof PsiClass
            && PsiTreeUtil.isAncestor(scope1, scope2, true)
            && !existing
                .isAccessible()) { // prefer methods from outer class to inaccessible base class
                                   // methods
          signatures.put(signature, info);
          continue;
        }
      }

      // filter out methods with incorrect inferred bounds (for unrelated methods only)
      boolean existingTypeParamAgree = areTypeParametersAgree(existing);
      boolean infoTypeParamAgree = areTypeParametersAgree(info);
      if (existingTypeParamAgree
          && !infoTypeParamAgree
          && !PsiSuperMethodImplUtil.isSuperMethodSmart(method, existingMethod)) {
        conflicts.remove(i);
        i--;
        continue;
      }
      if (!existingTypeParamAgree
          && infoTypeParamAgree
          && !PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) {
        signatures.put(signature, info);
        int index = conflicts.indexOf(existing);
        conflicts.remove(index);
        i--;
        continue;
      }

      if (InheritanceUtil.isInheritorOrSelf(class1, existingClass, true)
          || InheritanceUtil.isInheritorOrSelf(existingClass, class1, true)) {
        PsiParameter[] parameters = method.getParameterList().getParameters();
        final PsiParameter[] existingParameters = existingMethod.getParameterList().getParameters();
        for (int i1 = 0, parametersLength = parameters.length; i1 < parametersLength; i1++) {
          if (parameters[i1].getType() instanceof PsiArrayType
              && !(existingParameters[i1].getType()
                  instanceof PsiArrayType)) { // prefer more specific type
            signatures.put(signature, info);
            continue nextConflict;
          }
        }
        PsiType returnType1 = method.getReturnType();
        PsiType returnType2 = existingMethod.getReturnType();
        if (returnType1 != null && returnType2 != null) {
          returnType1 = infoSubstitutor.substitute(returnType1);
          returnType2 =
              ((MethodCandidateInfo) existing).getSubstitutor(false).substitute(returnType2);
          if (!returnType1.equals(returnType2) && returnType1.isAssignableFrom(returnType2)) {
            conflicts.remove(i);
            i--;
            continue;
          }
        }

        // prefer derived class
        signatures.put(signature, info);
      } else {
        final PsiMethodCallExpression methodCallExpression =
            PsiTreeUtil.getParentOfType(myArgumentsList, PsiMethodCallExpression.class);
        if (methodCallExpression != null) {
          final PsiReferenceExpression expression = methodCallExpression.getMethodExpression();
          final PsiExpression qualifierExpression = expression.getQualifierExpression();
          PsiClass currentClass;
          if (qualifierExpression != null) {
            currentClass = PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType());
          } else {
            currentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
          }

          if (currentClass != null && existingClass != null && class1 != null) {
            final PsiSubstitutor eSubstitutor =
                TypeConversionUtil.getMaybeSuperClassSubstitutor(
                    existingClass, currentClass, PsiSubstitutor.EMPTY, null);
            final PsiSubstitutor cSubstitutor =
                TypeConversionUtil.getMaybeSuperClassSubstitutor(
                    class1, currentClass, PsiSubstitutor.EMPTY, null);
            if (eSubstitutor != null
                && cSubstitutor != null
                && MethodSignatureUtil.areSignaturesEqual(
                    existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) {
              final PsiType returnType = eSubstitutor.substitute(existingMethod.getReturnType());
              final PsiType returnType1 = cSubstitutor.substitute(method.getReturnType());
              if (returnType != null && returnType1 != null && !returnType1.equals(returnType)) {
                if (TypeConversionUtil.isAssignable(returnType, returnType1, false)) {
                  if (class1.isInterface() && !existingClass.isInterface()) continue;
                  conflicts.remove(existing);
                } else {
                  if (!TypeConversionUtil.isAssignable(returnType1, returnType, false)) continue;
                  conflicts.remove(i);
                }
                i--;
                break;
              }
            }
          }
        }
      }
    }
  }