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

org.sonar.plugins.csharp.fxcop.FxCopResultParser Maven / Gradle / Ivy

There is a newer version: 2.1
Show newest version
/*
 * Sonar .NET Plugin :: FxCop
 * Copyright (C) 2010 Jose Chillan, Alexandre Victoor and SonarSource
 * [email protected]
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonar.plugins.csharp.fxcop;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMEvent;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchExtension;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RuleQuery;
import org.sonar.api.rules.Violation;
import org.sonar.api.utils.SonarException;
import org.sonar.plugins.dotnet.api.DotNetResourceBridge;
import org.sonar.plugins.dotnet.api.DotNetResourceBridges;
import org.sonar.plugins.dotnet.api.microsoft.MicrosoftWindowsEnvironment;
import org.sonar.plugins.dotnet.api.microsoft.VisualStudioProject;
import org.sonar.plugins.dotnet.api.microsoft.VisualStudioSolution;
import org.sonar.plugins.dotnet.api.utils.ResourceHelper;
import org.sonar.plugins.dotnet.api.utils.StaxParserUtils;

import javax.xml.stream.XMLStreamException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;

/**
 * Parses the reports generated by a FXCop analysis.
 */
public class FxCopResultParser implements BatchExtension {

  private static final Logger LOG = LoggerFactory.getLogger(FxCopResultParser.class);
  private static final String NAMESPACE = "Namespace";
  private static final String NAMESPACES = "Namespaces";
  private static final String TARGETS = "Targets";
  private static final String MESSAGE = "Message";
  private static final String MESSAGES = "Messages";
  private static final String MODULE = "Module";
  private static final String NAME = "Name";
  private static final String TYPENAME = "TypeName";
  private static final String LINE = "Line";

  private final VisualStudioSolution vsSolution;
  private VisualStudioProject vsProject;
  private Project project;
  private SensorContext context;
  private RuleFinder ruleFinder;
  private DotNetResourceBridge resourceBridge;
  private ResourceHelper resourceHelper;
  private String repositoryKey;

  /**
   * Constructs a @link{FxCopResultParser}.
   * 
   * @param project
   * @param context
   * @param rulesManager
   * @param profile
   */
  public FxCopResultParser(MicrosoftWindowsEnvironment env, Project project, SensorContext context, RuleFinder ruleFinder,
      DotNetResourceBridges dotNetResourceBridges, ResourceHelper resourceHelper) {
    super();
    this.vsSolution = env.getCurrentSolution();
    if (vsSolution == null) {
      // not a .NET project
      return;
    }
    this.vsProject = vsSolution.getProjectFromSonarProject(project);

    this.project = project;
    this.context = context;
    this.ruleFinder = ruleFinder;
    this.resourceHelper = resourceHelper;
    this.resourceBridge = dotNetResourceBridges.getBridge(project.getLanguageKey());
  }

  /**
   * Parses a processed violation file.
   * 
   * @param file
   *          the file to parse
   */
  public void parse(File file) {

    repositoryKey =
        vsProject.isTest() ? FxCopConstants.TEST_REPOSITORY_KEY : FxCopConstants.REPOSITORY_KEY;
    if (!"cs".equals(project.getLanguageKey())) {
      // every repository key should be "fxcop-", except for C# for which it is simply "fxcop" (for backward compatibility)
      repositoryKey += "-" + project.getLanguageKey();
    }

    SMInputFactory inputFactory = StaxParserUtils.initStax();
    FileInputStream fileInputStream = null;
    try {
      fileInputStream = new FileInputStream(file);
      SMHierarchicCursor cursor = inputFactory.rootElementCursor(new InputStreamReader(fileInputStream, project.getFileSystem().getSourceCharset()));
      SMInputCursor mainCursor = cursor.advance().childElementCursor();
      while (mainCursor.getNext() != null) {
        if (NAMESPACES.equals(mainCursor.getQName().getLocalPart())) {
          parseNamespacesBloc(mainCursor);
        } else if (TARGETS.equals(mainCursor.getQName().getLocalPart())) {
          parseTargetsBloc(mainCursor);
        }
      }
      cursor.getStreamReader().closeCompletely();
    } catch (XMLStreamException e) {
      throw new SonarException("Error while reading FxCop result file: " + file.getAbsolutePath(), e);
    } catch (FileNotFoundException e) {
      throw new SonarException("Cannot find FxCop result file: " + file.getAbsolutePath(), e);
    } finally {
      IOUtils.closeQuietly(fileInputStream);
    }
  }

  private void parseNamespacesBloc(SMInputCursor cursor) throws XMLStreamException {
    // Cursor in on 
    SMInputCursor namespacesCursor = cursor.childElementCursor(NAMESPACE);
    while (namespacesCursor.getNext() != null) {
      SMInputCursor messagesCursor = namespacesCursor.descendantElementCursor(MESSAGE);
      while (messagesCursor.getNext() != null) {
        createViolationFromMessageAtProjectLevel(messagesCursor);
      }
    }
  }

