import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.analyzer.AnalyzerContext;
import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
+import org.sonar.api.batch.analyzer.issue.AnalyzerIssueBuilder;
+import org.sonar.api.batch.analyzer.issue.internal.DefaultAnalyzerIssueBuilder;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasureBuilder;
import org.sonar.api.batch.analyzer.measure.internal.DefaultAnalyzerMeasureBuilder;
+import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measures.Metric;
+import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.component.ResourcePerspectives;
+import org.sonar.api.config.Settings;
import org.sonar.api.issue.Issuable;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.rule.RuleKey;
import java.io.Serializable;
-import java.util.Collection;
+/**
+ * Implements {@link AnalyzerContext} but forward everything to {@link SensorContext} for backward compatibility.
+ *
+ */
public class AnalyzerContextAdaptor implements AnalyzerContext {
private SensorContext sensorContext;
private MetricFinder metricFinder;
private Project project;
private ResourcePerspectives perspectives;
+ private Settings settings;
+ private FileSystem fs;
+ private ActiveRules activeRules;
- public AnalyzerContextAdaptor(SensorContext sensorContext, MetricFinder metricFinder, Project project, ResourcePerspectives perspectives) {
+ public AnalyzerContextAdaptor(SensorContext sensorContext, MetricFinder metricFinder, Project project, ResourcePerspectives perspectives,
+ Settings settings, FileSystem fs, ActiveRules activeRules) {
this.sensorContext = sensorContext;
this.metricFinder = metricFinder;
this.project = project;
this.perspectives = perspectives;
+ this.settings = settings;
+ this.fs = fs;
+ this.activeRules = activeRules;
+ }
+
+ @Override
+ public Settings settings() {
+ return settings;
+ }
+
+ @Override
+ public FileSystem fileSystem() {
+ return fs;
+ }
+
+ @Override
+ public ActiveRules activeRules() {
+ return activeRules;
}
@Override
@Override
public void addMeasure(AnalyzerMeasure<?> measure) {
- org.sonar.api.measures.Metric<?> m = metricFinder.findByKey(measure.metricKey());
+ org.sonar.api.measures.Metric<?> m = metricFinder.findByKey(measure.metric().key());
Measure measureToSave = new Measure(m);
switch (m.getType()) {
}
}
+ @Override
+ public AnalyzerIssueBuilder issueBuilder() {
+ return new DefaultAnalyzerIssueBuilder();
+ }
+
@Override
public void addIssue(AnalyzerIssue issue) {
Resource r;
.build());
}
- @Override
- public void addIssues(Collection<AnalyzerIssue> issues) {
- for (AnalyzerIssue analyzerIssue : issues) {
- addIssue(analyzerIssue);
- }
- }
-
}
public AnalyzerMeasureCache put(String resourceKey, DefaultAnalyzerMeasure<?> measure) {
Preconditions.checkNotNull(resourceKey);
- Preconditions.checkNotNull(measure.metricKey());
- cache.put(resourceKey, measure.metricKey(), measure);
+ Preconditions.checkNotNull(measure);
+ cache.put(resourceKey, measure.metric().key(), measure);
return this;
}
public boolean contains(String resourceKey, DefaultAnalyzerMeasure<?> measure) {
Preconditions.checkNotNull(resourceKey);
Preconditions.checkNotNull(measure);
- return cache.containsKey(resourceKey, measure.metricKey());
+ return cache.containsKey(resourceKey, measure.metric().key());
}
public Iterable<DefaultAnalyzerMeasure> all() {
import org.sonar.api.batch.analyzer.AnalyzerContext;
import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
+import org.sonar.api.batch.analyzer.issue.AnalyzerIssueBuilder;
+import org.sonar.api.batch.analyzer.issue.internal.DefaultAnalyzerIssueBuilder;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasureBuilder;
import org.sonar.api.batch.analyzer.measure.internal.DefaultAnalyzerMeasure;
import org.sonar.api.batch.analyzer.measure.internal.DefaultAnalyzerMeasureBuilder;
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.measures.Metric;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.config.Settings;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.batch.issue.ModuleIssues;
import org.sonar.core.issue.DefaultIssueBuilder;
import java.io.Serializable;
-import java.util.Collection;
public class DefaultAnalyzerContext implements AnalyzerContext {
private final AnalyzerMeasureCache measureCache;
private ProjectDefinition def;
private ModuleIssues moduleIssues;
+ private Settings settings;
+ private FileSystem fs;
+ private ActiveRules activeRules;
- public DefaultAnalyzerContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, ModuleIssues moduleIssues) {
+ public DefaultAnalyzerContext(ProjectDefinition def, AnalyzerMeasureCache measureCache,
+ ModuleIssues moduleIssues, Settings settings, FileSystem fs, ActiveRules activeRules) {
this.def = def;
this.measureCache = measureCache;
this.moduleIssues = moduleIssues;
+ this.settings = settings;
+ this.fs = fs;
+ this.activeRules = activeRules;
+ }
+
+ @Override
+ public Settings settings() {
+ return settings;
+ }
+
+ @Override
+ public FileSystem fileSystem() {
+ return fs;
+ }
+
+ @Override
+ public ActiveRules activeRules() {
+ return activeRules;
}
@Override
}
}
+ @Override
+ public AnalyzerIssueBuilder issueBuilder() {
+ return new DefaultAnalyzerIssueBuilder();
+ }
+
@Override
public void addIssue(AnalyzerIssue issue) {
DefaultIssueBuilder builder = new DefaultIssueBuilder()
.build());
}
- @Override
- public void addIssues(Collection<AnalyzerIssue> issues) {
- for (AnalyzerIssue analyzerIssue : issues) {
- addIssue(analyzerIssue);
- }
-
- }
-
}
package org.sonar.api.batch.analyzer;
import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
+import org.sonar.api.batch.analyzer.issue.AnalyzerIssueBuilder;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasureBuilder;
+import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measures.Metric;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.config.Settings;
import javax.annotation.CheckForNull;
import java.io.Serializable;
-import java.util.Collection;
/**
* @since 4.4
*/
public interface AnalyzerContext {
+ /**
+ * Get settings of the current project.
+ */
+ Settings settings();
+
+ /**
+ * Get filesystem of the current project.
+ */
+ FileSystem fileSystem();
+
+ /**
+ * Get list of active rules.
+ */
+ ActiveRules activeRules();
+
// ----------- MEASURES --------------
/**
// ----------- ISSUES --------------
/**
- * Add an issue.
+ * Builder to create a new {@link AnalyzerIssue}.
*/
- void addIssue(AnalyzerIssue issue);
+ AnalyzerIssueBuilder issueBuilder();
/**
- * Add a list of issues.
+ * Add an issue. Use {@link #issueBuilder()} to create the new issue.
*/
- void addIssues(Collection<AnalyzerIssue> issues);
+ void addIssue(AnalyzerIssue issue);
}
package org.sonar.api.batch.analyzer;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.languages.Language;
import org.sonar.api.batch.measures.Metric;
/**
+ * Describe what an {@link Analyzer} is doing. Information may be used by the platform
+ * to log interesting information or perform some optimization.
* @since 4.4
*/
public interface AnalyzerDescriptor {
+ /**
+ * Name of the {@link Analyzer}. Will be displayed in logs.
+ */
AnalyzerDescriptor name(String name);
+ /**
+ * List {@link Metric} this {@link Analyzer} depends on. Will be used to execute Analyzers in correct order.
+ */
AnalyzerDescriptor dependsOn(Metric<?>... metrics);
+ /**
+ * List {@link Metric} this {@link Analyzer} provides. Will be used to execute Analyzers in correct order.
+ */
AnalyzerDescriptor provides(Metric<?>... metrics);
+ /**
+ * List {@link Language} this {@link Analyzer} work on. May be used by the platform to skip execution of the {@link Analyzer} when
+ * no file for given languages are present in the project.
+ * If no language is provided then it will be executed for all languages.
+ */
AnalyzerDescriptor runOnLanguages(String... languageKeys);
+ /**
+ * List {@link InputFile.Type} this {@link Analyzer} work on. May be used by the platform to skip execution of the {@link Analyzer} when
+ * no file for given type are present in the project.
+ * If not type is provided then t will be executed for all types.
+ */
AnalyzerDescriptor runOnTypes(InputFile.Type... types);
}
*/
package org.sonar.api.batch.analyzer.issue;
-import com.google.common.base.Preconditions;
import org.sonar.api.batch.analyzer.Analyzer;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.rule.RuleKey;
*
* @since 4.4
*/
-public class AnalyzerIssue {
-
- private final InputFile inputFile;
- private final RuleKey ruleKey;
- private final String message;
- private final Integer line;
- private final Double effortToFix;
-
- private AnalyzerIssue(Builder builder) {
- this.inputFile = builder.file;
- this.ruleKey = builder.ruleKey;
- this.message = builder.message;
- this.line = builder.line;
- this.effortToFix = builder.effortToFix;
- }
-
- public static Builder builder() {
- return new Builder();
- }
+public interface AnalyzerIssue {
+ /**
+ * The {@link InputFile} this issue belongs to. Returns null if issue is global to the project.
+ */
@Nullable
- public InputFile inputFile() {
- return inputFile;
- }
-
- public RuleKey ruleKey() {
- return ruleKey;
- }
-
- public String message() {
- return message;
- }
-
- public Integer line() {
- return line;
- }
-
+ InputFile inputFile();
+
+ /**
+ * The {@link RuleKey} of this issue.
+ */
+ RuleKey ruleKey();
+
+ /**
+ * Message of the issue.
+ */
+ String message();
+
+ /**
+ * Line of the issue.
+ */
+ Integer line();
+
+ /**
+ * Effort to fix the issue. Used by technical debt model.
+ */
@Nullable
- public Double effortToFix() {
- return effortToFix;
- }
-
- public static class Builder {
-
- private Boolean onProject = null;
- private InputFile file;
- private RuleKey ruleKey;
- private String message;
- private Integer line;
- private Double effortToFix;
-
- public AnalyzerIssue build() {
- return new AnalyzerIssue(this);
- }
-
- public Builder ruleKey(RuleKey ruleKey) {
- this.ruleKey = ruleKey;
- return this;
- }
-
- public Builder onFile(InputFile file) {
- Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
- Preconditions.checkNotNull(file, "InputFile should be non null");
- this.file = file;
- this.onProject = false;
- return this;
- }
-
- public Builder onProject() {
- Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
- this.file = null;
- this.onProject = true;
- return this;
- }
-
- public Builder atLine(int line) {
- this.line = line;
- return this;
- }
-
- public Builder effortToFix(@Nullable Double effortToFix) {
- this.effortToFix = effortToFix;
- return this;
- }
-
- public Builder message(String message) {
- this.message = message;
- return this;
- }
-
- }
+ Double effortToFix();
}
--- /dev/null
+/*
+ * 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.api.batch.analyzer.issue;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.rule.RuleKey;
+
+import javax.annotation.Nullable;
+
+/**
+ * Builder for {@link AnalyzerIssue}.
+ *
+ * @since 4.4
+ */
+public interface AnalyzerIssueBuilder {
+
+ /**
+ * The {@link RuleKey} of the issue.
+ */
+ AnalyzerIssueBuilder ruleKey(RuleKey ruleKey);
+
+ /**
+ * The {@link InputFile} the issue belongs to. For global issues call {@link #onProject()}.
+ */
+ AnalyzerIssueBuilder onFile(InputFile file);
+
+ /**
+ * Tell that the issue is global to the project.
+ */
+ AnalyzerIssueBuilder onProject();
+
+ /**
+ * Line of the issue.
+ */
+ AnalyzerIssueBuilder atLine(int line);
+
+ /**
+ * Effort to fix for the issue.
+ */
+ AnalyzerIssueBuilder effortToFix(@Nullable Double effortToFix);
+
+ /**
+ * Message of the issue.
+ */
+ AnalyzerIssueBuilder message(String message);
+
+ /**
+ * Build the issue.
+ */
+ AnalyzerIssue build();
+
+}
--- /dev/null
+/*
+ * 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.api.batch.analyzer.issue.internal;
+
+import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.rule.RuleKey;
+
+import javax.annotation.Nullable;
+
+import java.io.Serializable;
+
+public class DefaultAnalyzerIssue implements AnalyzerIssue, Serializable {
+
+ private final InputFile inputFile;
+ private final RuleKey ruleKey;
+ private final String message;
+ private final Integer line;
+ private final Double effortToFix;
+
+ DefaultAnalyzerIssue(DefaultAnalyzerIssueBuilder builder) {
+ this.inputFile = builder.file;
+ this.ruleKey = builder.ruleKey;
+ this.message = builder.message;
+ this.line = builder.line;
+ this.effortToFix = builder.effortToFix;
+ }
+
+ @Override
+ @Nullable
+ public InputFile inputFile() {
+ return inputFile;
+ }
+
+ @Override
+ public RuleKey ruleKey() {
+ return ruleKey;
+ }
+
+ @Override
+ public String message() {
+ return message;
+ }
+
+ @Override
+ public Integer line() {
+ return line;
+ }
+
+ @Override
+ @Nullable
+ public Double effortToFix() {
+ return effortToFix;
+ }
+
+}
--- /dev/null
+/*
+ * 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.api.batch.analyzer.issue.internal;
+
+import com.google.common.base.Preconditions;
+import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
+import org.sonar.api.batch.analyzer.issue.AnalyzerIssueBuilder;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.rule.RuleKey;
+
+import javax.annotation.Nullable;
+
+public class DefaultAnalyzerIssueBuilder implements AnalyzerIssueBuilder {
+
+ Boolean onProject = null;
+ InputFile file;
+ RuleKey ruleKey;
+ String message;
+ Integer line;
+ Double effortToFix;
+
+ @Override
+ public DefaultAnalyzerIssueBuilder ruleKey(RuleKey ruleKey) {
+ this.ruleKey = ruleKey;
+ return this;
+ }
+
+ @Override
+ public DefaultAnalyzerIssueBuilder onFile(InputFile file) {
+ Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
+ Preconditions.checkNotNull(file, "InputFile should be non null");
+ this.file = file;
+ this.onProject = false;
+ return this;
+ }
+
+ @Override
+ public DefaultAnalyzerIssueBuilder onProject() {
+ Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
+ this.file = null;
+ this.onProject = true;
+ return this;
+ }
+
+ @Override
+ public DefaultAnalyzerIssueBuilder atLine(int line) {
+ this.line = line;
+ return this;
+ }
+
+ @Override
+ public DefaultAnalyzerIssueBuilder effortToFix(@Nullable Double effortToFix) {
+ this.effortToFix = effortToFix;
+ return this;
+ }
+
+ @Override
+ public DefaultAnalyzerIssueBuilder message(String message) {
+ this.message = message;
+ return this;
+ }
+
+ @Override
+ public AnalyzerIssue build() {
+ return new DefaultAnalyzerIssue(this);
+ }
+
+}
import org.sonar.api.batch.analyzer.Analyzer;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.measures.Metric;
import javax.annotation.Nullable;
import java.io.Serializable;
/**
- * A measure produced by {@link Analyzer}.
+ * A measure computed by an {@link Analyzer}.
* @since 4.4
*/
public interface AnalyzerMeasure<G extends Serializable> {
@Nullable
InputFile inputFile();
- String metricKey();
+ Metric<G> metric();
G value();
import com.google.common.base.Preconditions;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.measures.Metric;
import javax.annotation.Nullable;
public class DefaultAnalyzerMeasure<G extends Serializable> implements AnalyzerMeasure<G>, Serializable {
private final InputFile inputFile;
- private final String metricKey;
+ private final Metric<G> metric;
private final G value;
DefaultAnalyzerMeasure(DefaultAnalyzerMeasureBuilder<G> builder) {
Preconditions.checkNotNull(builder.value, "Measure value can't be null");
- Preconditions.checkNotNull(builder.metricKey, "Measure metricKey can't be null");
+ Preconditions.checkNotNull(builder.metric, "Measure metricKey can't be null");
this.inputFile = builder.file;
- this.metricKey = builder.metricKey;
+ this.metric = builder.metric;
this.value = builder.value;
}
}
@Override
- public String metricKey() {
- return metricKey;
+ public Metric<G> metric() {
+ return metric;
}
@Override
return false;
}
DefaultAnalyzerMeasure<?> other = (DefaultAnalyzerMeasure<?>) obj;
- return metricKey.equals(other.metricKey)
+ return metric.equals(other.metric)
&& value.equals(other.value)
&& (inputFile == null ? other.inputFile == null : inputFile.equals(other.inputFile));
}
@Override
public int hashCode() {
- return metricKey.hashCode()
+ return metric.hashCode()
+ value.hashCode()
+ (inputFile != null ? inputFile.hashCode() : 0);
}
@Override
public String toString() {
return "AnalyzerMeasure[" + (inputFile != null ? "inputFile=" + inputFile.toString() : "onProject")
- + ",metricKey=" + metricKey + ",value=" + value + "]";
+ + ",metric=" + metric + ",value=" + value + "]";
}
}
Boolean onProject = null;
InputFile file;
- String metricKey;
+ Metric<G> metric;
G value;
@Override
- public AnalyzerMeasureBuilder<G> onFile(InputFile file) {
+ public AnalyzerMeasureBuilder<G> onFile(InputFile inputFile) {
Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
- Preconditions.checkNotNull(file, "InputFile should be non null");
- this.file = file;
+ Preconditions.checkNotNull(inputFile, "inputFile should be non null");
+ this.file = inputFile;
this.onProject = false;
return this;
}
return this;
}
- private AnalyzerMeasureBuilder<G> metricKey(String metricKey) {
- Preconditions.checkState(metricKey != null, "Metric already defined");
- this.metricKey = metricKey;
- return this;
- }
-
@Override
public AnalyzerMeasureBuilder<G> forMetric(Metric<G> metric) {
- return metricKey(metric.key());
+ Preconditions.checkState(metric != null, "Metric already defined");
+ Preconditions.checkNotNull(metric, "metric should be non null");
+ this.metric = metric;
+ return this;
}
@Override
public AnalyzerMeasureBuilder<G> withValue(G value) {
- Preconditions.checkState(value != null, "Measure value already defined");
+ Preconditions.checkState(this.value == null, "Measure value already defined");
Preconditions.checkNotNull(value, "Measure value can't be null");
this.value = value;
return this;