All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.siyeh.ig.errorhandling.TooBroadThrowsInspectionBase Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition java-analysis-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2010-2015 Bas Leijdekkers
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.siyeh.ig.errorhandling;

import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.ExceptionUtils;
import com.siyeh.ig.psiutils.LibraryUtil;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.util.*;

public class TooBroadThrowsInspectionBase extends BaseInspection {

  @SuppressWarnings({"PublicField"})
  public boolean onlyWarnOnRootExceptions = false;

  @SuppressWarnings({"PublicField", "UnusedDeclaration"})
  public boolean ignoreInTestCode = false; // keep for compatibility

  @SuppressWarnings("PublicField")
  public boolean ignoreLibraryOverrides = false;

  @SuppressWarnings("PublicField")
  public boolean ignoreThrown = false;

  @Override
  @NotNull
  public String getID() {
    return "OverlyBroadThrowsClause";
  }

  @Override
  @NotNull
  public String getDisplayName() {
    return InspectionGadgetsBundle.message("overly.broad.throws.clause.display.name");
  }

  @Override
  @NotNull
  protected String buildErrorString(Object... infos) {
    final List typesMasked = (List)infos[0];
    final PsiType type = typesMasked.get(0).getType();
    String typesMaskedString = type != null ? type.getPresentableText() : "";
    if (typesMasked.size() == 1) {
      return InspectionGadgetsBundle.message(
        "overly.broad.throws.clause.problem.descriptor1",
        typesMaskedString);
    }
    else {
      final int lastTypeIndex = typesMasked.size() - 1;
      for (int i = 1; i < lastTypeIndex; i++) {
        final PsiType psiType = typesMasked.get(i).getType();
        if (psiType != null) {
          typesMaskedString += ", ";
          typesMaskedString += psiType.getPresentableText();
        }
      }
      final PsiType psiType = typesMasked.get(lastTypeIndex).getType();
      final String lastTypeString = psiType != null ? psiType.getPresentableText() : "";
      return InspectionGadgetsBundle.message("overly.broad.throws.clause.problem.descriptor2", typesMaskedString, lastTypeString);
    }
  }

  @Override
  public JComponent createOptionsPanel() {
    final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this);
    panel.addCheckbox(InspectionGadgetsBundle.message("too.broad.catch.option"), "onlyWarnOnRootExceptions");
    panel.addCheckbox(InspectionGadgetsBundle.message("ignore.exceptions.declared.on.library.override.option"), "ignoreLibraryOverrides");
    panel.addCheckbox(InspectionGadgetsBundle.message("overly.broad.throws.clause.ignore.thrown.option"), "ignoreThrown");
    return panel;
  }

  @NotNull
  @Override
  protected InspectionGadgetsFix buildFix(Object... infos) {
    final Collection maskedExceptions = (Collection)infos[0];
    final Boolean originalNeeded = (Boolean)infos[1];
    return new AddThrowsClauseFix(maskedExceptions, originalNeeded.booleanValue());
  }

  private static class AddThrowsClauseFix extends InspectionGadgetsFix {

    private final Collection types;
    private final boolean originalNeeded;

    AddThrowsClauseFix(Collection types, boolean originalNeeded) {
      this.types = types;
      this.originalNeeded = originalNeeded;
    }

    @Override
    @NotNull
    public String getName() {
      if (originalNeeded) {
        return InspectionGadgetsBundle.message("overly.broad.throws.clause.quickfix1");
      }
      else {
        return InspectionGadgetsBundle.message("overly.broad.throws.clause.quickfix2");
      }
    }

    @NotNull
    @Override
    public String getFamilyName() {
      return "Fix 'throws' clause";
    }

    @Override
    protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
      final PsiElement element = descriptor.getPsiElement();
      final PsiElement parent = element.getParent();
      if (!(parent instanceof PsiReferenceList)) {
        return;
      }
      final PsiReferenceList referenceList = (PsiReferenceList)parent;
      final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
      if (!originalNeeded) {
        element.delete();
      }
      for (SmartTypePointer type : types) {
        final PsiType psiType = type.getType();
        if (psiType instanceof PsiClassType) {
          final PsiJavaCodeReferenceElement referenceElement = factory.createReferenceElementByType((PsiClassType)psiType);
          referenceList.add(referenceElement);
        }
      }
    }
  }

  @Override
  public BaseInspectionVisitor buildVisitor() {
    return new TooBroadThrowsVisitor();
  }

  private class TooBroadThrowsVisitor extends BaseInspectionVisitor {

    @Override
    public void visitMethod(PsiMethod method) {
      super.visitMethod(method);
      final PsiReferenceList throwsList = method.getThrowsList();
      if (!throwsList.isPhysical()) {
        return;
      }
      final PsiJavaCodeReferenceElement[] throwsReferences = throwsList.getReferenceElements();
      if (throwsReferences.length == 0) {
        return;
      }
      final PsiCodeBlock body = method.getBody();
      if (body == null) {
        return;
      }
      if (ignoreLibraryOverrides && LibraryUtil.isOverrideOfLibraryMethod(method)) {
        return;
      }
      final Set exceptionsThrown = ExceptionUtils.calculateExceptionsThrown(body);
      final PsiClassType[] referencedExceptions = throwsList.getReferencedTypes();
      final Set exceptionsDeclared = new HashSet(referencedExceptions.length);
      ContainerUtil.addAll(exceptionsDeclared, referencedExceptions);
      final int referencedExceptionsLength = referencedExceptions.length;
      for (int i = 0; i < referencedExceptionsLength; i++) {
        final PsiClassType referencedException = referencedExceptions[i];
        if (onlyWarnOnRootExceptions) {
          if (!ExceptionUtils.isGenericExceptionClass(
            referencedException)) {
            continue;
          }
        }
        final List exceptionsMasked = new ArrayList();
        final SmartTypePointerManager pointerManager = SmartTypePointerManager.getInstance(body.getProject());
        for (PsiType exceptionThrown : exceptionsThrown) {
          if (referencedException.isAssignableFrom(exceptionThrown) && !exceptionsDeclared.contains(exceptionThrown)) {
            exceptionsMasked.add(pointerManager.createSmartTypePointer(exceptionThrown));
          }
        }
        if (!exceptionsMasked.isEmpty()) {
          final PsiJavaCodeReferenceElement throwsReference = throwsReferences[i];
          final boolean originalNeeded = exceptionsThrown.contains(referencedException);
          if (ignoreThrown && originalNeeded) {
            continue;
          }
          registerError(throwsReference, exceptionsMasked, Boolean.valueOf(originalNeeded), throwsReference);
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy