/* * Sonar Useless Code Tracker Plugin * Copyright (C) 2010 SonarSource * dev@sonar.codehaus.org * * 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.uselesscodetracker; import net.sourceforge.pmd.cpd.AbstractLanguage; import net.sourceforge.pmd.cpd.TokenEntry; import org.apache.commons.configuration.Configuration; import org.sonar.api.CoreProperties; import org.sonar.api.batch.CpdMapping; import org.sonar.api.batch.Sensor; import org.sonar.api.batch.SensorContext; import org.sonar.api.resources.Java; import org.sonar.api.resources.Language; import org.sonar.api.resources.Project; import org.sonar.duplications.cpd.CPD; import java.io.IOException; import java.nio.charset.Charset; public class TrackerSensor implements Sensor { private CpdMapping[] mappings; public TrackerSensor(CpdMapping[] mappings) { this.mappings = mappings; } public boolean shouldExecuteOnProject(Project project) { if (isSkipped(project)) { return false; } if(Java.INSTANCE.equals(project.getLanguage())) { return true; } return false; } boolean isSkipped(Project project) { Configuration conf = project.getConfiguration(); return conf.getBoolean("sonar.cpd." + project.getLanguageKey() + ".skip", conf.getBoolean("sonar.cpd.skip", false)); } public void analyse(Project project, SensorContext context) { CpdMapping mapping = getMapping(project.getLanguage()); CPD cpd = executeCPD(project, mapping, project.getFileSystem().getSourceCharset()); saveResults(cpd, project, context); } private CpdMapping getMapping(Language language) { for (CpdMapping cpdMapping : mappings) { if (cpdMapping.getLanguage().equals(language)) { return cpdMapping; } } return null; } private void saveResults(CPD cpd, Project project, SensorContext context) { DuplicationAnalyser duplicationAnalyser = new DuplicationAnalyser(project, context); duplicationAnalyser.analyse(cpd.getMatches()); } private CPD executeCPD(Project project, CpdMapping mapping, Charset encoding) { try { CPD cpd = configureCPD(project, mapping, encoding); cpd.go(); return cpd; } catch (Exception e) { throw new TrackerException(e); } } private CPD configureCPD(Project project, CpdMapping mapping, Charset encoding) throws IOException { // To avoid a uselesscodetracker bug generating error as "java.lang.IndexOutOfBoundsException: Index: 259, Size: 248" // See http://sourceforge.net/tracker/?func=detail&atid=479921&aid=1947823&group_id=56262 for more details TokenEntry.clearImages(); int minTokens = getMinimumTokens(project); AbstractLanguage cpdLanguage = new AbstractLanguage(mapping.getTokenizer()) { }; CPD cpd = new CPD(minTokens, cpdLanguage); cpd.setEncoding(encoding.name()); cpd.setLoadSourceCodeSlices(false); cpd.add(project.getFileSystem().getSourceFiles(project.getLanguage())); return cpd; } int getMinimumTokens(Project project) { Configuration conf = project.getConfiguration(); return conf.getInt("sonar.cpd." + project.getLanguageKey() + ".minimumTokens", conf.getInt("sonar.cpd.minimumTokens", CoreProperties.CPD_MINIMUM_TOKENS_DEFAULT_VALUE)); } @Override public String toString() { return getClass().getSimpleName(); } }