@@ -110,22 +110,7 @@ public class DefaultCpdEngine extends CpdEngine { | |||
// Create index | |||
SonarDuplicationsIndex index = indexFactory.create(project, languageKey); | |||
TokenizerBridge bridge = null; | |||
if (mapping != null) { | |||
bridge = new TokenizerBridge(mapping.getTokenizer(), fs.encoding().name(), getBlockSize(languageKey)); | |||
} | |||
for (InputFile inputFile : sourceFiles) { | |||
LOG.debug("Populating index from {}", inputFile); | |||
String resourceEffectiveKey = ((DeprecatedDefaultInputFile) inputFile).key(); | |||
FileBlocks fileBlocks = duplicationCache.byComponent(resourceEffectiveKey); | |||
if (fileBlocks != null) { | |||
index.insert(inputFile, fileBlocks.blocks()); | |||
} else if (bridge != null) { | |||
List<Block> blocks2 = bridge.chunk(resourceEffectiveKey, inputFile.file()); | |||
index.insert(inputFile, blocks2); | |||
} | |||
} | |||
populateIndex(languageKey, sourceFiles, mapping, index); | |||
// Detect | |||
Predicate<CloneGroup> minimumTokensPredicate = DuplicationPredicates.numberOfUnitsNotLessThan(getMinimumTokens(languageKey)); | |||
@@ -157,6 +142,24 @@ public class DefaultCpdEngine extends CpdEngine { | |||
} | |||
} | |||
private void populateIndex(String languageKey, List<InputFile> sourceFiles, CpdMapping mapping, SonarDuplicationsIndex index) { | |||
TokenizerBridge bridge = null; | |||
if (mapping != null) { | |||
bridge = new TokenizerBridge(mapping.getTokenizer(), fs.encoding().name(), getBlockSize(languageKey)); | |||
} | |||
for (InputFile inputFile : sourceFiles) { | |||
LOG.debug("Populating index from {}", inputFile); | |||
String resourceEffectiveKey = ((DeprecatedDefaultInputFile) inputFile).key(); | |||
FileBlocks fileBlocks = duplicationCache.byComponent(resourceEffectiveKey); | |||
if (fileBlocks != null) { | |||
index.insert(inputFile, fileBlocks.blocks()); | |||
} else if (bridge != null) { | |||
List<Block> blocks2 = bridge.chunk(resourceEffectiveKey, inputFile.file()); | |||
index.insert(inputFile, blocks2); | |||
} | |||
} | |||
} | |||
@VisibleForTesting | |||
int getBlockSize(String languageKey) { | |||
int blockSize = settings.getInt("sonar.cpd." + languageKey + ".minimumLines"); |
@@ -198,20 +198,8 @@ public class JavaCpdEngine extends CpdEngine { | |||
if (duplications == null || Iterables.isEmpty(duplications)) { | |||
return; | |||
} | |||
// Calculate number of lines and blocks | |||
Set<Integer> duplicatedLines = new HashSet<Integer>(); | |||
int duplicatedBlocks = 0; | |||
for (CloneGroup clone : duplications) { | |||
ClonePart origin = clone.getOriginPart(); | |||
for (ClonePart part : clone.getCloneParts()) { | |||
if (part.getResourceId().equals(origin.getResourceId())) { | |||
duplicatedBlocks++; | |||
for (int duplicatedLine = part.getStartLine(); duplicatedLine < part.getStartLine() + part.getLines(); duplicatedLine++) { | |||
duplicatedLines.add(duplicatedLine); | |||
} | |||
} | |||
} | |||
} | |||
int duplicatedBlocks = computeBlockAndLineCount(duplications, duplicatedLines); | |||
FileLinesContext linesContext = contextFactory.createFor(inputFile); | |||
for (int i = 1; i <= inputFile.lines(); i++) { | |||
linesContext.setIntValue(CoreMetrics.DUPLICATION_LINES_DATA_KEY, i, duplicatedLines.contains(i) ? 1 : 0); | |||
@@ -246,4 +234,20 @@ public class JavaCpdEngine extends CpdEngine { | |||
context.saveDuplications(inputFile, builder.build()); | |||
} | |||
private static int computeBlockAndLineCount(Iterable<CloneGroup> duplications, Set<Integer> duplicatedLines) { | |||
int duplicatedBlocks = 0; | |||
for (CloneGroup clone : duplications) { | |||
ClonePart origin = clone.getOriginPart(); | |||
for (ClonePart part : clone.getCloneParts()) { | |||
if (part.getResourceId().equals(origin.getResourceId())) { | |||
duplicatedBlocks++; | |||
for (int duplicatedLine = part.getStartLine(); duplicatedLine < part.getStartLine() + part.getLines(); duplicatedLine++) { | |||
duplicatedLines.add(duplicatedLine); | |||
} | |||
} | |||
} | |||
} | |||
return duplicatedBlocks; | |||
} | |||
} |
@@ -64,7 +64,7 @@ public class IndexFactory implements BatchComponent { | |||
} | |||
@VisibleForTesting | |||
boolean verifyCrossProject(Project project, Logger logger) { | |||
boolean verifyCrossProject(@Nullable Project project, Logger logger) { | |||
boolean crossProject = false; | |||
if (settings.getBoolean(CoreProperties.CPD_CROSS_PROJECT)) { |
@@ -1,36 +0,0 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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 02110-1301, USA. | |||
*/ | |||
package org.sonar.xoo; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
public interface XooConstants { | |||
String PLUGIN_KEY = "xoo"; | |||
String PLUGIN_NAME = "Xoo"; | |||
String REPOSITORY_KEY = PLUGIN_KEY; | |||
String REPOSITORY_NAME = PLUGIN_NAME; | |||
String[] FILE_SUFFIXES = {"xoo"}; | |||
Logger LOG = LoggerFactory.getLogger("xoo"); | |||
} |
@@ -21,6 +21,8 @@ package org.sonar.xoo.lang; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.measure.MetricFinder; | |||
import org.sonar.api.batch.sensor.Sensor; | |||
@@ -30,7 +32,6 @@ import org.sonar.api.batch.sensor.measure.Measure; | |||
import org.sonar.api.batch.sensor.measure.MeasureBuilder; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.xoo.Xoo; | |||
import org.sonar.xoo.XooConstants; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -42,6 +43,8 @@ import java.util.List; | |||
*/ | |||
public class MeasureSensor implements Sensor { | |||
private static final Logger LOG = LoggerFactory.getLogger(MeasureSensor.class); | |||
private static final String MEASURES_EXTENSION = ".measures"; | |||
private MetricFinder metricFinder; | |||
@@ -54,7 +57,7 @@ public class MeasureSensor implements Sensor { | |||
File ioFile = inputFile.file(); | |||
File measureFile = new File(ioFile.getParentFile(), ioFile.getName() + MEASURES_EXTENSION); | |||
if (measureFile.exists()) { | |||
XooConstants.LOG.debug("Processing " + measureFile.getAbsolutePath()); | |||
LOG.debug("Processing " + measureFile.getAbsolutePath()); | |||
try { | |||
List<String> lines = FileUtils.readLines(measureFile, context.fileSystem().encoding().name()); | |||
int lineNumber = 0; | |||
@@ -81,7 +84,7 @@ public class MeasureSensor implements Sensor { | |||
} | |||
} | |||
private Measure<?> createMeasure(SensorContext context, InputFile xooFile, String metricKey, String value) { | |||
private Measure createMeasure(SensorContext context, InputFile xooFile, String metricKey, String value) { | |||
org.sonar.api.batch.measure.Metric<Serializable> metric = metricFinder.findByKey(metricKey); | |||
if (metric == null) { | |||
throw new IllegalStateException("Unknow metric with key: " + metricKey); |
@@ -22,6 +22,8 @@ package org.sonar.xoo.lang; | |||
import com.google.common.base.Splitter; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.sensor.Sensor; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
@@ -30,7 +32,6 @@ import org.sonar.api.batch.sensor.symbol.Symbol; | |||
import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.xoo.Xoo; | |||
import org.sonar.xoo.XooConstants; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -42,41 +43,44 @@ import java.util.List; | |||
*/ | |||
public class SymbolReferencesSensor implements Sensor { | |||
private static final Logger LOG = LoggerFactory.getLogger(SymbolReferencesSensor.class); | |||
private static final String SYMBOL_EXTENSION = ".symbol"; | |||
private void processFileSymbol(InputFile inputFile, SensorContext context) { | |||
File ioFile = inputFile.file(); | |||
File symbolFile = new File(ioFile.getParentFile(), ioFile.getName() + SYMBOL_EXTENSION); | |||
if (symbolFile.exists()) { | |||
XooConstants.LOG.debug("Processing " + symbolFile.getAbsolutePath()); | |||
LOG.debug("Processing " + symbolFile.getAbsolutePath()); | |||
try { | |||
List<String> lines = FileUtils.readLines(symbolFile, context.fileSystem().encoding().name()); | |||
int lineNumber = 0; | |||
SymbolTableBuilder symbolTableBuilder = context.symbolTableBuilder(inputFile); | |||
for (String line : lines) { | |||
lineNumber++; | |||
if (StringUtils.isBlank(line)) { | |||
continue; | |||
} | |||
if (line.startsWith("#")) { | |||
if (StringUtils.isBlank(line) || line.startsWith("#")) { | |||
continue; | |||
} | |||
try { | |||
Iterator<String> split = Splitter.on(",").split(line).iterator(); | |||
int startOffset = Integer.parseInt(split.next()); | |||
int endOffset = Integer.parseInt(split.next()); | |||
Symbol s = symbolTableBuilder.newSymbol(startOffset, endOffset); | |||
while (split.hasNext()) { | |||
symbolTableBuilder.newReference(s, Integer.parseInt(split.next())); | |||
} | |||
} catch (Exception e) { | |||
throw new IllegalStateException("Error processing line " + lineNumber + " of file " + symbolFile.getAbsolutePath(), e); | |||
} | |||
processLine(symbolFile, lineNumber, symbolTableBuilder, line); | |||
} | |||
symbolTableBuilder.done(); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
} | |||
private void processLine(File symbolFile, int lineNumber, SymbolTableBuilder symbolTableBuilder, String line) { | |||
try { | |||
Iterator<String> split = Splitter.on(",").split(line).iterator(); | |||
int startOffset = Integer.parseInt(split.next()); | |||
int endOffset = Integer.parseInt(split.next()); | |||
Symbol s = symbolTableBuilder.newSymbol(startOffset, endOffset); | |||
while (split.hasNext()) { | |||
symbolTableBuilder.newReference(s, Integer.parseInt(split.next())); | |||
} | |||
} catch (Exception e) { | |||
throw new IllegalStateException("Error processing line " + lineNumber + " of file " + symbolFile.getAbsolutePath(), e); | |||
} | |||
} | |||
@@ -19,19 +19,19 @@ | |||
*/ | |||
package org.sonar.xoo.lang; | |||
import org.sonar.api.batch.sensor.highlighting.TypeOfText; | |||
import com.google.common.base.Splitter; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.sensor.Sensor; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.SensorDescriptor; | |||
import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; | |||
import org.sonar.api.batch.sensor.highlighting.TypeOfText; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.xoo.Xoo; | |||
import org.sonar.xoo.XooConstants; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -43,42 +43,45 @@ import java.util.List; | |||
*/ | |||
public class SyntaxHighlightingSensor implements Sensor { | |||
private static final Logger LOG = LoggerFactory.getLogger(SyntaxHighlightingSensor.class); | |||
private static final String HIGHLIGHTING_EXTENSION = ".highlighting"; | |||
private void processFileHighlighting(InputFile inputFile, SensorContext context) { | |||
File ioFile = inputFile.file(); | |||
File highlightingFile = new File(ioFile.getParentFile(), ioFile.getName() + HIGHLIGHTING_EXTENSION); | |||
if (highlightingFile.exists()) { | |||
XooConstants.LOG.debug("Processing " + highlightingFile.getAbsolutePath()); | |||
LOG.debug("Processing " + highlightingFile.getAbsolutePath()); | |||
try { | |||
List<String> lines = FileUtils.readLines(highlightingFile, context.fileSystem().encoding().name()); | |||
int lineNumber = 0; | |||
HighlightingBuilder highlightingBuilder = context.highlightingBuilder(inputFile); | |||
for (String line : lines) { | |||
lineNumber++; | |||
if (StringUtils.isBlank(line)) { | |||
continue; | |||
} | |||
if (line.startsWith("#")) { | |||
if (StringUtils.isBlank(line) || line.startsWith("#")) { | |||
continue; | |||
} | |||
try { | |||
Iterator<String> split = Splitter.on(":").split(line).iterator(); | |||
int startOffset = Integer.parseInt(split.next()); | |||
int endOffset = Integer.parseInt(split.next()); | |||
TypeOfText type = TypeOfText.forCssClass(split.next()); | |||
highlightingBuilder.highlight(startOffset, endOffset, type); | |||
} catch (Exception e) { | |||
throw new IllegalStateException("Error processing line " + lineNumber + " of file " + highlightingFile.getAbsolutePath(), e); | |||
} | |||
processLine(highlightingFile, lineNumber, highlightingBuilder, line); | |||
} | |||
highlightingBuilder.done(); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
} | |||
private void processLine(File highlightingFile, int lineNumber, HighlightingBuilder highlightingBuilder, String line) { | |||
try { | |||
Iterator<String> split = Splitter.on(":").split(line).iterator(); | |||
int startOffset = Integer.parseInt(split.next()); | |||
int endOffset = Integer.parseInt(split.next()); | |||
TypeOfText type = TypeOfText.forCssClass(split.next()); | |||
highlightingBuilder.highlight(startOffset, endOffset, type); | |||
} catch (Exception e) { | |||
throw new IllegalStateException("Error processing line " + lineNumber + " of file " + highlightingFile.getAbsolutePath(), e); | |||
} | |||
} | |||
@Override | |||
public void describe(SensorDescriptor descriptor) { | |||
descriptor |
@@ -25,7 +25,6 @@ import org.sonar.api.batch.sensor.Sensor; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.SensorDescriptor; | |||
import org.sonar.xoo.Xoo; | |||
import org.sonar.xoo.XooConstants; | |||
public class CreateIssueByInternalKeySensor implements Sensor { | |||
@@ -36,7 +35,7 @@ public class CreateIssueByInternalKeySensor implements Sensor { | |||
descriptor | |||
.name("CreateIssueByInternalKeySensor") | |||
.workOnLanguages(Xoo.KEY) | |||
.createIssuesForRuleRepositories(XooConstants.REPOSITORY_KEY) | |||
.createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY) | |||
.workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); | |||
} | |||
@@ -48,7 +47,7 @@ public class CreateIssueByInternalKeySensor implements Sensor { | |||
} | |||
private void createIssues(InputFile file, SensorContext context) { | |||
ActiveRule rule = context.activeRules().findByInternalKey(XooConstants.REPOSITORY_KEY, | |||
ActiveRule rule = context.activeRules().findByInternalKey(XooRulesDefinition.XOO_REPOSITORY, | |||
context.settings().getString(INTERNAL_KEY_PROPERTY)); | |||
if (rule != null) { | |||
context.addIssue(context.issueBuilder() |
@@ -26,7 +26,6 @@ import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.SensorDescriptor; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.xoo.Xoo; | |||
import org.sonar.xoo.XooConstants; | |||
public class OneIssueOnDirPerFileSensor implements Sensor { | |||
@@ -37,7 +36,7 @@ public class OneIssueOnDirPerFileSensor implements Sensor { | |||
descriptor | |||
.name("One Issue On Dir Per File") | |||
.workOnLanguages(Xoo.KEY) | |||
.createIssuesForRuleRepositories(XooConstants.REPOSITORY_KEY) | |||
.createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY) | |||
.workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); | |||
} | |||
@@ -49,7 +48,7 @@ public class OneIssueOnDirPerFileSensor implements Sensor { | |||
} | |||
private void createIssues(InputFile file, SensorContext context) { | |||
RuleKey ruleKey = RuleKey.of(XooConstants.REPOSITORY_KEY, RULE_KEY); | |||
RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY); | |||
InputDir inputDir = context.fileSystem().inputDir(file.file().getParentFile()); | |||
if (inputDir != null) { | |||
context.addIssue(context.issueBuilder() |
@@ -29,7 +29,6 @@ import org.sonar.api.batch.sensor.measure.Measure; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.xoo.Xoo; | |||
import org.sonar.xoo.XooConstants; | |||
public class OneIssuePerLineSensor implements Sensor { | |||
@@ -43,7 +42,7 @@ public class OneIssuePerLineSensor implements Sensor { | |||
.name("One Issue Per Line") | |||
.dependsOn(CoreMetrics.LINES) | |||
.workOnLanguages(Xoo.KEY) | |||
.createIssuesForRuleRepositories(XooConstants.REPOSITORY_KEY) | |||
.createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY) | |||
.workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); | |||
} | |||
@@ -55,7 +54,7 @@ public class OneIssuePerLineSensor implements Sensor { | |||
} | |||
private void createIssues(InputFile file, SensorContext context) { | |||
RuleKey ruleKey = RuleKey.of(XooConstants.REPOSITORY_KEY, RULE_KEY); | |||
RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY); | |||
Measure<Integer> linesMeasure = context.getMeasure(file, CoreMetrics.LINES); | |||
if (linesMeasure == null) { | |||
LoggerFactory.getLogger(getClass()).warn("Missing measure " + CoreMetrics.LINES_KEY + " on " + file); |
@@ -42,13 +42,13 @@ public class XooRulesDefinition implements RulesDefinition { | |||
.setName("No empty line") | |||
.setMarkdownDescription("Generate an issue on *empty* lines of Xoo source files") | |||
// optional tags | |||
// optional tags | |||
.setTags("style", "security") | |||
// optional status. Default value is READY. | |||
// optional status. Default value is READY. | |||
.setStatus(RuleStatus.BETA) | |||
// default severity when the rule is activated on a Quality profile. Default value is MAJOR. | |||
// default severity when the rule is activated on a Quality profile. Default value is MAJOR. | |||
.setSeverity(Severity.MINOR); | |||
// debt-related information |
@@ -21,8 +21,6 @@ package org.sonar.batch.duplication; | |||
import com.google.common.base.Preconditions; | |||
import net.sourceforge.pmd.cpd.TokenEntry; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder; | |||
@@ -37,8 +35,6 @@ import java.util.List; | |||
public class DefaultTokenBuilder implements DuplicationTokenBuilder { | |||
private static final Logger LOG = LoggerFactory.getLogger(DefaultTokenBuilder.class); | |||
private final BlockCache cache; | |||
private final InputFile inputFile; | |||
private final List<TokenEntry> tokens = new ArrayList<TokenEntry>(); | |||
@@ -69,7 +65,7 @@ public class DefaultTokenBuilder implements DuplicationTokenBuilder { | |||
tokens.add(TokenEntry.getEOF()); | |||
TokenEntry.clearImages(); | |||
List<TokensLine> tokensLines = TokenizerBridge.convert(tokens); | |||
ArrayList<Block> blocks = blockChunker.chunk(((DefaultInputFile) inputFile).key(), tokensLines); | |||
List<Block> blocks = blockChunker.chunk(((DefaultInputFile) inputFile).key(), tokensLines); | |||
cache.put(((DefaultInputFile) inputFile).key(), new FileBlocks(((DefaultInputFile) inputFile).key(), blocks)); | |||
tokens.clear(); |
@@ -26,6 +26,7 @@ import org.sonar.api.batch.sensor.duplication.DuplicationGroup; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationGroup.Block; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
class DuplicationGroupValueCoder implements ValueCoder { | |||
@@ -45,7 +46,7 @@ class DuplicationGroupValueCoder implements ValueCoder { | |||
public Object get(Value value, Class clazz, CoderContext context) { | |||
DuplicationGroup g = new DuplicationGroup((Block) blockCoder.get(value, DuplicationGroup.Block.class, context)); | |||
int count = value.getInt(); | |||
ArrayList<DuplicationGroup.Block> blocks = new ArrayList<DuplicationGroup.Block>(count); | |||
List<DuplicationGroup.Block> blocks = new ArrayList<DuplicationGroup.Block>(count); | |||
for (int i = 0; i < count; i++) { | |||
blocks.add((Block) blockCoder.get(value, DuplicationGroup.Block.class, context)); | |||
} |
@@ -19,27 +19,16 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import com.google.common.base.Preconditions; | |||
import org.sonar.api.batch.Sensor; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
import org.sonar.api.batch.fs.InputDir; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.InputPath; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.measure.Metric; | |||
import org.sonar.api.batch.rule.ActiveRules; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationGroup; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder; | |||
import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder; | |||
import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; | |||
import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.batch.sensor.issue.IssueBuilder; | |||
import org.sonar.api.batch.sensor.issue.internal.DefaultIssueBuilder; | |||
import org.sonar.api.batch.sensor.measure.Measure; | |||
import org.sonar.api.batch.sensor.measure.MeasureBuilder; | |||
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; | |||
import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; | |||
import org.sonar.api.component.ResourcePerspectives; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.issue.Issuable; | |||
@@ -55,66 +44,32 @@ import org.sonar.api.resources.Resource; | |||
import org.sonar.api.resources.Scopes; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.batch.duplication.BlockCache; | |||
import org.sonar.batch.duplication.DefaultTokenBuilder; | |||
import org.sonar.batch.duplication.DuplicationCache; | |||
import org.sonar.batch.highlighting.DefaultHighlightingBuilder; | |||
import org.sonar.batch.index.ComponentDataCache; | |||
import org.sonar.batch.symbol.DefaultSymbolTableBuilder; | |||
import org.sonar.duplications.internal.pmd.PmdBlockChunker; | |||
import org.sonar.batch.scan2.CommonSensorContext; | |||
import java.io.Serializable; | |||
import java.util.List; | |||
/** | |||
* Implements {@link SensorContext} but forward everything to {@link org.sonar.api.batch.SensorContext} for backward compatibility. | |||
* Will be dropped once old {@link Sensor} API is dropped. | |||
* | |||
*/ | |||
public class SensorContextAdaptor implements SensorContext { | |||
public class SensorContextAdaptor extends CommonSensorContext { | |||
private final org.sonar.api.batch.SensorContext sensorContext; | |||
private final MetricFinder metricFinder; | |||
private final Project project; | |||
private final ResourcePerspectives perspectives; | |||
private final Settings settings; | |||
private final FileSystem fs; | |||
private final ActiveRules activeRules; | |||
private final ComponentDataCache componentDataCache; | |||
private final BlockCache blockCache; | |||
private final DuplicationCache duplicationCache; | |||
public SensorContextAdaptor(org.sonar.api.batch.SensorContext sensorContext, MetricFinder metricFinder, Project project, ResourcePerspectives perspectives, | |||
Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache, BlockCache blockCache, | |||
DuplicationCache duplicationCache) { | |||
super(settings, fs, activeRules, componentDataCache, blockCache, duplicationCache); | |||
this.sensorContext = sensorContext; | |||
this.metricFinder = metricFinder; | |||
this.project = project; | |||
this.perspectives = perspectives; | |||
this.settings = settings; | |||
this.fs = fs; | |||
this.activeRules = activeRules; | |||
this.componentDataCache = componentDataCache; | |||
this.blockCache = blockCache; | |||
this.duplicationCache = duplicationCache; | |||
} | |||
@Override | |||
public Settings settings() { | |||
return settings; | |||
} | |||
@Override | |||
public FileSystem fileSystem() { | |||
return fs; | |||
} | |||
@Override | |||
public ActiveRules activeRules() { | |||
return activeRules; | |||
} | |||
@Override | |||
public <G extends Serializable> MeasureBuilder<G> measureBuilder() { | |||
return new DefaultMeasureBuilder<G>(); | |||
} | |||
@Override | |||
@@ -143,7 +98,7 @@ public class SensorContextAdaptor implements SensorContext { | |||
return getMeasure(file, m); | |||
} | |||
private Metric<?> findMetricOrFail(String metricKey) { | |||
private Metric findMetricOrFail(String metricKey) { | |||
Metric<?> m = metricFinder.findByKey(metricKey); | |||
if (m == null) { | |||
throw new IllegalStateException("Unknow metric with key: " + metricKey); | |||
@@ -222,11 +177,6 @@ public class SensorContextAdaptor implements SensorContext { | |||
} | |||
} | |||
@Override | |||
public IssueBuilder issueBuilder() { | |||
return new DefaultIssueBuilder(); | |||
} | |||
@Override | |||
public boolean addIssue(Issue issue) { | |||
Resource r; | |||
@@ -259,53 +209,4 @@ public class SensorContextAdaptor implements SensorContext { | |||
.build(); | |||
} | |||
@Override | |||
public HighlightingBuilder highlightingBuilder(InputFile inputFile) { | |||
return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); | |||
} | |||
@Override | |||
public SymbolTableBuilder symbolTableBuilder(InputFile inputFile) { | |||
return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); | |||
} | |||
@Override | |||
public DuplicationTokenBuilder duplicationTokenBuilder(InputFile inputFile) { | |||
PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language())); | |||
return new DefaultTokenBuilder(inputFile, blockCache, blockChunker); | |||
} | |||
@Override | |||
public DuplicationBuilder duplicationBuilder(InputFile inputFile) { | |||
return new DefaultDuplicationBuilder(inputFile); | |||
} | |||
@Override | |||
public void saveDuplications(InputFile inputFile, List<DuplicationGroup> duplications) { | |||
Preconditions.checkState(duplications.size() > 0, "Empty duplications"); | |||
String effectiveKey = ((DefaultInputFile) inputFile).key(); | |||
for (DuplicationGroup duplicationGroup : duplications) { | |||
Preconditions.checkState(effectiveKey.equals(duplicationGroup.originBlock().resourceKey()), "Invalid duplication group"); | |||
} | |||
duplicationCache.put(effectiveKey, duplications); | |||
} | |||
private int getBlockSize(String languageKey) { | |||
int blockSize = settings.getInt("sonar.cpd." + languageKey + ".minimumLines"); | |||
if (blockSize == 0) { | |||
blockSize = getDefaultBlockSize(languageKey); | |||
} | |||
return blockSize; | |||
} | |||
private static int getDefaultBlockSize(String languageKey) { | |||
if ("cobol".equals(languageKey)) { | |||
return 30; | |||
} else if ("abap".equals(languageKey) || "natur".equals(languageKey)) { | |||
return 20; | |||
} else { | |||
return 10; | |||
} | |||
} | |||
} |
@@ -37,13 +37,12 @@ public final class DeprecatedMetricFinder implements MetricFinder { | |||
public DeprecatedMetricFinder(GlobalReferentials globalReferentials) { | |||
for (org.sonar.batch.protocol.input.Metric metric : globalReferentials.metrics()) { | |||
Metric hibernateMetric = new org.sonar.api.measures.Metric.Builder(metric.key(), metric.key(), ValueType.valueOf(metric.valueType())) | |||
Metric hibernateMetric = new org.sonar.api.measures.Metric.Builder(metric.key(), metric.name(), ValueType.valueOf(metric.valueType())) | |||
.create() | |||
.setDirection(metric.direction()) | |||
.setQualitative(metric.isQualitative()) | |||
.setUserManaged(metric.isUserManaged()) | |||
.setDescription(metric.description()) | |||
.setName(metric.name()) | |||
.setOptimizedBestValue(metric.isOptimizedBestValue()) | |||
.setBestValue(metric.bestValue()) | |||
.setWorstValue(metric.worstValue()) |
@@ -0,0 +1,150 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.scan2; | |||
import com.google.common.base.Preconditions; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.rule.ActiveRules; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationGroup; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder; | |||
import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder; | |||
import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; | |||
import org.sonar.api.batch.sensor.issue.IssueBuilder; | |||
import org.sonar.api.batch.sensor.issue.internal.DefaultIssueBuilder; | |||
import org.sonar.api.batch.sensor.measure.MeasureBuilder; | |||
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; | |||
import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.batch.duplication.BlockCache; | |||
import org.sonar.batch.duplication.DefaultTokenBuilder; | |||
import org.sonar.batch.duplication.DuplicationCache; | |||
import org.sonar.batch.highlighting.DefaultHighlightingBuilder; | |||
import org.sonar.batch.index.ComponentDataCache; | |||
import org.sonar.batch.scan.SensorContextAdaptor; | |||
import org.sonar.batch.symbol.DefaultSymbolTableBuilder; | |||
import org.sonar.duplications.internal.pmd.PmdBlockChunker; | |||
import java.io.Serializable; | |||
import java.util.List; | |||
/** | |||
* Common bits between {@link DefaultSensorContext} and {@link SensorContextAdaptor} | |||
* @author julien | |||
* | |||
*/ | |||
public abstract class CommonSensorContext implements SensorContext { | |||
private final Settings settings; | |||
private final FileSystem fs; | |||
private final ActiveRules activeRules; | |||
private final ComponentDataCache componentDataCache; | |||
private final BlockCache blockCache; | |||
private final DuplicationCache duplicationCache; | |||
protected CommonSensorContext(Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache, | |||
BlockCache blockCache, DuplicationCache duplicationCache) { | |||
this.settings = settings; | |||
this.fs = fs; | |||
this.activeRules = activeRules; | |||
this.componentDataCache = componentDataCache; | |||
this.blockCache = blockCache; | |||
this.duplicationCache = duplicationCache; | |||
} | |||
@Override | |||
public Settings settings() { | |||
return settings; | |||
} | |||
@Override | |||
public FileSystem fileSystem() { | |||
return fs; | |||
} | |||
@Override | |||
public ActiveRules activeRules() { | |||
return activeRules; | |||
} | |||
@Override | |||
public <G extends Serializable> MeasureBuilder<G> measureBuilder() { | |||
return new DefaultMeasureBuilder<G>(); | |||
} | |||
@Override | |||
public IssueBuilder issueBuilder() { | |||
return new DefaultIssueBuilder(); | |||
} | |||
@Override | |||
public HighlightingBuilder highlightingBuilder(InputFile inputFile) { | |||
return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); | |||
} | |||
@Override | |||
public SymbolTableBuilder symbolTableBuilder(InputFile inputFile) { | |||
return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); | |||
} | |||
@Override | |||
public DuplicationTokenBuilder duplicationTokenBuilder(InputFile inputFile) { | |||
PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language())); | |||
return new DefaultTokenBuilder(inputFile, blockCache, blockChunker); | |||
} | |||
@Override | |||
public DuplicationBuilder duplicationBuilder(InputFile inputFile) { | |||
return new DefaultDuplicationBuilder(inputFile); | |||
} | |||
@Override | |||
public void saveDuplications(InputFile inputFile, List<DuplicationGroup> duplications) { | |||
Preconditions.checkState(!duplications.isEmpty(), "Empty duplications"); | |||
String effectiveKey = ((DefaultInputFile) inputFile).key(); | |||
for (DuplicationGroup duplicationGroup : duplications) { | |||
Preconditions.checkState(effectiveKey.equals(duplicationGroup.originBlock().resourceKey()), "Invalid duplication group"); | |||
} | |||
duplicationCache.put(effectiveKey, duplications); | |||
} | |||
private int getBlockSize(String languageKey) { | |||
int blockSize = settings.getInt("sonar.cpd." + languageKey + ".minimumLines"); | |||
if (blockSize == 0) { | |||
blockSize = getDefaultBlockSize(languageKey); | |||
} | |||
return blockSize; | |||
} | |||
private static int getDefaultBlockSize(String languageKey) { | |||
if ("cobol".equals(languageKey)) { | |||
return 30; | |||
} else if ("abap".equals(languageKey) || "natur".equals(languageKey)) { | |||
return 20; | |||
} else { | |||
return 10; | |||
} | |||
} | |||
} |
@@ -19,93 +19,46 @@ | |||
*/ | |||
package org.sonar.batch.scan2; | |||
import com.google.common.base.Preconditions; | |||
import com.google.common.base.Strings; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.measure.Metric; | |||
import org.sonar.api.batch.rule.ActiveRules; | |||
import org.sonar.api.batch.rule.internal.DefaultActiveRule; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationGroup; | |||
import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder; | |||
import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder; | |||
import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; | |||
import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.batch.sensor.issue.IssueBuilder; | |||
import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; | |||
import org.sonar.api.batch.sensor.issue.internal.DefaultIssueBuilder; | |||
import org.sonar.api.batch.sensor.measure.Measure; | |||
import org.sonar.api.batch.sensor.measure.MeasureBuilder; | |||
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; | |||
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; | |||
import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.duplication.BlockCache; | |||
import org.sonar.batch.duplication.DefaultTokenBuilder; | |||
import org.sonar.batch.duplication.DuplicationCache; | |||
import org.sonar.batch.highlighting.DefaultHighlightingBuilder; | |||
import org.sonar.batch.index.ComponentDataCache; | |||
import org.sonar.batch.issue.IssueFilters; | |||
import org.sonar.batch.scan.SensorContextAdaptor; | |||
import org.sonar.batch.symbol.DefaultSymbolTableBuilder; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.duplications.internal.pmd.PmdBlockChunker; | |||
import java.io.Serializable; | |||
import java.util.List; | |||
public class DefaultSensorContext implements SensorContext { | |||
public class DefaultSensorContext extends CommonSensorContext { | |||
private final AnalyzerMeasureCache measureCache; | |||
private final AnalyzerIssueCache issueCache; | |||
private final ProjectDefinition def; | |||
private final Settings settings; | |||
private final FileSystem fs; | |||
private final ActiveRules activeRules; | |||
private final IssueFilters issueFilters; | |||
private final ComponentDataCache componentDataCache; | |||
private final BlockCache blockCache; | |||
private final DuplicationCache duplicationCache; | |||
public DefaultSensorContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, AnalyzerIssueCache issueCache, | |||
Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters, ComponentDataCache componentDataCache, | |||
BlockCache blockCache, DuplicationCache duplicationCache) { | |||
super(settings, fs, activeRules, componentDataCache, blockCache, duplicationCache); | |||
this.def = def; | |||
this.measureCache = measureCache; | |||
this.issueCache = issueCache; | |||
this.settings = settings; | |||
this.fs = fs; | |||
this.activeRules = activeRules; | |||
this.issueFilters = issueFilters; | |||
this.componentDataCache = componentDataCache; | |||
this.blockCache = blockCache; | |||
this.duplicationCache = duplicationCache; | |||
} | |||
@Override | |||
public Settings settings() { | |||
return settings; | |||
} | |||
@Override | |||
public FileSystem fileSystem() { | |||
return fs; | |||
} | |||
@Override | |||
public ActiveRules activeRules() { | |||
return activeRules; | |||
} | |||
@Override | |||
public <G extends Serializable> MeasureBuilder<G> measureBuilder() { | |||
return new DefaultMeasureBuilder<G>(); | |||
} | |||
@Override | |||
@@ -138,11 +91,6 @@ public class DefaultSensorContext implements SensorContext { | |||
} | |||
} | |||
@Override | |||
public IssueBuilder issueBuilder() { | |||
return new DefaultIssueBuilder(); | |||
} | |||
@Override | |||
public boolean addIssue(Issue issue) { | |||
String resourceKey; | |||
@@ -181,54 +129,4 @@ public class DefaultSensorContext implements SensorContext { | |||
} | |||
} | |||
@Override | |||
public HighlightingBuilder highlightingBuilder(InputFile inputFile) { | |||
return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); | |||
} | |||
@Override | |||
public SymbolTableBuilder symbolTableBuilder(InputFile inputFile) { | |||
return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); | |||
} | |||
@Override | |||
public DuplicationTokenBuilder duplicationTokenBuilder(InputFile inputFile) { | |||
PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language())); | |||
return new DefaultTokenBuilder(inputFile, blockCache, blockChunker); | |||
} | |||
@Override | |||
public DuplicationBuilder duplicationBuilder(InputFile inputFile) { | |||
return new DefaultDuplicationBuilder(inputFile); | |||
} | |||
@Override | |||
public void saveDuplications(InputFile inputFile, List<DuplicationGroup> duplications) { | |||
Preconditions.checkState(duplications.size() > 0, "Empty duplications"); | |||
String effectiveKey = ((DefaultInputFile) inputFile).key(); | |||
for (DuplicationGroup duplicationGroup : duplications) { | |||
Preconditions.checkState(effectiveKey.equals(duplicationGroup.originBlock().resourceKey()), "Invalid duplication group"); | |||
} | |||
duplicationCache.put(effectiveKey, duplications); | |||
} | |||
private int getBlockSize(String languageKey) { | |||
int blockSize = settings.getInt("sonar.cpd." + languageKey + ".minimumLines"); | |||
if (blockSize == 0) { | |||
blockSize = getDefaultBlockSize(languageKey); | |||
} | |||
return blockSize; | |||
} | |||
private static int getDefaultBlockSize(String languageKey) { | |||
if ("cobol".equals(languageKey)) { | |||
return 30; | |||
} else if ("abap".equals(languageKey) || "natur".equals(languageKey)) { | |||
return 20; | |||
} else { | |||
return 10; | |||
} | |||
} | |||
} |
@@ -51,7 +51,7 @@ public class PmdBlockChunker { | |||
/** | |||
* @return ArrayList as we need a serializable object | |||
*/ | |||
public ArrayList<Block> chunk(String resourceId, List<TokensLine> fragments) { | |||
public List<Block> chunk(String resourceId, List<TokensLine> fragments) { | |||
List<TokensLine> filtered = Lists.newArrayList(); | |||
int i = 0; | |||
while (i < fragments.size()) { |
@@ -79,6 +79,14 @@ public class DuplicationGroup { | |||
.append(length, rhs.length).isEquals(); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return new HashCodeBuilder(13, 43) | |||
.append(resourceKey) | |||
.append(startLine) | |||
.append(length).toHashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE). |
@@ -31,6 +31,10 @@ import javax.annotation.Nullable; | |||
public class DefaultIssueBuilder implements IssueBuilder { | |||
private static final String INPUT_DIR_SHOULD_BE_NON_NULL = "InputDir should be non null"; | |||
private static final String INPUT_FILE_SHOULD_BE_NON_NULL = "InputFile should be non null"; | |||
private static final String ON_FILE_OR_ON_DIR_ALREADY_CALLED = "onFile or onDir already called"; | |||
private static final String ON_PROJECT_ALREADY_CALLED = "onProject already called"; | |||
String key; | |||
boolean onProject = false; | |||
InputPath path; | |||
@@ -48,26 +52,26 @@ public class DefaultIssueBuilder implements IssueBuilder { | |||
@Override | |||
public DefaultIssueBuilder onFile(InputFile file) { | |||
Preconditions.checkState(!this.onProject, "onProject already called"); | |||
Preconditions.checkState(this.path == null, "onFile or onDir already called"); | |||
Preconditions.checkNotNull(file, "InputFile should be non null"); | |||
Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED); | |||
Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED); | |||
Preconditions.checkNotNull(file, INPUT_FILE_SHOULD_BE_NON_NULL); | |||
this.path = file; | |||
return this; | |||
} | |||
@Override | |||
public DefaultIssueBuilder onDir(InputDir dir) { | |||
Preconditions.checkState(!this.onProject, "onProject already called"); | |||
Preconditions.checkState(this.path == null, "onFile or onDir already called"); | |||
Preconditions.checkNotNull(dir, "InputDir should be non null"); | |||
Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED); | |||
Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED); | |||
Preconditions.checkNotNull(dir, INPUT_DIR_SHOULD_BE_NON_NULL); | |||
this.path = dir; | |||
return this; | |||
} | |||
@Override | |||
public DefaultIssueBuilder onProject() { | |||
Preconditions.checkState(!this.onProject, "onProject already called"); | |||
Preconditions.checkState(this.path == null, "onFile or onDir already called"); | |||
Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED); | |||
Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED); | |||
this.onProject = true; | |||
return this; | |||
} |
@@ -341,6 +341,7 @@ public class Metric<G extends Serializable> implements ServerExtension, BatchExt | |||
/** | |||
* @return the metric description | |||
*/ | |||
@CheckForNull | |||
public String getDescription() { | |||
return description; | |||
} | |||
@@ -351,7 +352,7 @@ public class Metric<G extends Serializable> implements ServerExtension, BatchExt | |||
* @param description the description | |||
* @return this | |||
*/ | |||
public Metric setDescription(String description) { | |||
public Metric setDescription(@Nullable String description) { | |||
this.description = description; | |||
return this; | |||
} |