summaryrefslogtreecommitdiffstats
path: root/sonar-plugin-api
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2015-07-29 17:42:20 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2015-07-31 11:00:25 +0200
commit93420cb74009febd28256484ca73241442bc1ff9 (patch)
tree612fc1f176e3b41cff95dd3038c2726d14725ee2 /sonar-plugin-api
parent5b93180b18e756c6a246b8d22307785d333d0002 (diff)
downloadsonarqube-93420cb74009febd28256484ca73241442bc1ff9.tar.gz
sonarqube-93420cb74009febd28256484ca73241442bc1ff9.zip
SONAR-6052 Extract primaryLocation as a special attribute
Also rework new issue API on batch side.
Diffstat (limited to 'sonar-plugin-api')
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputComponent.java36
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java29
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputPath.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java53
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputDir.java13
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java8
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java45
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/postjob/issue/Issue.java9
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java15
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java7
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java14
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java18
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java62
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java49
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java10
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java4
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java12
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java31
18 files changed, 289 insertions, 129 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputComponent.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputComponent.java
new file mode 100644
index 00000000000..e4f66be54b0
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputComponent.java
@@ -0,0 +1,36 @@
+/*
+ * 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.fs;
+
+/**
+ * Common interface for all input components.
+ *
+ * @since 5.2
+ * @see InputFile
+ * @see InputDir
+ */
+public interface InputComponent {
+
+ /**
+ * Is the component an {@link InputFile}
+ */
+ boolean isFile();
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java
new file mode 100644
index 00000000000..a92dc3655f2
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java
@@ -0,0 +1,29 @@
+/*
+ * 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.fs;
+
+/**
+ * Used to create issues and measures on modules.
+ *
+ * @since 5.2
+ */
+public interface InputModule extends InputComponent {
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputPath.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputPath.java
index 121df157028..b63d955a4c2 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputPath.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputPath.java
@@ -20,7 +20,6 @@
package org.sonar.api.batch.fs;
import java.io.File;
-import java.io.Serializable;
import java.nio.file.Path;
/**
@@ -30,7 +29,7 @@ import java.nio.file.Path;
* @see InputFile
* @see InputDir
*/
-public interface InputPath extends Serializable {
+public interface InputPath extends InputComponent {
/**
* @see InputFile#relativePath()
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java
new file mode 100644
index 00000000000..9a49dd4de66
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java
@@ -0,0 +1,53 @@
+/*
+ * 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.fs.internal;
+
+import org.sonar.api.batch.fs.InputComponent;
+
+/**
+ * @since 5.2
+ */
+public abstract class DefaultInputComponent implements InputComponent {
+
+ public abstract String key();
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || this.getClass() != o.getClass()) {
+ return false;
+ }
+
+ DefaultInputComponent that = (DefaultInputComponent) o;
+ return key().equals(that.key());
+ }
+
+ @Override
+ public int hashCode() {
+ return key().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "[key=" + key() + "]";
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputDir.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputDir.java
index 8979e1f3468..5e1ebb651c2 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputDir.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputDir.java
@@ -19,16 +19,15 @@
*/
package org.sonar.api.batch.fs.internal;
-import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.utils.PathUtils;
-
import java.io.File;
import java.nio.file.Path;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.utils.PathUtils;
/**
* @since 4.5
*/
-public class DefaultInputDir implements InputDir {
+public class DefaultInputDir extends DefaultInputComponent implements InputDir {
private final String relativePath;
private final String moduleKey;
@@ -66,6 +65,7 @@ public class DefaultInputDir implements InputDir {
return moduleKey;
}
+ @Override
public String key() {
return new StringBuilder().append(moduleKey).append(":").append(relativePath).toString();
}
@@ -79,6 +79,11 @@ public class DefaultInputDir implements InputDir {
}
@Override
+ public boolean isFile() {
+ return false;
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) {
return true;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
index 3c0cb4a243b..a2e8e992472 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
@@ -39,7 +39,7 @@ import org.sonar.api.utils.PathUtils;
/**
* @since 4.2
*/
-public class DefaultInputFile implements InputFile, org.sonar.api.resources.InputFile {
+public class DefaultInputFile extends DefaultInputComponent implements InputFile, org.sonar.api.resources.InputFile {
private final String relativePath;
private final String moduleKey;
@@ -114,6 +114,7 @@ public class DefaultInputFile implements InputFile, org.sonar.api.resources.Inpu
/**
* Component key.
*/
+ @Override
public String key() {
return new StringBuilder().append(moduleKey).append(":").append(relativePath).toString();
}
@@ -327,4 +328,9 @@ public class DefaultInputFile implements InputFile, org.sonar.api.resources.Inpu
return new BufferedInputStream(new FileInputStream(file()));
}
+ @Override
+ public boolean isFile() {
+ return true;
+ }
+
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java
new file mode 100644
index 00000000000..e1dd688d6c8
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java
@@ -0,0 +1,45 @@
+/*
+ * 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.fs.internal;
+
+import org.sonar.api.batch.fs.InputModule;
+
+/**
+ * @since 5.2
+ */
+public class DefaultInputModule extends DefaultInputComponent implements InputModule {
+
+ private final String moduleKey;
+
+ public DefaultInputModule(String moduleKey) {
+ this.moduleKey = moduleKey;
+ }
+
+ @Override
+ public String key() {
+ return moduleKey;
+ }
+
+ @Override
+ public boolean isFile() {
+ return false;
+ }
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/postjob/issue/Issue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/postjob/issue/Issue.java
index ccf79d800fb..6027568a0cf 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/postjob/issue/Issue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/postjob/issue/Issue.java
@@ -20,12 +20,11 @@
package org.sonar.api.batch.postjob.issue;
import com.google.common.annotations.Beta;
-import org.sonar.api.batch.fs.InputPath;
+import javax.annotation.CheckForNull;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.rule.RuleKey;
-import javax.annotation.CheckForNull;
-
/**
* Represents an issue state at the end of the batch analysis. Only available after local issue tracking in preview mode.
*
@@ -50,10 +49,10 @@ public interface Issue {
String componentKey();
/**
- * The {@link InputPath} this issue belongs to. Returns null if issue is global to the project or if component was deleted (for resolved issues).
+ * The {@link InputComponent} this issue belongs to. Returns null if component was deleted (for resolved issues).
*/
@CheckForNull
- InputPath inputPath();
+ InputComponent inputComponent();
/**
* Line of the issue. Null for global issues and issues on directories. Can also be null
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java
index 1c519115e29..563c848ce0f 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java
@@ -21,6 +21,7 @@ package org.sonar.api.batch.sensor.issue;
import com.google.common.annotations.Beta;
import java.util.List;
+import java.util.Map;
import javax.annotation.CheckForNull;
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.Sensor;
@@ -59,7 +60,13 @@ public interface Issue {
Severity overriddenSeverity();
/**
- * List of locations for this issue. Returns at least one location.
+ * Primary locations for this issue.
+ * @since 5.2
+ */
+ IssueLocation primaryLocation();
+
+ /**
+ * List of additional locations for this issue.
* @since 5.2
*/
List<IssueLocation> locations();
@@ -70,4 +77,10 @@ public interface Issue {
*/
List<ExecutionFlow> executionFlows();
+ /**
+ * Key/value pair of attributes that are attached to the issue.
+ * @since 5.2
+ */
+ Map<String, String> attributes();
+
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java
index fa587f89cb8..aff5cd8947d 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java
@@ -21,7 +21,7 @@ package org.sonar.api.batch.sensor.issue;
import com.google.common.annotations.Beta;
import javax.annotation.CheckForNull;
-import org.sonar.api.batch.fs.InputPath;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.TextRange;
/**
@@ -33,10 +33,9 @@ import org.sonar.api.batch.fs.TextRange;
public interface IssueLocation {
/**
- * The {@link InputPath} this location belongs to. Returns null if location is global to the project.
+ * The {@link InputComponent} this location belongs to.
*/
- @CheckForNull
- InputPath inputPath();
+ InputComponent inputComponent();
/**
* Range of the issue. Null for global issues and issues on directories. Can also be null
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java
index 7c44f331163..8ad694545b3 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java
@@ -51,7 +51,13 @@ public interface NewIssue {
/**
* @since 5.2
- * Register a new location for this issue. First registered location is considered as primary location.
+ * Primary for this issue.
+ */
+ NewIssue at(NewIssueLocation primaryLocation);
+
+ /**
+ * @since 5.2
+ * Register an additional location for this issue.
*/
NewIssue addLocation(NewIssueLocation location);
@@ -68,6 +74,12 @@ public interface NewIssue {
NewIssueLocation newLocation();
/**
+ * @since 5.2
+ * Attach a new attribute to the issue. Not used by SQ but can be reused later for integration needs (for example it is returned by WS).
+ */
+ NewIssue addAttribute(String key, String value);
+
+ /**
* Save the issue. If rule key is unknown or rule not enabled in the current quality profile then a warning is logged but no exception
* is thrown.
*/
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java
index 3ead59ed7f5..e0f4281a65a 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java
@@ -20,7 +20,7 @@
package org.sonar.api.batch.sensor.issue;
import com.google.common.annotations.Beta;
-import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.TextRange;
@@ -38,22 +38,12 @@ public interface NewIssueLocation {
int MESSAGE_MAX_SIZE = 4000;
/**
- * The {@link InputFile} the issue location belongs to. For global issues call {@link #onProject()}.
+ * The {@link InputComponent} the issue location belongs to. Mandatory.
*/
- NewIssueLocation onFile(InputFile file);
+ NewIssueLocation on(InputComponent component);
/**
- * The {@link InputDir} the issue location belongs to. For global issues call {@link #onProject()}.
- */
- NewIssueLocation onDir(InputDir inputDir);
-
- /**
- * Tell that the issue location is global to the project.
- */
- NewIssueLocation onProject();
-
- /**
- * Position in the file. Only valid when {@link #onFile(InputFile)} has been called.
+ * Position in the file. Only applicable when {@link #on(InputComponent)} has been called with an InputFile.
* See {@link InputFile#newRange(org.sonar.api.batch.fs.TextPointer, org.sonar.api.batch.fs.TextPointer)}
*/
NewIssueLocation at(TextRange location);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
index 686677ffb29..2018f7ac0ed 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
@@ -21,11 +21,13 @@ package org.sonar.api.batch.sensor.issue.internal;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import javax.annotation.Nullable;
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.internal.DefaultStorable;
@@ -35,25 +37,23 @@ import org.sonar.api.batch.sensor.issue.IssueLocation;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.internal.Uuids;
public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
- private String key;
private RuleKey ruleKey;
private Double effortToFix;
private Severity overriddenSeverity;
+ private IssueLocation primaryLocation;
private List<IssueLocation> locations = new ArrayList<>();
private List<List<IssueLocation>> executionFlows = new ArrayList<>();
+ private final Map<String, String> attributes = new LinkedHashMap<>();
public DefaultIssue() {
super(null);
- this.key = Uuids.create();
}
public DefaultIssue(SensorStorage storage) {
super(storage);
- this.key = Uuids.create();
}
@Override
@@ -80,6 +80,14 @@ public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
}
@Override
+ public DefaultIssue at(NewIssueLocation primaryLocation) {
+ Preconditions.checkArgument(primaryLocation != null, "Cannot use a location that is null");
+ Preconditions.checkState(this.primaryLocation == null, "at() already called");
+ this.primaryLocation = (DefaultIssueLocation) primaryLocation;
+ return this;
+ }
+
+ @Override
public DefaultIssue addLocation(NewIssueLocation location) {
locations.add((DefaultIssueLocation) location);
return this;
@@ -96,6 +104,17 @@ public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
}
@Override
+ public DefaultIssue addAttribute(String key, String value) {
+ attributes.put(key, value);
+ return this;
+ }
+
+ @Override
+ public Map<String, String> attributes() {
+ return ImmutableMap.copyOf(attributes);
+ }
+
+ @Override
public RuleKey ruleKey() {
return this.ruleKey;
}
@@ -110,8 +129,9 @@ public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
return this.effortToFix;
}
- public String key() {
- return this.key;
+ @Override
+ public IssueLocation primaryLocation() {
+ return primaryLocation;
}
@Override
@@ -137,34 +157,8 @@ public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
@Override
public void doSave() {
Preconditions.checkNotNull(this.ruleKey, "ruleKey is mandatory on issue");
- Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key");
- Preconditions.checkState(!locations.isEmpty(), "At least one location is mandatory on every issue");
+ Preconditions.checkState(primaryLocation != null, "Primary location is mandatory on every issue");
storage.store(this);
}
- /**
- * For testing only.
- */
- public DefaultIssue withKey(String key) {
- this.key = key;
- return this;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- DefaultIssue that = (DefaultIssue) o;
- return !key.equals(that.key);
- }
-
- @Override
- public int hashCode() {
- return key.hashCode();
- }
-
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
index 3840cd595f8..87b6ff67d44 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
@@ -20,10 +20,7 @@
package org.sonar.api.batch.sensor.issue.internal;
import com.google.common.base.Preconditions;
-import javax.annotation.CheckForNull;
-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.InputComponent;
import org.sonar.api.batch.fs.TextRange;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.sensor.issue.IssueLocation;
@@ -31,46 +28,23 @@ import org.sonar.api.batch.sensor.issue.NewIssueLocation;
public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
- 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";
-
- private boolean onProject = false;
- private InputPath path;
+ private InputComponent component;
private TextRange textRange;
private String message;
@Override
- public NewIssueLocation onFile(InputFile file) {
- 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 NewIssueLocation onDir(InputDir dir) {
- 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 NewIssueLocation onProject() {
- Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
- Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
- this.onProject = true;
+ public NewIssueLocation on(InputComponent component) {
+ Preconditions.checkArgument(component != null, "Component can't be null");
+ Preconditions.checkState(this.component == null, "on() already called");
+ this.component = component;
return this;
}
@Override
public NewIssueLocation at(TextRange location) {
- Preconditions.checkState(this.path != null && this.path instanceof InputFile, "at() should be called after onFile.");
- DefaultInputFile file = (DefaultInputFile) this.path;
+ Preconditions.checkState(this.component != null, "at() should be called after on()");
+ Preconditions.checkState(this.component.isFile(), "at() should be called only for an InputFile.");
+ DefaultInputFile file = (DefaultInputFile) this.component;
file.validate(location);
this.textRange = location;
return this;
@@ -86,9 +60,8 @@ public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
}
@Override
- @CheckForNull
- public InputPath inputPath() {
- return this.path;
+ public InputComponent inputComponent() {
+ return this.component;
}
@Override
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java
index 7cf03cb0579..c2adf0e5e11 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java
@@ -67,7 +67,7 @@ public interface Issuable extends Perspective {
/**
* Optional line index, starting from 1. It must not be zero or negative.
- * @deprecated since 5.2 use {@link #addLocation(NewIssueLocation)}
+ * @deprecated since 5.2 use {@link #at(NewIssueLocation)}
*/
@Deprecated
IssueBuilder line(@Nullable Integer line);
@@ -76,7 +76,7 @@ public interface Issuable extends Perspective {
* Optional, but recommended, plain-text message.
* <p/>
* Formats like Markdown or HTML are not supported. Size must not be greater than {@link Issue#MESSAGE_MAX_SIZE} characters.
- * @deprecated since 5.2 use {@link #addLocation(NewIssueLocation)}
+ * @deprecated since 5.2 use {@link #at(NewIssueLocation)}
*/
@Deprecated
IssueBuilder message(@Nullable String message);
@@ -89,6 +89,12 @@ public interface Issuable extends Perspective {
/**
* @since 5.2
+ * Register primary location for this issue.
+ */
+ IssueBuilder at(NewIssueLocation primaryLocation);
+
+ /**
+ * @since 5.2
* Register a new secondary location for this issue.
*/
IssueBuilder addLocation(NewIssueLocation location);
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
index 8837c6eb6da..7c15bd2c3f9 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
@@ -89,12 +89,12 @@ public class SensorContextTesterTest {
assertThat(tester.allIssues()).isEmpty();
NewIssue newIssue = tester.newIssue();
newIssue
- .addLocation(newIssue.newLocation().onFile(new DefaultInputFile("foo", "src/Foo.java")))
+ .at(newIssue.newLocation().on(new DefaultInputFile("foo", "src/Foo.java")))
.forRule(RuleKey.of("repo", "rule"))
.save();
newIssue = tester.newIssue();
newIssue
- .addLocation(newIssue.newLocation().onFile(new DefaultInputFile("foo", "src/Foo.java")))
+ .at(newIssue.newLocation().on(new DefaultInputFile("foo", "src/Foo.java")))
.forRule(RuleKey.of("repo", "rule"))
.save();
assertThat(tester.allIssues()).hasSize(2);
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java
index 6ed1a7aa686..cffb6367baf 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java
@@ -35,19 +35,19 @@ public class DefaultIssueLocationTest {
private DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.php").initMetadata(new FileMetadata().readMetadata(new StringReader("Foo\nBar\n")));
@Test
- public void not_allowed_to_call_onFile_and_onProject() {
+ public void not_allowed_to_call_on_twice() {
thrown.expect(IllegalStateException.class);
- thrown.expectMessage("onProject already called");
+ thrown.expectMessage("on() already called");
new DefaultIssueLocation()
- .onProject()
- .onFile(inputFile)
+ .on(inputFile)
+ .on(inputFile)
.message("Wrong way!");
}
@Test
public void prevent_too_long_messages() {
new DefaultIssueLocation()
- .onFile(inputFile)
+ .on(inputFile)
.message(StringUtils.repeat("a", 4000));
thrown.expect(IllegalArgumentException.class);
@@ -55,7 +55,7 @@ public class DefaultIssueLocationTest {
thrown.expectMessage("aaa] size is 4001");
new DefaultIssueLocation()
- .onFile(inputFile)
+ .on(inputFile)
.message(StringUtils.repeat("a", 4001));
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java
index e9b27548b35..011683854e1 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java
@@ -23,6 +23,7 @@ import java.io.StringReader;
import org.junit.Test;
import org.sonar.api.batch.fs.internal.DefaultInputDir;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.internal.SensorStorage;
@@ -40,18 +41,18 @@ public class DefaultIssueTest {
public void build_file_issue() {
SensorStorage storage = mock(SensorStorage.class);
DefaultIssue issue = new DefaultIssue(storage)
- .addLocation(new DefaultIssueLocation()
- .onFile(inputFile)
+ .at(new DefaultIssueLocation()
+ .on(inputFile)
.at(inputFile.selectLine(1))
.message("Wrong way!"))
.forRule(RuleKey.of("repo", "rule"))
.effortToFix(10.0);
- assertThat(issue.locations().get(0).inputPath()).isEqualTo(inputFile);
+ assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputFile);
assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
- assertThat(issue.locations().get(0).textRange().start().line()).isEqualTo(1);
+ assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1);
assertThat(issue.effortToFix()).isEqualTo(10.0);
- assertThat(issue.locations().get(0).message()).isEqualTo("Wrong way!");
+ assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
issue.save();
@@ -62,16 +63,16 @@ public class DefaultIssueTest {
public void build_directory_issue() {
SensorStorage storage = mock(SensorStorage.class);
DefaultIssue issue = new DefaultIssue(storage)
- .addLocation(new DefaultIssueLocation()
- .onDir(new DefaultInputDir("foo", "src"))
+ .at(new DefaultIssueLocation()
+ .on(new DefaultInputDir("foo", "src"))
.message("Wrong way!"))
.forRule(RuleKey.of("repo", "rule"))
.overrideSeverity(Severity.BLOCKER);
- assertThat(issue.locations().get(0).inputPath()).isEqualTo(new DefaultInputDir("foo", "src"));
+ assertThat(issue.primaryLocation().inputComponent()).isEqualTo(new DefaultInputDir("foo", "src"));
assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
- assertThat(issue.locations().get(0).textRange()).isNull();
- assertThat(issue.locations().get(0).message()).isEqualTo("Wrong way!");
+ assertThat(issue.primaryLocation().textRange()).isNull();
+ assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
assertThat(issue.overriddenSeverity()).isEqualTo(Severity.BLOCKER);
issue.save();
@@ -83,17 +84,17 @@ public class DefaultIssueTest {
public void build_project_issue() {
SensorStorage storage = mock(SensorStorage.class);
DefaultIssue issue = new DefaultIssue(storage)
- .addLocation(new DefaultIssueLocation()
- .onProject()
+ .at(new DefaultIssueLocation()
+ .on(new DefaultInputModule("foo"))
.message("Wrong way!"))
.forRule(RuleKey.of("repo", "rule"))
.effortToFix(10.0);
- assertThat(issue.locations().get(0).inputPath()).isNull();
+ assertThat(issue.primaryLocation().inputComponent()).isEqualTo(new DefaultInputModule("foo"));
assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
- assertThat(issue.locations().get(0).textRange()).isNull();
+ assertThat(issue.primaryLocation().textRange()).isNull();
assertThat(issue.effortToFix()).isEqualTo(10.0);
- assertThat(issue.locations().get(0).message()).isEqualTo("Wrong way!");
+ assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
issue.save();