@Nullable
  private ProblemDescriptor[] checkMember(
      final PsiDocCommentOwner docCommentOwner,
      final InspectionManager manager,
      final boolean isOnTheFly) {
    final ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
    final PsiDocComment docComment = docCommentOwner.getDocComment();
    if (docComment == null) return null;

    final Set<PsiJavaCodeReferenceElement> references = new HashSet<PsiJavaCodeReferenceElement>();
    docComment.accept(getVisitor(references, docCommentOwner, problems, manager, isOnTheFly));
    for (PsiJavaCodeReferenceElement reference : references) {
      final List<PsiClass> classesToImport = new ImportClassFix(reference).getClassesToImport();
      final PsiElement referenceNameElement = reference.getReferenceNameElement();
      problems.add(
          manager.createProblemDescriptor(
              referenceNameElement != null ? referenceNameElement : reference,
              cannotResolveSymbolMessage("<code>" + reference.getText() + "</code>"),
              !isOnTheFly || classesToImport.isEmpty() ? null : new AddImportFix(classesToImport),
              ProblemHighlightType.LIKE_UNKNOWN_SYMBOL,
              isOnTheFly));
    }

    return problems.isEmpty() ? null : problems.toArray(new ProblemDescriptor[problems.size()]);
  }
  @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);
  }