  private void parseTargetsBloc(SMInputCursor cursor) throws XMLStreamException {
    // Cursor on 
    SMInputCursor modulesCursor = cursor.descendantElementCursor(MODULE);
    while (modulesCursor.getNext() != null) {
      parseModuleMessagesBloc(modulesCursor);
    }
  }

  private void parseModuleMessagesBloc(SMInputCursor cursor) throws XMLStreamException {
    // Cursor on 
    SMInputCursor moduleChildrenCursor = cursor.childElementCursor();
    while (moduleChildrenCursor.getNext() != null) {
      if (MESSAGES.equals(moduleChildrenCursor.getQName().getLocalPart())) {
        // We are on , look for 
        SMInputCursor messagesCursor = moduleChildrenCursor.childElementCursor(MESSAGE);
        while (messagesCursor.getNext() != null) {
          createViolationFromMessageAtProjectLevel(messagesCursor);
        }
      } else if (NAMESPACES.equals(moduleChildrenCursor.getQName().getLocalPart())) {
        // We are on , get 
        SMInputCursor namespaceCursor = moduleChildrenCursor.childElementCursor();
        while (namespaceCursor.getNext() != null) {
          String namespaceName = namespaceCursor.getAttrValue(NAME);
          SMInputCursor typeCursor = namespaceCursor.childElementCursor().advance().childElementCursor();
          while (typeCursor.getNext() != null) {
            parseTypeBloc(namespaceName, typeCursor);
          }
        }
      }
    }
  }

  private void parseTypeBloc(String namespaceName, SMInputCursor cursor) throws XMLStreamException {
    // Cursor on 
    String typeName = cursor.getAttrValue(NAME);
    Resource typeResource = resourceBridge.getFromTypeName(namespaceName, typeName);
    SMInputCursor messagesCursor = cursor.descendantElementCursor(MESSAGE);
    while (messagesCursor.getNext() != null) {
      // Cursor on 
      if (messagesCursor.getCurrEvent() == SMEvent.START_ELEMENT) {

        Rule currentRule = ruleFinder.find(RuleQuery.create().withRepositoryKey(repositoryKey)
            .withKey(messagesCursor.getAttrValue(TYPENAME)));
        if (currentRule != null) {
          // look for all potential issues
          searchForViolations(messagesCursor, typeResource, currentRule);
        } else {
          LOG.warn("Could not find the following rule in the FxCop rule repository: " + messagesCursor.getAttrValue(TYPENAME));
        }

      }
    }
  }

  protected void searchForViolations(SMInputCursor messagesCursor, Resource typeResource, Rule currentRule) throws XMLStreamException {
    SMInputCursor issueCursor = messagesCursor.childElementCursor();
    while (issueCursor.getNext() != null) {
      final Resource resource;
      final boolean saveViolation;
      String path = issueCursor.getAttrValue("Path");
      String file = issueCursor.getAttrValue("File");
      if (StringUtils.isNotEmpty(path) && StringUtils.isNotEmpty(file)) {
        File sourceFile = new File(path, file).getAbsoluteFile();
        VisualStudioProject currentVsProject = vsSolution.getProject(sourceFile);
        if (vsProject.equals(currentVsProject)) {
          if (vsProject.isTest()) {
            resource = org.sonar.api.resources.File.fromIOFile(sourceFile, project.getFileSystem().getTestDirs());
          } else {
            resource = org.sonar.api.resources.File.fromIOFile(sourceFile, project);
          }
          saveViolation = true;
        } else {
          LOG.debug("Ignoring file outside current project : {}", sourceFile);
          resource = null;
          saveViolation = false;
        }
      } else if (typeResource == null || resourceHelper.isResourceInProject(typeResource, project)) {
        resource = typeResource;
        saveViolation = true;
      } else {
        resource = null;
        saveViolation = false;
      }

      if (saveViolation) {
        // Cursor on Issue
        Violation violation = Violation.create(currentRule, resource);
        String lineNumber = issueCursor.getAttrValue(LINE);
        if (lineNumber != null) {
          violation.setLineId(Integer.parseInt(lineNumber));
        }
        violation.setMessage(issueCursor.collectDescendantText().trim());
        violation.setSeverity(currentRule.getSeverity());
        context.saveViolation(violation);
      }
    }
  }

  private void createViolationFromMessageAtProjectLevel(SMInputCursor messagesCursor) throws XMLStreamException {
    Rule currentRule = ruleFinder.find(RuleQuery.create().withRepositoryKey(repositoryKey)
        .withKey(messagesCursor.getAttrValue(TYPENAME)));
    if (currentRule != null) {
      // the violation is saved at project level, not on a specific resource
      Violation violation = Violation.create(currentRule, project);
      violation.setMessage(messagesCursor.collectDescendantText().trim());
      violation.setSeverity(currentRule.getSeverity());
      context.saveViolation(violation);
    } else {
      LOG.debug("Could not find the following rule in the FxCop rule repository: " + messagesCursor.getAttrValue(TYPENAME));
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy