private boolean isAccessible(
      RefJavaElement to, @PsiModifier.ModifierConstant String accessModifier) {

    for (RefElement refElement : to.getInReferences()) {
      if (!isAccessibleFrom(refElement, to, accessModifier)) return false;
    }

    if (to instanceof RefMethod) {
      RefMethod refMethod = (RefMethod) to;

      if (refMethod.isAbstract()
          && (refMethod.getDerivedMethods().isEmpty()
              || refMethod.getAccessModifier() == PsiModifier.PRIVATE)) return false;

      for (RefMethod refOverride : refMethod.getDerivedMethods()) {
        if (!isAccessibleFrom(refOverride, to, accessModifier)) return false;
      }

      for (RefMethod refSuper : refMethod.getSuperMethods()) {
        if (RefJavaUtil.getInstance().compareAccess(refSuper.getAccessModifier(), accessModifier)
            > 0) return false;
      }
    }

    if (to instanceof RefClass) {
      RefClass refClass = (RefClass) to;
      for (RefClass subClass : refClass.getSubClasses()) {
        if (!isAccessibleFrom(subClass, to, accessModifier)) return false;
      }

      List children = refClass.getChildren();
      if (children != null) {
        for (Object refElement : children) {
          if (!isAccessible((RefJavaElement) refElement, accessModifier)) return false;
        }
      }

      for (final RefElement refElement : refClass.getInTypeReferences()) {
        if (!isAccessibleFrom(refElement, refClass, accessModifier)) return false;
      }

      List<RefJavaElement> classExporters = ((RefClassImpl) refClass).getClassExporters();
      if (classExporters != null) {
        for (RefJavaElement refExporter : classExporters) {
          if (getAccessLevel(accessModifier) < getAccessLevel(refExporter.getAccessModifier()))
            return false;
        }
      }
    }

    return true;
  }