Beispiel #3
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;
  }
 private static ProblemDescriptor createDescriptor(
     @NotNull PsiElement element, String template, InspectionManager manager, boolean onTheFly) {
   return manager.createProblemDescriptor(
       element, template, onTheFly, null, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
 }
  public static void visitRefInDocTag(
      final PsiDocTag tag,
      final JavadocManager manager,
      final PsiElement context,
      final ArrayList<ProblemDescriptor> problems,
      final InspectionManager inspectionManager,
      final boolean onTheFly) {
    final String tagName = tag.getName();
    final PsiDocTagValue value = tag.getValueElement();
    if (value == null) return;
    final JavadocTagInfo info = manager.getTagInfo(tagName);
    if (info != null && !info.isValidInContext(context)) return;
    final String message = info == null || !info.isInline() ? null : info.checkTagValue(value);
    if (message != null) {
      problems.add(createDescriptor(value, message, inspectionManager, onTheFly));
    }

    final PsiReference reference = value.getReference();
    if (reference == null) return;
    final PsiElement element = reference.resolve();
    if (element != null) return;
    final int textOffset = value.getTextOffset();
    if (textOffset == value.getTextRange().getEndOffset()) return;
    final PsiDocTagValue valueElement = tag.getValueElement();
    if (valueElement == null) return;

    final CharSequence paramName =
        value
            .getContainingFile()
            .getViewProvider()
            .getContents()
            .subSequence(textOffset, value.getTextRange().getEndOffset());
    final String params = "<code>" + paramName + "</code>";
    final List<LocalQuickFix> fixes = new ArrayList<LocalQuickFix>();
    if (onTheFly && "param".equals(tagName)) {
      final PsiDocCommentOwner commentOwner =
          PsiTreeUtil.getParentOfType(tag, PsiDocCommentOwner.class);
      if (commentOwner instanceof PsiMethod) {
        final PsiMethod method = (PsiMethod) commentOwner;
        final PsiParameter[] parameters = method.getParameterList().getParameters();
        final PsiDocTag[] tags = tag.getContainingComment().getTags();
        final Set<String> unboundParams = new HashSet<String>();
        for (PsiParameter parameter : parameters) {
          if (!JavaDocLocalInspection.isFound(tags, parameter)) {
            unboundParams.add(parameter.getName());
          }
        }
        if (!unboundParams.isEmpty()) {
          fixes.add(new RenameReferenceQuickFix(unboundParams));
        }
      }
    }
    fixes.add(new RemoveTagFix(tagName, paramName));

    problems.add(
        inspectionManager.createProblemDescriptor(
            valueElement,
            reference.getRangeInElement(),
            cannotResolveSymbolMessage(params),
            ProblemHighlightType.LIKE_UNKNOWN_SYMBOL,
            onTheFly,
            fixes.toArray(new LocalQuickFix[fixes.size()])));
  }
  @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;
  }
  public CommonProblemDescriptor[] checkElement(
      @NotNull final PsiElement psiElement, InspectionManager manager, Project project) {
    final Map<PsiElement, Collection<String>> suppressedScopes =
        new THashMap<PsiElement, Collection<String>>();
    psiElement.accept(
        new JavaRecursiveElementWalkingVisitor() {
          @Override
          public void visitModifierList(PsiModifierList list) {
            super.visitModifierList(list);
            final PsiElement parent = list.getParent();
            if (parent instanceof PsiModifierListOwner && !(parent instanceof PsiClass)) {
              checkElement(parent);
            }
          }

          @Override
          public void visitComment(PsiComment comment) {
            checkElement(comment);
          }

          @Override
          public void visitClass(PsiClass aClass) {
            if (aClass == psiElement) {
              super.visitClass(aClass);
              checkElement(aClass);
            }
          }

          private void checkElement(final PsiElement owner) {
            String idsString = SuppressManager.getInstance().getSuppressedInspectionIdsIn(owner);
            if (idsString != null && idsString.length() != 0) {
              List<String> ids = StringUtil.split(idsString, ",");
              if (IGNORE_ALL
                  && (ids.contains(SuppressionUtil.ALL)
                      || ids.contains(SuppressionUtil.ALL.toLowerCase()))) return;
              Collection<String> suppressed = suppressedScopes.get(owner);
              if (suppressed == null) {
                suppressed = ids;
              } else {
                for (String id : ids) {
                  if (!suppressed.contains(id)) {
                    suppressed.add(id);
                  }
                }
              }
              suppressedScopes.put(owner, suppressed);
            }
          }
        });

    if (suppressedScopes.values().isEmpty()) return null;
    // have to visit all file from scratch since inspections can be written in any perversive way
    // including checkFile() overriding
    Collection<InspectionTool> suppressedTools = new THashSet<InspectionTool>();
    InspectionTool[] tools = getInspectionTools(psiElement, manager);
    for (Collection<String> ids : suppressedScopes.values()) {
      for (Iterator<String> iterator = ids.iterator(); iterator.hasNext(); ) {
        final String shortName = iterator.next().trim();
        for (InspectionTool tool : tools) {
          if (tool instanceof LocalInspectionToolWrapper
              && ((LocalInspectionToolWrapper) tool).getTool().getID().equals(shortName)) {
            if (!((LocalInspectionToolWrapper) tool).isUnfair()) {
              suppressedTools.add(tool);
            } else {
              iterator.remove();
              break;
            }
          } else if (tool.getShortName().equals(shortName)) {
            // ignore global unused as it won't be checked anyway
            if (!(tool instanceof LocalInspectionToolWrapper)
                && !(tool instanceof GlobalInspectionToolWrapper)) {
              iterator.remove();
              break;
            } else {
              suppressedTools.add(tool);
            }
          }
        }
      }
    }

    final AnalysisScope scope = new AnalysisScope(psiElement.getContainingFile());
    final InspectionManagerEx inspectionManagerEx =
        ((InspectionManagerEx) InspectionManager.getInstance(project));
    GlobalInspectionContextImpl globalContext = inspectionManagerEx.createNewGlobalContext(false);
    globalContext.setCurrentScope(scope);
    final RefManagerImpl refManager = ((RefManagerImpl) globalContext.getRefManager());
    refManager.inspectionReadActionStarted();
    final List<ProblemDescriptor> result;
    try {
      result = new ArrayList<ProblemDescriptor>();
      for (InspectionTool tool : suppressedTools) {
        String toolId =
            tool instanceof LocalInspectionToolWrapper
                ? ((LocalInspectionToolWrapper) tool).getTool().getID()
                : tool.getShortName();
        tool.initialize(globalContext);
        Collection<CommonProblemDescriptor> descriptors;
        if (tool instanceof LocalInspectionToolWrapper) {
          LocalInspectionToolWrapper local = (LocalInspectionToolWrapper) tool;
          if (local.isUnfair()) continue; // cant't work with passes other than LocalInspectionPass
          local.processFile(psiElement.getContainingFile(), false, manager);
          descriptors = local.getProblemDescriptors();
        } else if (tool instanceof GlobalInspectionToolWrapper) {
          GlobalInspectionToolWrapper global = (GlobalInspectionToolWrapper) tool;
          if (global.getTool().isGraphNeeded()) {
            refManager.findAllDeclarations();
          }
          global.processFile(scope, manager, globalContext, false);
          descriptors = global.getProblemDescriptors();
        } else {
          continue;
        }
        for (PsiElement suppressedScope : suppressedScopes.keySet()) {
          Collection<String> suppressedIds = suppressedScopes.get(suppressedScope);
          if (!suppressedIds.contains(toolId)) continue;
          for (CommonProblemDescriptor descriptor : descriptors) {
            if (!(descriptor instanceof ProblemDescriptor)) continue;
            PsiElement element = ((ProblemDescriptor) descriptor).getPsiElement();
            if (element == null) continue;
            PsiElement annotation =
                SuppressManager.getInstance().getElementToolSuppressedIn(element, toolId);
            if (annotation != null && PsiTreeUtil.isAncestor(suppressedScope, annotation, false)
                || annotation == null && !PsiTreeUtil.isAncestor(suppressedScope, element, false)) {
              suppressedIds.remove(toolId);
              break;
            }
          }
        }
      }
      for (PsiElement suppressedScope : suppressedScopes.keySet()) {
        Collection<String> suppressedIds = suppressedScopes.get(suppressedScope);
        for (String toolId : suppressedIds) {
          PsiMember psiMember;
          String problemLine = null;
          if (suppressedScope instanceof PsiMember) {
            psiMember = (PsiMember) suppressedScope;
          } else {
            psiMember = PsiTreeUtil.getParentOfType(suppressedScope, PsiDocCommentOwner.class);
            final PsiStatement statement =
                PsiTreeUtil.getNextSiblingOfType(suppressedScope, PsiStatement.class);
            problemLine = statement != null ? statement.getText() : null;
          }
          if (psiMember != null && psiMember.isValid()) {
            String description =
                InspectionsBundle.message("inspection.redundant.suppression.description");
            if (myQuickFixes == null) myQuickFixes = new BidirectionalMap<String, QuickFix>();
            final String key = toolId + (problemLine != null ? ";" + problemLine : "");
            QuickFix fix = myQuickFixes.get(key);
            if (fix == null) {
              fix = new RemoveSuppressWarningAction(toolId, problemLine);
              myQuickFixes.put(key, fix);
            }
            PsiElement identifier = null;
            if (psiMember instanceof PsiMethod) {
              identifier = ((PsiMethod) psiMember).getNameIdentifier();
            } else if (psiMember instanceof PsiField) {
              identifier = ((PsiField) psiMember).getNameIdentifier();
            } else if (psiMember instanceof PsiClass) {
              identifier = ((PsiClass) psiMember).getNameIdentifier();
            }
            if (identifier == null) {
              identifier = psiMember;
            }
            result.add(
                manager.createProblemDescriptor(
                    identifier,
                    description,
                    (LocalQuickFix) fix,
                    ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
                    false));
          }
        }
      }
    } finally {
      refManager.inspectionReadActionFinished();
      globalContext.close(true);
    }
    return result.toArray(new ProblemDescriptor[result.size()]);
  }