Package com.google.test.metric.report.issues

Source Code of com.google.test.metric.report.issues.IssuesReporter

/*
* Copyright 2009 Google Inc.
*
* 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.google.test.metric.report.issues;

import com.google.test.metric.ClassCost;
import com.google.test.metric.GlobalCost;
import com.google.test.metric.MethodCost;
import com.google.test.metric.MethodInvocationCost;
import static com.google.test.metric.Reason.IMPLICIT_CONSTRUCTOR;
import static com.google.test.metric.Reason.IMPLICIT_SETTER;
import static com.google.test.metric.Reason.IMPLICIT_STATIC_INIT;
import com.google.test.metric.SourceLocation;
import com.google.test.metric.ViolationCost;
import static com.google.test.metric.report.issues.IssueSubType.COMPLEXITY;
import static com.google.test.metric.report.issues.IssueSubType.NON_MOCKABLE;
import static com.google.test.metric.report.issues.IssueSubType.SETTER;
import static com.google.test.metric.report.issues.IssueSubType.SINGLETON;
import static com.google.test.metric.report.issues.IssueSubType.STATIC_INIT;
import static com.google.test.metric.report.issues.IssueSubType.STATIC_METHOD;
import static com.google.test.metric.report.issues.IssueType.COLLABORATOR;
import static com.google.test.metric.report.issues.IssueType.CONSTRUCTION;
import static com.google.test.metric.report.issues.IssueType.DIRECT_COST;

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.logging.Logger;

/**
* Looks at ClassCost models and infers the coding issue that incurred the cost.
*
* @author alexeagle@google.com (Alex Eagle)
*/
public class IssuesReporter {

  private static final Logger logger = Logger.getLogger(IssuesReporter.class.getCanonicalName());
  private final Queue<ClassIssues> mostImportantIssues;
  private final HypotheticalCostModel costModel;

  public IssuesReporter(Queue<ClassIssues> mostImportantIssues, HypotheticalCostModel costModel) {
    this.mostImportantIssues = mostImportantIssues;
    this.costModel = costModel;
  }

  public void inspectClass(ClassCost classCost) {
    int cost = costModel.computeClass(classCost);
    ClassIssues classIssues = new ClassIssues(classCost.getClassName(), cost);
    if (mostImportantIssues.offer(classIssues)) {
      populateIssues(classCost, classIssues);
    }
  }

  public ClassIssues determineIssues(ClassCost classCost) {
    int cost = costModel.computeClass(classCost);
    ClassIssues classIssues = new ClassIssues(classCost.getClassName(), cost);
    populateIssues(classCost, classIssues);
    return classIssues;
  }

  private void populateIssues(ClassCost classCost, ClassIssues classIssues) {
    for (MethodCost methodCost : classCost.getMethods()) {
      addIssuesInMethod(classIssues, methodCost, classCost);
    }
    int cost;
    if (classIssues.isEmpty() && (cost = costModel.computeClass(classCost)) > 100) {
      logger.warning(String.format("No issues found in class %s which has a cost of %d",
          classCost.getClassName(), cost));
    }
  }

  void addIssuesInMethod(ClassIssues classIssues, MethodCost methodCost, ClassCost classCost) {
    if (methodCost.isStaticInit()) {
      addStaticInitializationIssues(classIssues, methodCost, classCost);
      return;
    }
    if (methodCost.getViolationCosts() == null || methodCost.getViolationCosts().isEmpty()) {
      // no issues to add
      return;
    }

    boolean issuesFound = false;
    for (ViolationCost violationCost : methodCost.getViolationCosts()) {
      if (violationCost instanceof MethodInvocationCost) {
        MethodInvocationCost invocationCost = (MethodInvocationCost) violationCost;
        if (invocationCost.getCostSourceType() != IMPLICIT_STATIC_INIT) {
          issuesFound = addMethodInvocationIssues(classIssues, methodCost, classCost, issuesFound,
              invocationCost);
        }
      }
    }
    if (methodCost.getDirectCost().getCyclomaticComplexityCost() > 0) {
      addDirectCostIssue(classIssues, methodCost, classCost);
    }
  }

  private void addStaticInitializationIssues(ClassIssues classIssues, MethodCost methodCost,
                                             ClassCost classCost) {
    for (ViolationCost violationCost : methodCost.getViolationCosts()) {
      float contribution = costModel.computeContributionFromIssue(classCost, methodCost, violationCost);
      classIssues.add(new Issue(violationCost.getLocation(), violationCost.getDescription(),
          contribution, CONSTRUCTION, STATIC_INIT));
    }
  }

  private void addDirectCostIssue(ClassIssues classIssues, MethodCost methodCost,
                                  ClassCost classCost) {
    float contributionToClassCost = costModel.computeContributionFromMethod(classCost, methodCost);
    Issue issue = new Issue(new SourceLocation(classCost.getClassName(), methodCost.getMethodLineNumber()),
        methodCost.getDescription(), contributionToClassCost, null, null);
    if (methodCost.isConstructor()) {
      issue.setType(CONSTRUCTION);
      issue.setSubType(COMPLEXITY);
    } else {
      issue.setLineNumberIsApproximate(true);
      issue.setType(DIRECT_COST);
      issue.setSubType(COMPLEXITY);
    }
    classIssues.add(issue);
  }

  private boolean addMethodInvocationIssues(ClassIssues classIssues, MethodCost methodCost,
                                            ClassCost classCost, boolean collaboratorIssuesFound,
                                            MethodInvocationCost invocationCost) {
    IssueType type;
    if (invocationCost.getCostSourceType() == IMPLICIT_CONSTRUCTOR ||
        invocationCost.getCostSourceType() == IMPLICIT_SETTER ||
        methodCost.isConstructor()) {
      type = CONSTRUCTION;
    } else {
      type = COLLABORATOR;
      collaboratorIssuesFound = true;
    }
    IssueSubType subType = null;
    switch (invocationCost.getCostSourceType()) {
      case IMPLICIT_CONSTRUCTOR:
        subType = COMPLEXITY;
        break;
      case IMPLICIT_SETTER:
        subType = SETTER;
        break;
      case NON_OVERRIDABLE_METHOD_CALL:
        if (invocationCost.getMethodCost().isStatic()) {
          subType = STATIC_METHOD;
        } else if (hasGlobalSource(invocationCost.getMethodCost())) {
          subType = SINGLETON;
        } else {
          subType = NON_MOCKABLE;
        }
        break;
    }

    classIssues.add(new Issue(invocationCost.getLocation(), invocationCost.getDescription(),
        costModel.computeContributionFromIssue(classCost, methodCost, invocationCost),
        type, subType));
    return collaboratorIssuesFound;
  }

  private boolean hasGlobalSource(MethodCost methodCost) {
    for (ViolationCost cost : methodCost.getViolationCosts()) {
      if (cost instanceof GlobalCost) {
        return true;
      }
    }
    return false;
  }

  public List<ClassIssues> getMostImportantIssues() {
    if (mostImportantIssues instanceof TriageIssuesQueue) {
      return ((TriageIssuesQueue<ClassIssues>) mostImportantIssues).asList();
    }
    return new ArrayList<ClassIssues>(mostImportantIssues);
  }
}
TOP

Related Classes of com.google.test.metric.report.issues.IssuesReporter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.