예제 #2
0
  @Override
  @Nullable
  public CommonProblemDescriptor[] checkElement(
      @NotNull final RefEntity refEntity,
      @NotNull final AnalysisScope scope,
      @NotNull final InspectionManager manager,
      @NotNull final GlobalInspectionContext globalContext,
      @NotNull final ProblemDescriptionsProcessor processor) {
    if (refEntity instanceof RefJavaElement) {
      final RefJavaElement refElement = (RefJavaElement) refEntity;
      if (refElement instanceof RefParameter) return null;
      if (!refElement.isReferenced()) return null;
      if (refElement.isSyntheticJSP()) return null;
      if (refElement.isFinal()) return null;
      if (!((RefElementImpl) refElement).checkFlag(CanBeFinalAnnotator.CAN_BE_FINAL_MASK))
        return null;

      final PsiMember psiMember = (PsiMember) refElement.getElement();
      if (psiMember == null || !CanBeFinalHandler.allowToBeFinal(psiMember)) return null;

      PsiIdentifier psiIdentifier = null;
      if (refElement instanceof RefClass) {
        RefClass refClass = (RefClass) refElement;
        if (refClass.isInterface() || refClass.isAnonymous() || refClass.isAbstract()) return null;
        if (!isReportClasses()) return null;
        psiIdentifier = ((PsiClass) psiMember).getNameIdentifier();
      } else if (refElement instanceof RefMethod) {
        RefMethod refMethod = (RefMethod) refElement;
        if (refMethod.getOwnerClass().isFinal()) return null;
        if (!isReportMethods()) return null;
        psiIdentifier = ((PsiMethod) psiMember).getNameIdentifier();
      } else if (refElement instanceof RefField) {
        if (!isReportFields()) return null;
        psiIdentifier = ((PsiField) psiMember).getNameIdentifier();
      }

      if (psiIdentifier != null) {
        return new ProblemDescriptor[] {
          manager.createProblemDescriptor(
              psiIdentifier,
              InspectionsBundle.message("inspection.export.results.can.be.final.description"),
              new AcceptSuggested(globalContext.getRefManager()),
              ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
              false)
        };
      }
    }
    return null;
  }
  @Nullable
  @PsiModifier.ModifierConstant
  public String getPossibleAccess(@Nullable RefJavaElement refElement) {
    if (refElement == null) return null;
    String curAccess = refElement.getAccessModifier();
    String weakestAccess = PsiModifier.PRIVATE;

    if (isTopLevelClass(refElement) || isCalledOnSubClasses(refElement)) {
      weakestAccess = PsiModifier.PACKAGE_LOCAL;
    }

    if (isAbstractMethod(refElement)) {
      weakestAccess = PsiModifier.PROTECTED;
    }

    if (curAccess == weakestAccess) return curAccess;

    while (true) {
      String weakerAccess = getWeakerAccess(curAccess, refElement);
      if (weakerAccess == null
          || RefJavaUtil.getInstance().compareAccess(weakerAccess, weakestAccess) < 0) break;
      if (isAccessible(refElement, weakerAccess)) {
        curAccess = weakerAccess;
      } else {
        break;
      }
    }

    return curAccess;
  }
  private boolean isAccessibleFrom(RefElement from, RefJavaElement to, String accessModifier) {
    if (accessModifier == PsiModifier.PUBLIC) return true;

    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
    if (accessModifier == PsiModifier.PACKAGE_LOCAL) {
      return RefJavaUtil.getPackage(from) == RefJavaUtil.getPackage(to);
    }

    RefClass fromTopLevel = refUtil.getTopLevelClass(from);
    RefClass toTopLevel = refUtil.getTopLevelClass(to);
    RefClass fromOwner = refUtil.getOwnerClass(from);
    RefClass toOwner = refUtil.getOwnerClass(to);

    if (accessModifier == PsiModifier.PROTECTED) {
      if (SUGGEST_PRIVATE_FOR_INNERS) {
        return refUtil.isInheritor(fromTopLevel, toOwner)
            || fromOwner != null && refUtil.isInheritor(fromOwner, toTopLevel)
            || toOwner != null && refUtil.getOwnerClass(toOwner) == from;
      }

      return refUtil.isInheritor(fromTopLevel, toOwner);
    }

    if (accessModifier == PsiModifier.PRIVATE) {
      if (SUGGEST_PRIVATE_FOR_INNERS) {
        if (isInExtendsList(to, fromTopLevel.getElement().getExtendsList())) return false;
        if (isInExtendsList(to, fromTopLevel.getElement().getImplementsList())) return false;
        if (isInAnnotations(to, fromTopLevel)) return false;
        return fromTopLevel == toOwner
            || fromOwner == toTopLevel
            || toOwner != null && refUtil.getOwnerClass(toOwner) == from;
      }

      if (fromOwner != null
          && fromOwner.isStatic()
          && !to.isStatic()
          && refUtil.isInheritor(fromOwner, toOwner)) return false;

      if (fromTopLevel == toOwner) {
        if (from instanceof RefClass && to instanceof RefClass) {
          final PsiClass fromClass = ((RefClass) from).getElement();
          LOG.assertTrue(fromClass != null);
          if (isInExtendsList(to, fromClass.getExtendsList())) return false;
          if (isInExtendsList(to, fromClass.getImplementsList())) return false;
        }

        return true;
      }
    }

    return false;
  }
 private static boolean isInExtendsList(
     final RefJavaElement to, final PsiReferenceList extendsList) {
   if (extendsList != null) {
     final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements();
     for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
       final PsiReferenceParameterList parameterList = referenceElement.getParameterList();
       if (parameterList != null) {
         for (PsiType type : parameterList.getTypeArguments()) {
           if (extendsList
               .getManager()
               .areElementsEquivalent(PsiUtil.resolveClassInType(type), to.getElement())) {
             return true;
           }
         }
       }
     }
   }
   return false;
 }
  private static boolean isInAnnotations(final RefJavaElement to, final RefClass fromTopLevel) {
    final PsiModifierList modifierList = fromTopLevel.getElement().getModifierList();
    if (modifierList == null) return false;
    final PsiElement toElement = to.getElement();

    final boolean[] resolved = new boolean[] {false};
    modifierList.accept(
        new JavaRecursiveElementWalkingVisitor() {
          @Override
          public void visitReferenceExpression(PsiReferenceExpression expression) {
            if (resolved[0]) return;
            super.visitReferenceExpression(expression);
            if (expression.resolve() == toElement) {
              resolved[0] = true;
            }
          }
        });
    return resolved[0];
  }
  @Override
  @Nullable
  public CommonProblemDescriptor[] checkElement(
      @NotNull final RefEntity refEntity,
      @NotNull final AnalysisScope scope,
      @NotNull final InspectionManager manager,
      @NotNull final GlobalInspectionContext globalContext,
      @NotNull final ProblemDescriptionsProcessor processor) {
    if (refEntity instanceof RefJavaElement) {
      final RefJavaElement refElement = (RefJavaElement) refEntity;

      if (refElement instanceof RefParameter) return null;
      if (refElement.isSyntheticJSP()) return null;

      // ignore entry points.
      if (refElement.isEntry()) return null;

      // ignore implicit constructors. User should not be able to see them.
      if (refElement instanceof RefImplicitConstructor) return null;

      if (refElement instanceof RefField
          && ((RefField) refElement).getElement() instanceof PsiEnumConstant) return null;

      // ignore library override methods.
      if (refElement instanceof RefMethod) {
        RefMethod refMethod = (RefMethod) refElement;
        if (refMethod.isExternalOverride()) return null;
        if (refMethod.isEntry()) return null;
      }

      // ignore anonymous classes. They do not have access modifiers.
      if (refElement instanceof RefClass) {
        RefClass refClass = (RefClass) refElement;
        if (refClass.isAnonymous()
            || refClass.isEntry()
            || refClass.isTestCase()
            || refClass.isServlet()
            || refClass.isApplet()
            || refClass.isLocalClass()) return null;
        if (isTopLevelClass(refClass) && !SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES) return null;
      }

      // ignore unreferenced code. They could be a potential entry points.
      if (refElement.getInReferences().isEmpty()) return null;

      // ignore interface members. They always have public access modifier.
      if (refElement.getOwner() instanceof RefClass) {
        RefClass refClass = (RefClass) refElement.getOwner();
        if (refClass.isInterface()) return null;
      }
      String access = getPossibleAccess(refElement);
      if (access != refElement.getAccessModifier() && access != null) {
        final PsiElement element = refElement.getElement();
        final PsiElement nameIdentifier =
            element != null ? HighlightUsagesHandler.getNameIdentifier(element) : null;
        if (nameIdentifier != null) {
          return new ProblemDescriptor[] {
            manager.createProblemDescriptor(
                nameIdentifier,
                access.equals(PsiModifier.PRIVATE)
                    ? CAN_BE_PRIVATE
                    : access.equals(PsiModifier.PACKAGE_LOCAL)
                        ? CAN_BE_PACKAGE_LOCAL
                        : CAN_BE_PROTECTED,
                new AcceptSuggestedAccess(globalContext.getRefManager(), access),
                ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
                false)
          };
        }
      }
    }
    return null;
  }