diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..7de0b7241
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,4 @@
+language: java
+sudo: false
+script:
+ - travis_wait mvn compile
diff --git a/pom.xml b/pom.xml
index c4b1e71a9..10406cd8e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,6 +59,17 @@
- * The default implementation passes control to the
- * {@link #lookupSeriesShape(int)} method. You can override this method if
+ * The default implementation passes control to the
+ * {@link #lookupSeriesShape(int)} method. You can override this method if
* you require different behaviour.
*
* @param row the row (or series) index (zero-based).
@@ -1566,7 +1568,7 @@ public void setAutoPopulateSeriesOutlineStroke(boolean auto) {
*
* @return The shape (never {@code null}).
*/
- public Shape getItemShape(int row, int column) {
+ public Shape getItemShape(@NonNegative int row, @NonNegative int column) {
return lookupSeriesShape(row);
}
@@ -1579,7 +1581,7 @@ public Shape getItemShape(int row, int column) {
*
* @since 1.0.6
*/
- public Shape lookupSeriesShape(int series) {
+ public Shape lookupSeriesShape(@NonNegative int series) {
Shape result = getSeriesShape(series);
if (result == null && this.autoPopulateSeriesShape) {
@@ -1605,7 +1607,7 @@ public Shape lookupSeriesShape(int series) {
*
* @see #setSeriesShape(int, Shape)
*/
- public Shape getSeriesShape(int series) {
+ public Shape getSeriesShape(@NonNegative int series) {
return this.shapeList.getShape(series);
}
@@ -1618,7 +1620,7 @@ public Shape getSeriesShape(int series) {
*
* @see #getSeriesShape(int)
*/
- public void setSeriesShape(int series, Shape shape) {
+ public void setSeriesShape(@NonNegative int series, Shape shape) {
setSeriesShape(series, shape, true);
}
@@ -1632,7 +1634,7 @@ public void setSeriesShape(int series, Shape shape) {
*
* @see #getSeriesShape(int)
*/
- public void setSeriesShape(int series, Shape shape, boolean notify) {
+ public void setSeriesShape(@NonNegative int series, Shape shape, boolean notify) {
this.shapeList.setShape(series, shape);
if (notify) {
fireChangeEvent();
@@ -1719,7 +1721,7 @@ public void setAutoPopulateSeriesShape(boolean auto) {
*
* @return A boolean.
*/
- public boolean isItemLabelVisible(int row, int column) {
+ public boolean isItemLabelVisible(@NonNegative int row, @NonNegative int column) {
return isSeriesItemLabelsVisible(row);
}
@@ -1731,7 +1733,7 @@ public boolean isItemLabelVisible(int row, int column) {
*
* @return A boolean.
*/
- public boolean isSeriesItemLabelsVisible(int series) {
+ public boolean isSeriesItemLabelsVisible(@NonNegative int series) {
Boolean b = this.itemLabelsVisibleList.getBoolean(series);
if (b == null) {
return this.defaultItemLabelsVisible;
@@ -1746,7 +1748,7 @@ public boolean isSeriesItemLabelsVisible(int series) {
* @param series the series index (zero-based).
* @param visible the flag.
*/
- public void setSeriesItemLabelsVisible(int series, boolean visible) {
+ public void setSeriesItemLabelsVisible(@NonNegative int series, boolean visible) {
setSeriesItemLabelsVisible(series, Boolean.valueOf(visible));
}
@@ -1757,7 +1759,7 @@ public void setSeriesItemLabelsVisible(int series, boolean visible) {
* @param series the series index (zero-based).
* @param visible the flag ({@code null} permitted).
*/
- public void setSeriesItemLabelsVisible(int series, Boolean visible) {
+ public void setSeriesItemLabelsVisible(@NonNegative int series, Boolean visible) {
setSeriesItemLabelsVisible(series, visible, true);
}
@@ -1770,7 +1772,7 @@ public void setSeriesItemLabelsVisible(int series, Boolean visible) {
* @param notify a flag that controls whether or not listeners are
* notified.
*/
- public void setSeriesItemLabelsVisible(int series, Boolean visible,
+ public void setSeriesItemLabelsVisible(@NonNegative int series, Boolean visible,
boolean notify) {
this.itemLabelsVisibleList.setBoolean(series, visible);
if (notify) {
@@ -1811,7 +1813,7 @@ public void setDefaultItemLabelsVisible(boolean visible) {
* @param notify a flag that controls whether or not listeners are
* notified.
*
- * @see #getDefaultItemLabelsVisible()
+ * @see #getDefaultItemLabelsVisible()
*/
public void setDefaultItemLabelsVisible(boolean visible, boolean notify) {
this.defaultItemLabelsVisible = visible;
@@ -1830,7 +1832,7 @@ public void setDefaultItemLabelsVisible(boolean visible, boolean notify) {
*
* @return The font (never {@code null}).
*/
- public Font getItemLabelFont(int row, int column) {
+ public Font getItemLabelFont(@NonNegative int row, @NonNegative int column) {
Font result = getSeriesItemLabelFont(row);
if (result == null) {
result = this.defaultItemLabelFont;
@@ -1847,7 +1849,7 @@ public Font getItemLabelFont(int row, int column) {
*
* @see #setSeriesItemLabelFont(int, Font)
*/
- public Font getSeriesItemLabelFont(int series) {
+ public Font getSeriesItemLabelFont(@NonNegative int series) {
return this.itemLabelFontMap.get(series);
}
@@ -1860,7 +1862,7 @@ public Font getSeriesItemLabelFont(int series) {
*
* @see #getSeriesItemLabelFont(int)
*/
- public void setSeriesItemLabelFont(int series, Font font) {
+ public void setSeriesItemLabelFont(@NonNegative int series, Font font) {
setSeriesItemLabelFont(series, font, true);
}
@@ -1875,7 +1877,7 @@ public void setSeriesItemLabelFont(int series, Font font) {
*
* @see #getSeriesItemLabelFont(int)
*/
- public void setSeriesItemLabelFont(int series, Font font, boolean notify) {
+ public void setSeriesItemLabelFont(@NonNegative int series, Font font, boolean notify) {
this.itemLabelFontMap.put(series, font);
if (notify) {
fireChangeEvent();
@@ -1895,7 +1897,7 @@ public Font getDefaultItemLabelFont() {
}
/**
- * Sets the default item label font and sends a {@link RendererChangeEvent}
+ * Sets the default item label font and sends a {@link RendererChangeEvent}
* to all registered listeners.
*
* @param font the font ({@code null} not permitted).
@@ -1934,7 +1936,7 @@ public void setDefaultItemLabelFont(Font font, boolean notify) {
*
* @return The paint (never {@code null}).
*/
- public Paint getItemLabelPaint(int row, int column) {
+ public Paint getItemLabelPaint(@NonNegative int row, @NonNegative int column) {
Paint result = getSeriesItemLabelPaint(row);
if (result == null) {
result = this.defaultItemLabelPaint;
@@ -1951,7 +1953,7 @@ public Paint getItemLabelPaint(int row, int column) {
*
* @see #setSeriesItemLabelPaint(int, Paint)
*/
- public Paint getSeriesItemLabelPaint(int series) {
+ public Paint getSeriesItemLabelPaint(@NonNegative int series) {
return this.itemLabelPaintList.getPaint(series);
}
@@ -1964,7 +1966,7 @@ public Paint getSeriesItemLabelPaint(int series) {
*
* @see #getSeriesItemLabelPaint(int)
*/
- public void setSeriesItemLabelPaint(int series, Paint paint) {
+ public void setSeriesItemLabelPaint(@NonNegative int series, Paint paint) {
setSeriesItemLabelPaint(series, paint, true);
}
@@ -1979,7 +1981,7 @@ public void setSeriesItemLabelPaint(int series, Paint paint) {
*
* @see #getSeriesItemLabelPaint(int)
*/
- public void setSeriesItemLabelPaint(int series, Paint paint,
+ public void setSeriesItemLabelPaint(@NonNegative int series, Paint paint,
boolean notify) {
this.itemLabelPaintList.setPaint(series, paint);
if (notify) {
@@ -2041,7 +2043,7 @@ public void setDefaultItemLabelPaint(Paint paint, boolean notify) {
*
* @see #getNegativeItemLabelPosition(int, int)
*/
- public ItemLabelPosition getPositiveItemLabelPosition(int row, int column) {
+ public ItemLabelPosition getPositiveItemLabelPosition(@NonNegative int row, @NonNegative int column) {
return getSeriesPositiveItemLabelPosition(row);
}
@@ -2054,7 +2056,7 @@ public ItemLabelPosition getPositiveItemLabelPosition(int row, int column) {
*
* @see #setSeriesPositiveItemLabelPosition(int, ItemLabelPosition)
*/
- public ItemLabelPosition getSeriesPositiveItemLabelPosition(int series) {
+ public ItemLabelPosition getSeriesPositiveItemLabelPosition(@NonNegative int series) {
// otherwise look up the position table
ItemLabelPosition position = (ItemLabelPosition)
this.positiveItemLabelPositionMap.get(series);
@@ -2073,7 +2075,7 @@ public ItemLabelPosition getSeriesPositiveItemLabelPosition(int series) {
*
* @see #getSeriesPositiveItemLabelPosition(int)
*/
- public void setSeriesPositiveItemLabelPosition(int series,
+ public void setSeriesPositiveItemLabelPosition(@NonNegative int series,
ItemLabelPosition position) {
setSeriesPositiveItemLabelPosition(series, position, true);
}
@@ -2089,7 +2091,7 @@ public void setSeriesPositiveItemLabelPosition(int series,
*
* @see #getSeriesPositiveItemLabelPosition(int)
*/
- public void setSeriesPositiveItemLabelPosition(int series,
+ public void setSeriesPositiveItemLabelPosition(@NonNegative int series,
ItemLabelPosition position, boolean notify) {
this.positiveItemLabelPositionMap.put(series, position);
if (notify) {
@@ -2153,7 +2155,7 @@ public void setDefaultPositiveItemLabelPosition(ItemLabelPosition position,
*
* @see #getPositiveItemLabelPosition(int, int)
*/
- public ItemLabelPosition getNegativeItemLabelPosition(int row, int column) {
+ public ItemLabelPosition getNegativeItemLabelPosition(@NonNegative int row, @NonNegative int column) {
return getSeriesNegativeItemLabelPosition(row);
}
@@ -2166,9 +2168,9 @@ public ItemLabelPosition getNegativeItemLabelPosition(int row, int column) {
*
* @see #setSeriesNegativeItemLabelPosition(int, ItemLabelPosition)
*/
- public ItemLabelPosition getSeriesNegativeItemLabelPosition(int series) {
+ public ItemLabelPosition getSeriesNegativeItemLabelPosition(@NonNegative int series) {
// otherwise look up the position list
- ItemLabelPosition position
+ ItemLabelPosition position
= this.negativeItemLabelPositionMap.get(series);
if (position == null) {
position = this.defaultNegativeItemLabelPosition;
@@ -2185,7 +2187,7 @@ public ItemLabelPosition getSeriesNegativeItemLabelPosition(int series) {
*
* @see #getSeriesNegativeItemLabelPosition(int)
*/
- public void setSeriesNegativeItemLabelPosition(int series,
+ public void setSeriesNegativeItemLabelPosition(@NonNegative int series,
ItemLabelPosition position) {
setSeriesNegativeItemLabelPosition(series, position, true);
}
@@ -2201,7 +2203,7 @@ public void setSeriesNegativeItemLabelPosition(int series,
*
* @see #getSeriesNegativeItemLabelPosition(int)
*/
- public void setSeriesNegativeItemLabelPosition(int series,
+ public void setSeriesNegativeItemLabelPosition(@NonNegative int series,
ItemLabelPosition position, boolean notify) {
this.negativeItemLabelPositionMap.put(series, position);
if (notify) {
@@ -2283,7 +2285,7 @@ public void setItemLabelAnchorOffset(double offset) {
*
* @return A boolean.
*/
- public boolean getItemCreateEntity(int series, int item) {
+ public boolean getItemCreateEntity(@NonNegative int series, @NonNegative int item) {
Boolean b = getSeriesCreateEntities(series);
if (b != null) {
return b;
@@ -2302,7 +2304,7 @@ public boolean getItemCreateEntity(int series, int item) {
*
* @see #setSeriesCreateEntities(int, Boolean)
*/
- public Boolean getSeriesCreateEntities(int series) {
+ public Boolean getSeriesCreateEntities(@NonNegative int series) {
return this.createEntitiesList.getBoolean(series);
}
@@ -2315,7 +2317,7 @@ public Boolean getSeriesCreateEntities(int series) {
*
* @see #getSeriesCreateEntities(int)
*/
- public void setSeriesCreateEntities(int series, Boolean create) {
+ public void setSeriesCreateEntities(@NonNegative int series, Boolean create) {
setSeriesCreateEntities(series, create, true);
}
@@ -2330,7 +2332,7 @@ public void setSeriesCreateEntities(int series, Boolean create) {
*
* @see #getSeriesCreateEntities(int)
*/
- public void setSeriesCreateEntities(int series, Boolean create,
+ public void setSeriesCreateEntities(@NonNegative int series, Boolean create,
boolean notify) {
this.createEntitiesList.setBoolean(series, create);
if (notify) {
@@ -2388,7 +2390,7 @@ public void setDefaultCreateEntities(boolean create, boolean notify) {
*
* @see #setDefaultEntityRadius(int)
*/
- public int getDefaultEntityRadius() {
+ public @NonNegative int getDefaultEntityRadius() {
return this.defaultEntityRadius;
}
@@ -2400,7 +2402,7 @@ public int getDefaultEntityRadius() {
*
* @see #getDefaultEntityRadius()
*/
- public void setDefaultEntityRadius(int radius) {
+ public void setDefaultEntityRadius(@NonNegative int radius) {
this.defaultEntityRadius = radius;
}
@@ -2413,7 +2415,7 @@ public void setDefaultEntityRadius(int radius) {
*
* @since 1.0.11
*/
- public Shape lookupLegendShape(int series) {
+ public Shape lookupLegendShape(@NonNegative int series) {
Shape result = getLegendShape(series);
if (result == null) {
result = this.defaultLegendShape;
@@ -2436,7 +2438,7 @@ public Shape lookupLegendShape(int series) {
*
* @since 1.0.11
*/
- public Shape getLegendShape(int series) {
+ public Shape getLegendShape(@NonNegative int series) {
return this.legendShapeList.getShape(series);
}
@@ -2449,7 +2451,7 @@ public Shape getLegendShape(int series) {
*
* @since 1.0.11
*/
- public void setLegendShape(int series, Shape shape) {
+ public void setLegendShape(@NonNegative int series, Shape shape) {
this.legendShapeList.setShape(series, shape);
fireChangeEvent();
}
@@ -2481,9 +2483,9 @@ public void setDefaultLegendShape(Shape shape) {
/**
* Returns the flag that controls whether or not the legend shape is
* treated as a line when creating legend items.
- *
+ *
* @return A boolean.
- *
+ *
* @since 1.0.14
*/
protected boolean getTreatLegendShapeAsLine() {
@@ -2514,7 +2516,7 @@ protected void setTreatLegendShapeAsLine(boolean treatAsLine) {
*
* @since 1.0.11
*/
- public Font lookupLegendTextFont(int series) {
+ public Font lookupLegendTextFont(@NonNegative int series) {
Font result = getLegendTextFont(series);
if (result == null) {
result = this.defaultLegendTextFont;
@@ -2534,7 +2536,7 @@ public Font lookupLegendTextFont(int series) {
*
* @since 1.0.11
*/
- public Font getLegendTextFont(int series) {
+ public Font getLegendTextFont(@NonNegative int series) {
return this.legendTextFontMap.get(series);
}
@@ -2547,7 +2549,7 @@ public Font getLegendTextFont(int series) {
*
* @since 1.0.11
*/
- public void setLegendTextFont(int series, Font font) {
+ public void setLegendTextFont(@NonNegative int series, Font font) {
this.legendTextFontMap.put(series, font);
fireChangeEvent();
}
@@ -2586,7 +2588,7 @@ public void setDefaultLegendTextFont(Font font) {
*
* @since 1.0.11
*/
- public Paint lookupLegendTextPaint(int series) {
+ public Paint lookupLegendTextPaint(@NonNegative int series) {
Paint result = getLegendTextPaint(series);
if (result == null) {
result = this.defaultLegendTextPaint;
@@ -2606,7 +2608,7 @@ public Paint lookupLegendTextPaint(int series) {
*
* @since 1.0.11
*/
- public Paint getLegendTextPaint(int series) {
+ public Paint getLegendTextPaint(@NonNegative int series) {
return this.legendTextPaint.getPaint(series);
}
@@ -2619,7 +2621,7 @@ public Paint getLegendTextPaint(int series) {
*
* @since 1.0.11
*/
- public void setLegendTextPaint(int series, Paint paint) {
+ public void setLegendTextPaint(@NonNegative int series, Paint paint) {
this.legendTextPaint.setPaint(series, paint);
fireChangeEvent();
}
diff --git a/src/main/java/org/jfree/chart/renderer/DefaultPolarItemRenderer.java b/src/main/java/org/jfree/chart/renderer/DefaultPolarItemRenderer.java
index e777ff71d..b35e367e1 100644
--- a/src/main/java/org/jfree/chart/renderer/DefaultPolarItemRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/DefaultPolarItemRenderer.java
@@ -63,6 +63,10 @@
package org.jfree.chart.renderer;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
@@ -367,7 +371,7 @@ public DrawingSupplier getDrawingSupplier() {
*
* @return A boolean.
*/
- public boolean isSeriesFilled(int series) {
+ public boolean isSeriesFilled(@NonNegative int series) {
boolean result = false;
Boolean b = this.seriesFilled.getBoolean(series);
if (b != null) {
@@ -382,7 +386,7 @@ public boolean isSeriesFilled(int series) {
* @param series the series index.
* @param filled the flag.
*/
- public void setSeriesFilled(int series, boolean filled) {
+ public void setSeriesFilled(@NonNegative int series, boolean filled) {
this.seriesFilled.setBoolean(series, Boolean.valueOf(filled));
}
@@ -455,7 +459,7 @@ public void setLegendLine(Shape line) {
* used if {@code area} is {@code null}).
*/
protected void addEntity(EntityCollection entities, Shape area,
- XYDataset dataset, int series, int item,
+ XYDataset dataset, @NonNegative int series, @IndexFor("#3.getSeries(#4)") int item,
double entityX, double entityY) {
if (!getItemCreateEntity(series, item)) {
return;
@@ -498,13 +502,14 @@ protected void addEntity(EntityCollection entities, Shape area,
@Override
public void drawSeries(Graphics2D g2, Rectangle2D dataArea,
PlotRenderingInfo info, PolarPlot plot, XYDataset dataset,
- int seriesIndex) {
+ @NonNegative int seriesIndex) {
final int numPoints = dataset.getItemCount(seriesIndex);
if (numPoints == 0) {
return;
}
GeneralPath poly = null;
+ @SuppressWarnings("index") // This would fail if the dataset passed to this function was not associated with this plot. Maybe a bug?
ValueAxis axis = plot.getAxisForDataset(plot.indexOf(dataset));
for (int i = 0; i < numPoints; i++) {
double theta = dataset.getXValue(seriesIndex, i);
@@ -583,7 +588,9 @@ public void drawSeries(Graphics2D g2, Rectangle2D dataArea,
// data area...
if (entities != null && ShapeUtils.isPointInRect(dataArea, x,
y)) {
- addEntity(entities, shape, dataset, seriesIndex, i-1, x, y);
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/219: i - 1 is an index because the i increases once on each iteration of this while loop, and the loop condition is equivalent to the length of this series
+ @IndexFor("dataset.getSeries(seriesIndex)") int i1 = i - 1;
+ addEntity(entities, shape, dataset, seriesIndex, i1, x, y);
}
}
}
@@ -684,12 +691,13 @@ public void drawRadialGridLines(Graphics2D g2, PolarPlot plot,
* @return The legend item.
*/
@Override
- public LegendItem getLegendItem(int series) {
+ public LegendItem getLegendItem(@NonNegative int series) {
LegendItem result;
PolarPlot plot = getPlot();
if (plot == null) {
return null;
}
+ @SuppressWarnings("index") // guaranteed index: this renderer belongs to the plot, so plot.getIndexOf returns a non negative
XYDataset dataset = plot.getDataset(plot.getIndexOf(this));
if (dataset == null) {
return null;
@@ -746,7 +754,7 @@ public LegendItem getLegendItem(int series) {
* @since 1.0.14
*/
@Override
- public XYToolTipGenerator getToolTipGenerator(int series, int item) {
+ public XYToolTipGenerator getToolTipGenerator(@NonNegative int series, @NonNegative int item) {
XYToolTipGenerator generator
= (XYToolTipGenerator) this.toolTipGeneratorList.get(series);
if (generator == null) {
@@ -763,7 +771,7 @@ public XYToolTipGenerator getToolTipGenerator(int series, int item) {
* @since 1.0.14
*/
@Override
- public XYToolTipGenerator getSeriesToolTipGenerator(int series) {
+ public XYToolTipGenerator getSeriesToolTipGenerator(@NonNegative int series) {
return (XYToolTipGenerator) this.toolTipGeneratorList.get(series);
}
@@ -776,7 +784,7 @@ public XYToolTipGenerator getSeriesToolTipGenerator(int series) {
* @since 1.0.14
*/
@Override
- public void setSeriesToolTipGenerator(int series,
+ public void setSeriesToolTipGenerator(@NonNegative int series,
XYToolTipGenerator generator) {
this.toolTipGeneratorList.set(series, generator);
fireChangeEvent();
diff --git a/src/main/java/org/jfree/chart/renderer/LookupPaintScale.java b/src/main/java/org/jfree/chart/renderer/LookupPaintScale.java
index 447484585..74d818836 100644
--- a/src/main/java/org/jfree/chart/renderer/LookupPaintScale.java
+++ b/src/main/java/org/jfree/chart/renderer/LookupPaintScale.java
@@ -45,6 +45,8 @@
package org.jfree.chart.renderer;
+import org.checkerframework.checker.index.qual.*;
+
import java.awt.Color;
import java.awt.Paint;
import java.io.IOException;
@@ -295,10 +297,11 @@ public Paint getPaint(double value) {
}
// for value in bounds, do the lookup...
- int low = 0;
- int high = this.lookupTable.size() - 1;
+ @NonNegative int low = 0;
+ @SuppressWarnings("index") // lookupTable always has at least one element
+ @NonNegative int high = this.lookupTable.size() - 1;
while (high - low > 1) {
- int current = (low + high) / 2;
+ @NonNegative int current = (low + high) / 2;
item = (PaintItem) this.lookupTable.get(current);
if (value >= item.value) {
low = current;
diff --git a/src/main/java/org/jfree/chart/renderer/OutlierList.java b/src/main/java/org/jfree/chart/renderer/OutlierList.java
index 2ef1d57f9..78b1a7d27 100644
--- a/src/main/java/org/jfree/chart/renderer/OutlierList.java
+++ b/src/main/java/org/jfree/chart/renderer/OutlierList.java
@@ -44,6 +44,8 @@
package org.jfree.chart.renderer;
+import org.checkerframework.checker.index.qual.*;
+
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Iterator;
@@ -103,7 +105,7 @@ public boolean add(Outlier outlier) {
*
* @return The item count.
*/
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.outliers.size();
}
diff --git a/src/main/java/org/jfree/chart/renderer/PolarItemRenderer.java b/src/main/java/org/jfree/chart/renderer/PolarItemRenderer.java
index b19790e44..f45cc788d 100644
--- a/src/main/java/org/jfree/chart/renderer/PolarItemRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/PolarItemRenderer.java
@@ -41,6 +41,8 @@
package org.jfree.chart.renderer;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
@@ -73,7 +75,7 @@ public interface PolarItemRenderer {
*/
public void drawSeries(Graphics2D g2, Rectangle2D dataArea,
PlotRenderingInfo info, PolarPlot plot, XYDataset dataset,
- int seriesIndex);
+ @NonNegative int seriesIndex);
/**
* Draw the angular gridlines - the spokes.
@@ -105,7 +107,7 @@ public void drawRadialGridLines(Graphics2D g2, PolarPlot plot,
*
* @return The legend item.
*/
- public LegendItem getLegendItem(int series);
+ public LegendItem getLegendItem(@NonNegative int series);
/**
* Returns the plot that this renderer has been assigned to.
@@ -149,7 +151,7 @@ public void drawRadialGridLines(Graphics2D g2, PolarPlot plot,
*
* @since 1.0.14
*/
- public XYToolTipGenerator getToolTipGenerator(int row, int column);
+ public XYToolTipGenerator getToolTipGenerator(@NonNegative int row, @NonNegative int column);
/**
* Returns the tool tip generator for a series.
@@ -162,7 +164,7 @@ public void drawRadialGridLines(Graphics2D g2, PolarPlot plot,
*
* @since 1.0.14
*/
- public XYToolTipGenerator getSeriesToolTipGenerator(int series);
+ public XYToolTipGenerator getSeriesToolTipGenerator(@NonNegative int series);
/**
* Sets the tool tip generator for a series and sends a
@@ -175,7 +177,7 @@ public void drawRadialGridLines(Graphics2D g2, PolarPlot plot,
*
* @since 1.0.14
*/
- public void setSeriesToolTipGenerator(int series,
+ public void setSeriesToolTipGenerator(@NonNegative int series,
XYToolTipGenerator generator);
/**
diff --git a/src/main/java/org/jfree/chart/renderer/RendererUtils.java b/src/main/java/org/jfree/chart/renderer/RendererUtils.java
index d362f7681..72f5203eb 100644
--- a/src/main/java/org/jfree/chart/renderer/RendererUtils.java
+++ b/src/main/java/org/jfree/chart/renderer/RendererUtils.java
@@ -44,6 +44,9 @@
package org.jfree.chart.renderer;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
import org.jfree.chart.util.Args;
import org.jfree.data.DomainOrder;
import org.jfree.data.xy.XYDataset;
@@ -70,7 +73,7 @@ public class RendererUtils {
*
* @see #findLiveItemsUpperBound(XYDataset, int, double, double)
*/
- public static int findLiveItemsLowerBound(XYDataset dataset, int series,
+ public static @NonNegative int findLiveItemsLowerBound(XYDataset dataset, @NonNegative int series,
double xLow, double xHigh) {
Args.nullNotPermitted(dataset, "dataset");
if (xLow >= xHigh) {
@@ -83,8 +86,9 @@ public static int findLiveItemsLowerBound(XYDataset dataset, int series,
if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
// for data in ascending order by x-value, we are (broadly) looking
// for the index of the highest x-value that is less than xLow
- int low = 0;
- int high = itemCount - 1;
+ @SuppressWarnings("index") // 0 is an index, because the item count is checked above and the function returns if there isn't at least one item
+ @IndexFor("dataset.getSeries(series)") int low = 0;
+ @IndexFor("dataset.getSeries(series)") int high = itemCount - 1;
double lowValue = dataset.getXValue(series, low);
if (lowValue >= xLow) {
// special case where the lowest x-value is >= xLow
@@ -110,8 +114,9 @@ public static int findLiveItemsLowerBound(XYDataset dataset, int series,
else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
// when the x-values are sorted in descending order, the lower
// bound is found by calculating relative to the xHigh value
- int low = 0;
- int high = itemCount - 1;
+ @SuppressWarnings("index") // 0 is an index, because the item count is checked above and the function returns if there isn't at least one item
+ @IndexFor("dataset.getSeries(series)") int low = 0;
+ @IndexFor("dataset.getSeries(series)") int high = itemCount - 1;
double lowValue = dataset.getXValue(series, low);
if (lowValue <= xHigh) {
return low;
@@ -136,9 +141,11 @@ else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
// we don't know anything about the ordering of the x-values,
// but we can still skip any initial values that fall outside the
// range...
- int index = 0;
+ @SuppressWarnings("index") // 0 is an index, because the item count is checked above and the function returns if there isn't at least one item
+ @IndexFor("dataset.getSeries(series)") int i = 0;
// skip any items that don't need including...
- double x = dataset.getXValue(series, index);
+ double x = dataset.getXValue(series, i);
+ int index = i;
while (index < itemCount && x < xLow) {
index++;
if (index < itemCount) {
@@ -164,7 +171,7 @@ else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
*
* @see #findLiveItemsLowerBound(XYDataset, int, double, double)
*/
- public static int findLiveItemsUpperBound(XYDataset dataset, int series,
+ public static @NonNegative int findLiveItemsUpperBound(XYDataset dataset, @NonNegative int series,
double xLow, double xHigh) {
Args.nullNotPermitted(dataset, "dataset");
if (xLow >= xHigh) {
@@ -175,8 +182,9 @@ public static int findLiveItemsUpperBound(XYDataset dataset, int series,
return 0;
}
if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
- int low = 0;
- int high = itemCount - 1;
+ @SuppressWarnings("index") // 0 is an index, because the item count is checked above and the function returns if there isn't at least one item
+ @IndexFor("dataset.getSeries(series)") int low = 0;
+ @IndexFor("dataset.getSeries(series)") int high = itemCount - 1;
double lowValue = dataset.getXValue(series, low);
if (lowValue > xHigh) {
return low;
@@ -201,8 +209,9 @@ public static int findLiveItemsUpperBound(XYDataset dataset, int series,
else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
// when the x-values are descending, the upper bound is found by
// comparing against xLow
- int low = 0;
- int high = itemCount - 1;
+ @SuppressWarnings("index") // 0 is an index, because the item count is checked above and the function returns if there isn't at least one item
+ @IndexFor("dataset.getSeries(series)") int low = 0;
+ @IndexFor("dataset.getSeries(series)") int high = itemCount - 1;
int mid = (low + high) / 2;
double lowValue = dataset.getXValue(series, low);
if (lowValue < xLow) {
@@ -229,8 +238,8 @@ else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
// but we can still skip any trailing values that fall outside the
// range...
int index = itemCount - 1;
- // skip any items that don't need including...
- double x = dataset.getXValue(series, index);
+ @IndexFor("dataset.getSeries(series)") int indexTmp = index; // skip any items that don't need including...
+ double x = dataset.getXValue(series, indexTmp);
while (index >= 0 && x > xHigh) {
index--;
if (index >= 0) {
@@ -252,17 +261,17 @@ else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
*
* @return The indices of the boundary items.
*/
- public static int[] findLiveItems(XYDataset dataset, int series,
- double xLow, double xHigh) {
+ public static @NonNegative int @ArrayLen(2) [] findLiveItems(XYDataset dataset, @NonNegative int series,
+ double xLow, double xHigh) {
// here we could probably be a little faster by searching for both
// indices simultaneously, but I'll look at that later if it seems
// like it matters...
- int i0 = findLiveItemsLowerBound(dataset, series, xLow, xHigh);
- int i1 = findLiveItemsUpperBound(dataset, series, xLow, xHigh);
+ @NonNegative int i0 = findLiveItemsLowerBound(dataset, series, xLow, xHigh);
+ @NonNegative int i1 = findLiveItemsUpperBound(dataset, series, xLow, xHigh);
if (i0 > i1) {
i0 = i1;
}
- return new int[] {i0, i1};
+ return new @NonNegative int[] {i0, i1};
}
}
diff --git a/src/main/java/org/jfree/chart/renderer/WaferMapRenderer.java b/src/main/java/org/jfree/chart/renderer/WaferMapRenderer.java
index df07663f4..997e863f9 100644
--- a/src/main/java/org/jfree/chart/renderer/WaferMapRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/WaferMapRenderer.java
@@ -44,6 +44,8 @@
package org.jfree.chart.renderer;
+import org.checkerframework.checker.index.qual.*;
+
import java.awt.Color;
import java.awt.Paint;
import java.awt.Shape;
@@ -197,7 +199,8 @@ public Paint getChipColor(Number value) {
*
* @return The paint index.
*/
- private int getPaintIndex(Number value) {
+ @SuppressWarnings("index") // paint indices are always non negative
+ private @NonNegative int getPaintIndex(Number value) {
return ((Integer) this.paintIndex.get(value)).intValue();
}
@@ -301,6 +304,7 @@ public LegendItemCollection getLegendCollection() {
String label = entry.getKey().toString();
String description = label;
Shape shape = new Rectangle2D.Double(1d, 1d, 1d, 1d);
+ @SuppressWarnings("index") // paint indices are always nonnegative
Paint paint = lookupSeriesPaint(
((Integer) entry.getValue()).intValue());
Paint outlinePaint = Color.BLACK;
@@ -324,7 +328,8 @@ public LegendItemCollection getLegendCollection() {
(Integer) entry.getValue()).toString();
String description = label;
Shape shape = new Rectangle2D.Double(1d, 1d, 1d, 1d);
- Paint paint = getSeriesPaint(
+ @SuppressWarnings("index") // paint indices are always nonnegative
+ Paint paint = getSeriesPaint(
((Integer) entry.getValue()).intValue()
);
Paint outlinePaint = Color.BLACK;
diff --git a/src/main/java/org/jfree/chart/renderer/category/AbstractCategoryItemRenderer.java b/src/main/java/org/jfree/chart/renderer/category/AbstractCategoryItemRenderer.java
index 8e85108ff..b309b345c 100644
--- a/src/main/java/org/jfree/chart/renderer/category/AbstractCategoryItemRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/AbstractCategoryItemRenderer.java
@@ -111,6 +111,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.*;
+
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Font;
@@ -213,10 +215,10 @@ public abstract class AbstractCategoryItemRenderer extends AbstractRenderer
private CategorySeriesLabelGenerator legendItemURLGenerator;
/** The number of rows in the dataset (temporary record). */
- private transient int rowCount;
+ private transient @NonNegative int rowCount;
/** The number of columns in the dataset (temporary record). */
- private transient int columnCount;
+ private transient @NonNegative int columnCount;
/**
* Creates a new renderer with no tool tip generator and no URL generator.
@@ -243,7 +245,7 @@ protected AbstractCategoryItemRenderer() {
* @return The pass count.
*/
@Override
- public int getPassCount() {
+ public @NonNegative int getPassCount() {
return 1;
}
@@ -290,7 +292,7 @@ public void setPlot(CategoryPlot plot) {
* @return The generator (possibly {@code null}).
*/
@Override
- public CategoryItemLabelGenerator getItemLabelGenerator(int row,
+ public CategoryItemLabelGenerator getItemLabelGenerator(@NonNegative int row,
int column) {
return getSeriesItemLabelGenerator(row);
}
@@ -305,7 +307,7 @@ public CategoryItemLabelGenerator getItemLabelGenerator(int row,
* @see #setSeriesItemLabelGenerator(int, CategoryItemLabelGenerator)
*/
@Override
- public CategoryItemLabelGenerator getSeriesItemLabelGenerator(int series) {
+ public CategoryItemLabelGenerator getSeriesItemLabelGenerator(@NonNegative int series) {
// otherwise look up the generator table
CategoryItemLabelGenerator generator = this.itemLabelGeneratorMap.get(
@@ -326,7 +328,7 @@ public CategoryItemLabelGenerator getSeriesItemLabelGenerator(int series) {
* @see #getSeriesItemLabelGenerator(int)
*/
@Override
- public void setSeriesItemLabelGenerator(int series,
+ public void setSeriesItemLabelGenerator(@NonNegative int series,
CategoryItemLabelGenerator generator) {
setSeriesItemLabelGenerator(series, generator, true);
}
@@ -342,7 +344,7 @@ public void setSeriesItemLabelGenerator(int series,
* @see #getSeriesItemLabelGenerator(int)
*/
@Override
- public void setSeriesItemLabelGenerator(int series,
+ public void setSeriesItemLabelGenerator(@NonNegative int series,
CategoryItemLabelGenerator generator, boolean notify) {
this.itemLabelGeneratorMap.put(series, generator);
if (notify) {
@@ -409,7 +411,7 @@ public void setDefaultItemLabelGenerator(
* @return The generator (possibly {@code null}).
*/
@Override
- public CategoryToolTipGenerator getToolTipGenerator(int row, int column) {
+ public CategoryToolTipGenerator getToolTipGenerator(@NonNegative int row, @NonNegative int column) {
CategoryToolTipGenerator result = getSeriesToolTipGenerator(row);
if (result == null) {
@@ -429,7 +431,7 @@ public CategoryToolTipGenerator getToolTipGenerator(int row, int column) {
* @see #setSeriesToolTipGenerator(int, CategoryToolTipGenerator)
*/
@Override
- public CategoryToolTipGenerator getSeriesToolTipGenerator(int series) {
+ public CategoryToolTipGenerator getSeriesToolTipGenerator(@NonNegative int series) {
return this.toolTipGeneratorMap.get(series);
}
@@ -443,7 +445,7 @@ public CategoryToolTipGenerator getSeriesToolTipGenerator(int series) {
* @see #getSeriesToolTipGenerator(int)
*/
@Override
- public void setSeriesToolTipGenerator(int series,
+ public void setSeriesToolTipGenerator(@NonNegative int series,
CategoryToolTipGenerator generator) {
setSeriesToolTipGenerator(series, generator, true);
}
@@ -459,7 +461,7 @@ public void setSeriesToolTipGenerator(int series,
* @see #getSeriesToolTipGenerator(int)
*/
@Override
- public void setSeriesToolTipGenerator(int series,
+ public void setSeriesToolTipGenerator(@NonNegative int series,
CategoryToolTipGenerator generator, boolean notify) {
this.toolTipGeneratorMap.put(series, generator);
if (notify) {
@@ -522,7 +524,7 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator, boole
* @return The URL generator.
*/
@Override
- public CategoryURLGenerator getItemURLGenerator(int row, int column) {
+ public CategoryURLGenerator getItemURLGenerator(@NonNegative int row, @NonNegative int column) {
return getSeriesItemURLGenerator(row);
}
@@ -536,7 +538,7 @@ public CategoryURLGenerator getItemURLGenerator(int row, int column) {
* @see #setSeriesItemURLGenerator(int, CategoryURLGenerator)
*/
@Override
- public CategoryURLGenerator getSeriesItemURLGenerator(int series) {
+ public CategoryURLGenerator getSeriesItemURLGenerator(@NonNegative int series) {
// otherwise look up the generator table
CategoryURLGenerator generator = this.itemURLGeneratorMap.get(series);
if (generator == null) {
@@ -555,7 +557,7 @@ public CategoryURLGenerator getSeriesItemURLGenerator(int series) {
* @see #getSeriesItemURLGenerator(int)
*/
@Override
- public void setSeriesItemURLGenerator(int series,
+ public void setSeriesItemURLGenerator(@NonNegative int series,
CategoryURLGenerator generator) {
setSeriesItemURLGenerator(series, generator, true);
}
@@ -571,7 +573,7 @@ public void setSeriesItemURLGenerator(int series,
* @see #getSeriesItemURLGenerator(int)
*/
@Override
- public void setSeriesItemURLGenerator(int series,
+ public void setSeriesItemURLGenerator(@NonNegative int series,
CategoryURLGenerator generator, boolean notify) {
this.itemURLGeneratorMap.put(series, generator);
if (notify) {
@@ -627,7 +629,7 @@ public void setDefaultItemURLGenerator(CategoryURLGenerator generator, boolean n
*
* @return The row count.
*/
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.rowCount;
}
@@ -637,7 +639,7 @@ public int getRowCount() {
*
* @return The column count.
*/
- public int getColumnCount() {
+ public @NonNegative int getColumnCount() {
return this.columnCount;
}
@@ -674,7 +676,7 @@ protected CategoryItemRendererState createState(PlotRenderingInfo info) {
*/
@Override
public CategoryItemRendererState initialise(Graphics2D g2,
- Rectangle2D dataArea, CategoryPlot plot, int rendererIndex,
+ Rectangle2D dataArea, CategoryPlot plot, @NonNegative int rendererIndex,
PlotRenderingInfo info) {
setPlot(plot);
@@ -688,17 +690,22 @@ public CategoryItemRendererState initialise(Graphics2D g2,
}
CategoryItemRendererState state = createState(info);
state.setElementHinting(plot.fetchElementHintingFlag());
- int[] visibleSeriesTemp = new int[this.rowCount];
+ int rowCount = this.rowCount;
+ int[] visibleSeriesTemp = new int[rowCount];
int visibleSeriesCount = 0;
- for (int row = 0; row < this.rowCount; row++) {
+ for (int row = 0; row < rowCount; row++) {
if (isSeriesVisible(row)) {
- visibleSeriesTemp[visibleSeriesCount] = row;
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/219: visibleSeriesCount is incremented at most as many times as row, which is an index
+ @IndexFor("visibleSeriesTemp") int visibleSeriesCountTemp = visibleSeriesCount;
+ visibleSeriesTemp[visibleSeriesCountTemp] = row;
visibleSeriesCount++;
}
}
- int[] visibleSeries = new int[visibleSeriesCount];
+ @NonNegative int[] visibleSeries = new int[visibleSeriesCount];
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/219: visibleSeriesCount is incremented at most as many times as row, which is an index
+ @IndexOrHigh({"visibleSeriesTemp", "visibleSeries"}) int visibleSeriesCountTemp = visibleSeriesCount;
System.arraycopy(visibleSeriesTemp, 0, visibleSeries, 0,
- visibleSeriesCount);
+ visibleSeriesCountTemp);
state.setVisibleSeriesArray(visibleSeries);
return state;
}
@@ -927,6 +934,7 @@ public void drawDomainMarker(Graphics2D g2, CategoryPlot plot,
CategoryAxis axis, CategoryMarker marker, Rectangle2D dataArea) {
Comparable category = marker.getKey();
+ @SuppressWarnings("index") // this will fail if this renderer is not associated with the given plot. A bug?
CategoryDataset dataset = plot.getDataset(plot.getIndexOf(this));
int columnIndex = dataset.getColumnIndex(category);
if (columnIndex < 0) {
@@ -1246,7 +1254,7 @@ protected Point2D calculateRangeMarkerTextAnchorPoint(Graphics2D g2,
* @see #getLegendItems()
*/
@Override
- public LegendItem getLegendItem(int datasetIndex, int series) {
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series) {
CategoryPlot p = getPlot();
if (p == null) {
@@ -1393,7 +1401,7 @@ public DrawingSupplier getDrawingSupplier() {
*/
protected void updateCrosshairValues(CategoryCrosshairState crosshairState,
Comparable rowKey, Comparable columnKey, double value,
- int datasetIndex,
+ @NonNegative int datasetIndex,
double transX, double transY, PlotOrientation orientation) {
Args.nullNotPermitted(orientation, "orientation");
@@ -1425,7 +1433,7 @@ protected void updateCrosshairValues(CategoryCrosshairState crosshairState,
* label position).
*/
protected void drawItemLabel(Graphics2D g2, PlotOrientation orientation,
- CategoryDataset dataset, int row, int column,
+ CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
double x, double y, boolean negative) {
CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
@@ -1544,7 +1552,7 @@ public Object clone() throws CloneNotSupportedException {
*
* @return A domain axis.
*/
- protected CategoryAxis getDomainAxis(CategoryPlot plot, int index) {
+ protected CategoryAxis getDomainAxis(CategoryPlot plot, @NonNegative int index) {
CategoryAxis result = plot.getDomainAxis(index);
if (result == null) {
result = plot.getDomainAxis();
@@ -1560,7 +1568,7 @@ protected CategoryAxis getDomainAxis(CategoryPlot plot, int index) {
*
* @return A range axis.
*/
- protected ValueAxis getRangeAxis(CategoryPlot plot, int index) {
+ protected ValueAxis getRangeAxis(CategoryPlot plot, @NonNegative int index) {
ValueAxis result = plot.getRangeAxis(index);
if (result == null) {
result = plot.getRangeAxis();
@@ -1582,7 +1590,8 @@ public LegendItemCollection getLegendItems() {
if (this.plot == null) {
return result;
}
- int index = this.plot.getIndexOf(this);
+ @SuppressWarnings("index") // guaranteed index: this.plot.getIndexOf(this) is always non negative, since this.plot is the plot associated with the renderer
+ @NonNegative int index = this.plot.getIndexOf(this);
CategoryDataset dataset = this.plot.getDataset(index);
if (dataset == null) {
return result;
@@ -1697,7 +1706,7 @@ public void setLegendItemURLGenerator(
* @param hotspot the hotspot ({@code null} not permitted).
*/
protected void addItemEntity(EntityCollection entities,
- CategoryDataset dataset, int row, int column, Shape hotspot) {
+ CategoryDataset dataset, @NonNegative int row, @NonNegative int column, Shape hotspot) {
Args.nullNotPermitted(hotspot, "hotspot");
if (!getItemCreateEntity(row, column)) {
return;
@@ -1734,7 +1743,7 @@ protected void addItemEntity(EntityCollection entities,
* @since 1.0.13
*/
protected void addEntity(EntityCollection entities, Shape hotspot,
- CategoryDataset dataset, int row, int column,
+ CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
double entityX, double entityY) {
if (!getItemCreateEntity(row, column)) {
return;
diff --git a/src/main/java/org/jfree/chart/renderer/category/AreaRenderer.java b/src/main/java/org/jfree/chart/renderer/category/AreaRenderer.java
index b544bf798..14c5098c8 100644
--- a/src/main/java/org/jfree/chart/renderer/category/AreaRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/AreaRenderer.java
@@ -74,6 +74,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
@@ -157,7 +159,7 @@ public void setEndType(AreaRendererEndType type) {
* @return The legend item.
*/
@Override
- public LegendItem getLegendItem(int datasetIndex, int series) {
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series) {
// if there is no plot, there is no dataset to access...
CategoryPlot cp = getPlot();
@@ -221,7 +223,7 @@ public LegendItem getLegendItem(int datasetIndex, int series) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
// do nothing if item is not visible or null
@@ -320,7 +322,8 @@ else if (orientation == PlotOrientation.HORIZONTAL) {
}
// submit the current data point as a crosshair candidate
- int datasetIndex = plot.indexOf(dataset);
+ @SuppressWarnings("index") // documentation bug: dataset is assumed to be associated with plot
+ @NonNegative int datasetIndex = plot.indexOf(dataset);
updateCrosshairValues(state.getCrosshairState(),
dataset.getRowKey(row), dataset.getColumnKey(column), yy1,
datasetIndex, x1, y1, orientation);
diff --git a/src/main/java/org/jfree/chart/renderer/category/BarPainter.java b/src/main/java/org/jfree/chart/renderer/category/BarPainter.java
index 4522152fd..e42ec405f 100644
--- a/src/main/java/org/jfree/chart/renderer/category/BarPainter.java
+++ b/src/main/java/org/jfree/chart/renderer/category/BarPainter.java
@@ -40,6 +40,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.geom.RectangularShape;
import org.jfree.chart.ui.RectangleEdge;
@@ -72,7 +74,7 @@ public interface BarPainter {
* @param base the base of the bar.
*/
public void paintBar(Graphics2D g2, BarRenderer renderer,
- int row, int column, RectangularShape bar, RectangleEdge base);
+ @NonNegative int row, @NonNegative int column, RectangularShape bar, RectangleEdge base);
/**
* Paints the shadow for a single bar on behalf of a renderer.
@@ -86,7 +88,7 @@ public void paintBar(Graphics2D g2, BarRenderer renderer,
* @param pegShadow peg the shadow to the base of the bar?
*/
public void paintBarShadow(Graphics2D g2, BarRenderer renderer,
- int row, int column, RectangularShape bar, RectangleEdge base,
+ @NonNegative int row, @NonNegative int column, RectangularShape bar, RectangleEdge base,
boolean pegShadow);
}
diff --git a/src/main/java/org/jfree/chart/renderer/category/BarRenderer.java b/src/main/java/org/jfree/chart/renderer/category/BarRenderer.java
index 846125d21..9c854ab9e 100644
--- a/src/main/java/org/jfree/chart/renderer/category/BarRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/BarRenderer.java
@@ -96,6 +96,10 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.common.value.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
@@ -743,7 +747,7 @@ public double getUpperClip() {
*/
@Override
public CategoryItemRendererState initialise(Graphics2D g2,
- Rectangle2D dataArea, CategoryPlot plot, int rendererIndex,
+ Rectangle2D dataArea, CategoryPlot plot, @NonNegative int rendererIndex,
PlotRenderingInfo info) {
CategoryItemRendererState state = super.initialise(g2, dataArea, plot,
@@ -771,7 +775,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*/
protected void calculateBarWidth(CategoryPlot plot,
Rectangle2D dataArea,
- int rendererIndex,
+ @NonNegative int rendererIndex,
CategoryItemRendererState state) {
CategoryAxis domainAxis = getDomainAxis(plot, rendererIndex);
@@ -827,7 +831,7 @@ else if (orientation == PlotOrientation.VERTICAL) {
protected double calculateBarW0(CategoryPlot plot,
PlotOrientation orientation, Rectangle2D dataArea,
CategoryAxis domainAxis, CategoryItemRendererState state,
- int row, int column) {
+ @NonNegative int row, @NonNegative int column) {
// calculate bar width...
double space;
if (orientation == PlotOrientation.HORIZONTAL) {
@@ -865,7 +869,7 @@ protected double calculateBarW0(CategoryPlot plot,
* @return The coordinates for each end of the bar (or {@code null} if
* the bar is not visible for the current axis range).
*/
- protected double[] calculateBarL0L1(double value) {
+ protected double @ArrayLen(2) [] calculateBarL0L1(double value) {
double lclip = getLowerClip();
double uclip = getUpperClip();
double barLow = Math.min(this.base, value);
@@ -917,7 +921,7 @@ public Range findRangeBounds(CategoryDataset dataset,
* @return The legend item (possibly {@code null}).
*/
@Override
- public LegendItem getLegendItem(int datasetIndex, int series) {
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series) {
CategoryPlot cp = getPlot();
if (cp == null) {
@@ -984,8 +988,8 @@ urlText, true, shape, true, paint, isDrawBarOutline(),
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row,
- int column, int pass) {
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row,
+ @NonNegative int column, int pass) {
// nothing is drawn if the row index is not included in the list with
// the indices of the visible rows...
@@ -1080,7 +1084,8 @@ public void drawItem(Graphics2D g2, CategoryItemRendererState state,
}
// submit the current data point as a crosshair candidate
- int datasetIndex = plot.indexOf(dataset);
+ @SuppressWarnings("index") // documentation bug: dataset is assumed to be associated with plot
+ @NonNegative int datasetIndex = plot.indexOf(dataset);
updateCrosshairValues(state.getCrosshairState(),
dataset.getRowKey(row), dataset.getColumnKey(column), value,
datasetIndex, barW0, barL0, orientation);
@@ -1104,7 +1109,7 @@ public void drawItem(Graphics2D g2, CategoryItemRendererState state,
* @return The width of one series.
*/
protected double calculateSeriesWidth(double space, CategoryAxis axis,
- int categories, int series) {
+ int categories, @NonNegative int series) {
double factor = 1.0 - getItemMargin() - axis.getLowerMargin()
- axis.getUpperMargin();
if (categories > 1) {
@@ -1128,8 +1133,8 @@ protected double calculateSeriesWidth(double space, CategoryAxis axis,
*/
protected void drawItemLabel(Graphics2D g2,
CategoryDataset data,
- int row,
- int column,
+ @NonNegative int row,
+ @NonNegative int column,
CategoryPlot plot,
CategoryItemLabelGenerator generator,
Rectangle2D bar,
diff --git a/src/main/java/org/jfree/chart/renderer/category/BoxAndWhiskerRenderer.java b/src/main/java/org/jfree/chart/renderer/category/BoxAndWhiskerRenderer.java
index 4639d665c..c45c1ffef 100644
--- a/src/main/java/org/jfree/chart/renderer/category/BoxAndWhiskerRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/BoxAndWhiskerRenderer.java
@@ -91,6 +91,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
@@ -451,7 +453,7 @@ public void setWhiskerWidth(double width) {
* @return The legend item (possibly {@code null}).
*/
@Override
- public LegendItem getLegendItem(int datasetIndex, int series) {
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series) {
CategoryPlot cp = getPlot();
if (cp == null) {
@@ -523,7 +525,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
*/
@Override
public CategoryItemRendererState initialise(Graphics2D g2,
- Rectangle2D dataArea, CategoryPlot plot, int rendererIndex,
+ Rectangle2D dataArea, CategoryPlot plot, @NonNegative int rendererIndex,
PlotRenderingInfo info) {
CategoryItemRendererState state = super.initialise(g2, dataArea, plot,
@@ -584,7 +586,7 @@ else if (orientation == PlotOrientation.VERTICAL) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
// do nothing if item is not visible
@@ -630,7 +632,7 @@ else if (orientation == PlotOrientation.VERTICAL) {
public void drawHorizontalItem(Graphics2D g2,
CategoryItemRendererState state, Rectangle2D dataArea,
CategoryPlot plot, CategoryAxis domainAxis, ValueAxis rangeAxis,
- CategoryDataset dataset, int row, int column) {
+ CategoryDataset dataset, @NonNegative int row, @NonNegative int column) {
BoxAndWhiskerCategoryDataset bawDataset
= (BoxAndWhiskerCategoryDataset) dataset;
@@ -773,7 +775,7 @@ public void drawHorizontalItem(Graphics2D g2,
*/
public void drawVerticalItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column) {
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column) {
BoxAndWhiskerCategoryDataset bawDataset
= (BoxAndWhiskerCategoryDataset) dataset;
diff --git a/src/main/java/org/jfree/chart/renderer/category/CategoryItemRenderer.java b/src/main/java/org/jfree/chart/renderer/category/CategoryItemRenderer.java
index 7c7dade56..2f67593a8 100644
--- a/src/main/java/org/jfree/chart/renderer/category/CategoryItemRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/CategoryItemRenderer.java
@@ -97,6 +97,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Paint;
@@ -148,7 +150,7 @@ public interface CategoryItemRenderer extends LegendItemSource {
*
* @return The pass count.
*/
- public int getPassCount();
+ public @NonNegative int getPassCount();
/**
* Returns the plot that the renderer has been assigned to (where
@@ -219,7 +221,7 @@ public interface CategoryItemRenderer extends LegendItemSource {
public CategoryItemRendererState initialise(Graphics2D g2,
Rectangle2D dataArea,
CategoryPlot plot,
- int rendererIndex,
+ @NonNegative int rendererIndex,
PlotRenderingInfo info);
/**
@@ -231,7 +233,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @return A boolean.
*/
- public boolean getItemVisible(int series, int item);
+ public boolean getItemVisible(@NonNegative int series, @NonNegative int item);
/**
* Returns a boolean that indicates whether or not the specified series
@@ -241,7 +243,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @return A boolean.
*/
- public boolean isSeriesVisible(int series);
+ public boolean isSeriesVisible(@NonNegative int series);
/**
* Returns the flag that controls whether a series is visible.
@@ -252,7 +254,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @see #setSeriesVisible(int, Boolean)
*/
- public Boolean getSeriesVisible(int series);
+ public Boolean getSeriesVisible(@NonNegative int series);
/**
* Sets the flag that controls whether a series is visible and sends a
@@ -263,7 +265,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @see #getSeriesVisible(int)
*/
- public void setSeriesVisible(int series, Boolean visible);
+ public void setSeriesVisible(@NonNegative int series, Boolean visible);
/**
* Sets the flag that controls whether a series is visible and, if
@@ -276,7 +278,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @see #getSeriesVisible(int)
*/
- public void setSeriesVisible(int series, Boolean visible, boolean notify);
+ public void setSeriesVisible(@NonNegative int series, Boolean visible, boolean notify);
/**
* Returns the default visibility for all series.
@@ -318,7 +320,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @return A boolean.
*/
- public boolean isSeriesVisibleInLegend(int series);
+ public boolean isSeriesVisibleInLegend(@NonNegative int series);
/**
* Returns the flag that controls whether a series is visible in the
@@ -332,7 +334,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @see #setSeriesVisibleInLegend(int, Boolean)
*/
- public Boolean getSeriesVisibleInLegend(int series);
+ public Boolean getSeriesVisibleInLegend(@NonNegative int series);
/**
* Sets the flag that controls whether a series is visible in the legend
@@ -343,7 +345,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @see #getSeriesVisibleInLegend(int)
*/
- public void setSeriesVisibleInLegend(int series, Boolean visible);
+ public void setSeriesVisibleInLegend(@NonNegative int series, Boolean visible);
/**
* Sets the flag that controls whether a series is visible in the legend
@@ -356,7 +358,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
*
* @see #getSeriesVisibleInLegend(int)
*/
- public void setSeriesVisibleInLegend(int series, Boolean visible,
+ public void setSeriesVisibleInLegend(@NonNegative int series, Boolean visible,
boolean notify);
/**
@@ -400,7 +402,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @return The paint (never {@code null}).
*/
- public Paint getItemPaint(int row, int column);
+ public Paint getItemPaint(@NonNegative int row, @NonNegative int column);
/**
* Returns the paint used to fill an item drawn by the renderer.
@@ -411,7 +413,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #setSeriesPaint(int, Paint)
*/
- public Paint getSeriesPaint(int series);
+ public Paint getSeriesPaint(@NonNegative int series);
/**
* Sets the paint used for a series and sends a {@link RendererChangeEvent}
@@ -422,9 +424,9 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #getSeriesPaint(int)
*/
- public void setSeriesPaint(int series, Paint paint);
+ public void setSeriesPaint(@NonNegative int series, Paint paint);
- public void setSeriesPaint(int series, Paint paint, boolean notify);
+ public void setSeriesPaint(@NonNegative int series, Paint paint, boolean notify);
/**
* Returns the default paint.
@@ -457,7 +459,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @return The paint (never {@code null}).
*/
- public Paint getItemFillPaint(int row, int column);
+ public Paint getItemFillPaint(@NonNegative int row, @NonNegative int column);
/**
* Returns the paint used to fill an item drawn by the renderer.
@@ -468,7 +470,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #setSeriesFillPaint(int, Paint)
*/
- public Paint getSeriesFillPaint(int series);
+ public Paint getSeriesFillPaint(@NonNegative int series);
/**
* Sets the paint used for a series outline and sends a
@@ -479,7 +481,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #getSeriesFillPaint(int)
*/
- public void setSeriesFillPaint(int series, Paint paint);
+ public void setSeriesFillPaint(@NonNegative int series, Paint paint);
/**
* Returns the default outline paint.
@@ -510,7 +512,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @return The paint (never {@code null}).
*/
- public Paint getItemOutlinePaint(int row, int column);
+ public Paint getItemOutlinePaint(@NonNegative int row, @NonNegative int column);
/**
* Returns the paint used to outline an item drawn by the renderer.
@@ -521,7 +523,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #setSeriesOutlinePaint(int, Paint)
*/
- public Paint getSeriesOutlinePaint(int series);
+ public Paint getSeriesOutlinePaint(@NonNegative int series);
/**
* Sets the paint used for a series outline and sends a
@@ -532,9 +534,9 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #getSeriesOutlinePaint(int)
*/
- public void setSeriesOutlinePaint(int series, Paint paint);
+ public void setSeriesOutlinePaint(@NonNegative int series, Paint paint);
- public void setSeriesOutlinePaint(int series, Paint paint, boolean notify);
+ public void setSeriesOutlinePaint(@NonNegative int series, Paint paint, boolean notify);
/**
* Returns the default outline paint.
@@ -567,7 +569,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @return The stroke (never {@code null}).
*/
- public Stroke getItemStroke(int row, int column);
+ public Stroke getItemStroke(@NonNegative int row, @NonNegative int column);
/**
* Returns the stroke used to draw the items in a series.
@@ -578,7 +580,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #setSeriesStroke(int, Stroke)
*/
- public Stroke getSeriesStroke(int series);
+ public Stroke getSeriesStroke(@NonNegative int series);
/**
* Sets the stroke used for a series and sends a
@@ -589,9 +591,9 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #getSeriesStroke(int)
*/
- public void setSeriesStroke(int series, Stroke stroke);
+ public void setSeriesStroke(@NonNegative int series, Stroke stroke);
- public void setSeriesStroke(int series, Stroke stroke, boolean notify);
+ public void setSeriesStroke(@NonNegative int series, Stroke stroke, boolean notify);
/**
* Returns the default stroke.
@@ -628,7 +630,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @return The stroke (never {@code null}).
*/
- public Stroke getItemOutlineStroke(int row, int column);
+ public Stroke getItemOutlineStroke(@NonNegative int row, @NonNegative int column);
/**
* Returns the stroke used to outline the items in a series.
@@ -639,7 +641,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #setSeriesOutlineStroke(int, Stroke)
*/
- public Stroke getSeriesOutlineStroke(int series);
+ public Stroke getSeriesOutlineStroke(@NonNegative int series);
/**
* Sets the outline stroke used for a series and sends a
@@ -650,9 +652,9 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #getSeriesOutlineStroke(int)
*/
- public void setSeriesOutlineStroke(int series, Stroke stroke);
+ public void setSeriesOutlineStroke(@NonNegative int series, Stroke stroke);
- public void setSeriesOutlineStroke(int series, Stroke stroke, boolean notify);
+ public void setSeriesOutlineStroke(@NonNegative int series, Stroke stroke, boolean notify);
/**
* Returns the default outline stroke.
@@ -685,7 +687,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @return The shape (never {@code null}).
*/
- public Shape getItemShape(int row, int column);
+ public Shape getItemShape(@NonNegative int row, @NonNegative int column);
/**
* Returns a shape used to represent the items in a series.
@@ -696,7 +698,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #setSeriesShape(int, Shape)
*/
- public Shape getSeriesShape(int series);
+ public Shape getSeriesShape(@NonNegative int series);
/**
* Sets the shape used for a series and sends a {@link RendererChangeEvent}
@@ -707,9 +709,9 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #getSeriesShape(int)
*/
- public void setSeriesShape(int series, Shape shape);
+ public void setSeriesShape(@NonNegative int series, Shape shape);
- public void setSeriesShape(int series, Shape shape, boolean notify);
+ public void setSeriesShape(@NonNegative int series, Shape shape, boolean notify);
/**
* Returns the default shape.
@@ -743,7 +745,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @return A boolean.
*/
- public boolean isItemLabelVisible(int row, int column);
+ public boolean isItemLabelVisible(@NonNegative int row, @NonNegative int column);
/**
* Returns {@code true} if the item labels for a series are visible,
@@ -755,7 +757,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #setSeriesItemLabelsVisible(int, Boolean)
*/
- public boolean isSeriesItemLabelsVisible(int series);
+ public boolean isSeriesItemLabelsVisible(@NonNegative int series);
/**
* Sets a flag that controls the visibility of the item labels for a series.
@@ -765,7 +767,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #isSeriesItemLabelsVisible(int)
*/
- public void setSeriesItemLabelsVisible(int series, boolean visible);
+ public void setSeriesItemLabelsVisible(@NonNegative int series, boolean visible);
/**
* Sets a flag that controls the visibility of the item labels for a series.
@@ -775,7 +777,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #isSeriesItemLabelsVisible(int)
*/
- public void setSeriesItemLabelsVisible(int series, Boolean visible);
+ public void setSeriesItemLabelsVisible(@NonNegative int series, Boolean visible);
/**
* Sets the visibility of item labels for a series and, if requested, sends
@@ -788,7 +790,7 @@ public void setSeriesVisibleInLegend(int series, Boolean visible,
*
* @see #isSeriesItemLabelsVisible(int)
*/
- public void setSeriesItemLabelsVisible(int series, Boolean visible,
+ public void setSeriesItemLabelsVisible(@NonNegative int series, Boolean visible,
boolean notify);
/**
@@ -835,7 +837,7 @@ public void setSeriesItemLabelsVisible(int series, Boolean visible,
*
* @return The generator (possibly {@code null}).
*/
- public CategoryItemLabelGenerator getItemLabelGenerator(int series,
+ public CategoryItemLabelGenerator getItemLabelGenerator(@NonNegative int series,
int item);
/**
@@ -847,7 +849,7 @@ public CategoryItemLabelGenerator getItemLabelGenerator(int series,
*
* @see #setSeriesItemLabelGenerator(int, CategoryItemLabelGenerator)
*/
- public CategoryItemLabelGenerator getSeriesItemLabelGenerator(int series);
+ public CategoryItemLabelGenerator getSeriesItemLabelGenerator(@NonNegative int series);
/**
* Sets the item label generator for a series and sends a
@@ -858,10 +860,10 @@ public CategoryItemLabelGenerator getItemLabelGenerator(int series,
*
* @see #getSeriesItemLabelGenerator(int)
*/
- public void setSeriesItemLabelGenerator(int series,
+ public void setSeriesItemLabelGenerator(@NonNegative int series,
CategoryItemLabelGenerator generator);
- public void setSeriesItemLabelGenerator(int series,
+ public void setSeriesItemLabelGenerator(@NonNegative int series,
CategoryItemLabelGenerator generator, boolean notify);
/**
@@ -898,7 +900,7 @@ public void setDefaultItemLabelGenerator(CategoryItemLabelGenerator generator,
*
* @return The generator (possibly {@code null}).
*/
- public CategoryToolTipGenerator getToolTipGenerator(int row, int column);
+ public CategoryToolTipGenerator getToolTipGenerator(@NonNegative int row, @NonNegative int column);
/**
* Returns the tool tip generator for the specified series (a "layer 1"
@@ -910,7 +912,7 @@ public void setDefaultItemLabelGenerator(CategoryItemLabelGenerator generator,
*
* @see #setSeriesToolTipGenerator(int, CategoryToolTipGenerator)
*/
- public CategoryToolTipGenerator getSeriesToolTipGenerator(int series);
+ public CategoryToolTipGenerator getSeriesToolTipGenerator(@NonNegative int series);
/**
* Sets the tool tip generator for a series and sends a
@@ -922,10 +924,10 @@ public void setDefaultItemLabelGenerator(CategoryItemLabelGenerator generator,
*
* @see #getSeriesToolTipGenerator(int)
*/
- public void setSeriesToolTipGenerator(int series,
+ public void setSeriesToolTipGenerator(@NonNegative int series,
CategoryToolTipGenerator generator);
- public void setSeriesToolTipGenerator(int series,
+ public void setSeriesToolTipGenerator(@NonNegative int series,
CategoryToolTipGenerator generator, boolean notify);
/**
@@ -961,7 +963,7 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @return The font (never {@code null}).
*/
- public Font getItemLabelFont(int row, int column);
+ public Font getItemLabelFont(@NonNegative int row, @NonNegative int column);
/**
* Returns the font for all the item labels in a series.
@@ -972,7 +974,7 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @see #setSeriesItemLabelFont(int, Font)
*/
- public Font getSeriesItemLabelFont(int series);
+ public Font getSeriesItemLabelFont(@NonNegative int series);
/**
* Sets the item label font for a series and sends a
@@ -983,9 +985,9 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @see #getSeriesItemLabelFont(int)
*/
- public void setSeriesItemLabelFont(int series, Font font);
+ public void setSeriesItemLabelFont(@NonNegative int series, Font font);
- public void setSeriesItemLabelFont(int series, Font font, boolean notify);
+ public void setSeriesItemLabelFont(@NonNegative int series, Font font, boolean notify);
/**
* Returns the default item label font (this is used when no other font
@@ -1019,7 +1021,7 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @return The paint (never {@code null}).
*/
- public Paint getItemLabelPaint(int row, int column);
+ public Paint getItemLabelPaint(@NonNegative int row, @NonNegative int column);
/**
* Returns the paint used to draw the item labels for a series.
@@ -1030,7 +1032,7 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @see #setSeriesItemLabelPaint(int, Paint)
*/
- public Paint getSeriesItemLabelPaint(int series);
+ public Paint getSeriesItemLabelPaint(@NonNegative int series);
/**
* Sets the item label paint for a series and sends a
@@ -1041,9 +1043,9 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @see #getSeriesItemLabelPaint(int)
*/
- public void setSeriesItemLabelPaint(int series, Paint paint);
+ public void setSeriesItemLabelPaint(@NonNegative int series, Paint paint);
- public void setSeriesItemLabelPaint(int series, Paint paint, boolean notify);
+ public void setSeriesItemLabelPaint(@NonNegative int series, Paint paint, boolean notify);
/**
* Returns the default item label paint.
@@ -1076,7 +1078,7 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @return The item label position (never {@code null}).
*/
- public ItemLabelPosition getPositiveItemLabelPosition(int row, int column);
+ public ItemLabelPosition getPositiveItemLabelPosition(@NonNegative int row, @NonNegative int column);
/**
* Returns the item label position for all positive values in a series.
@@ -1087,7 +1089,7 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @see #setSeriesPositiveItemLabelPosition(int, ItemLabelPosition)
*/
- public ItemLabelPosition getSeriesPositiveItemLabelPosition(int series);
+ public ItemLabelPosition getSeriesPositiveItemLabelPosition(@NonNegative int series);
/**
* Sets the item label position for all positive values in a series and
@@ -1098,7 +1100,7 @@ public void setDefaultToolTipGenerator(CategoryToolTipGenerator generator,
*
* @see #getSeriesPositiveItemLabelPosition(int)
*/
- public void setSeriesPositiveItemLabelPosition(int series,
+ public void setSeriesPositiveItemLabelPosition(@NonNegative int series,
ItemLabelPosition position);
/**
@@ -1112,7 +1114,7 @@ public void setSeriesPositiveItemLabelPosition(int series,
*
* @see #getSeriesPositiveItemLabelPosition(int)
*/
- public void setSeriesPositiveItemLabelPosition(int series,
+ public void setSeriesPositiveItemLabelPosition(@NonNegative int series,
ItemLabelPosition position, boolean notify);
/**
@@ -1158,7 +1160,7 @@ public void setDefaultPositiveItemLabelPosition(ItemLabelPosition position,
*
* @return The item label position.
*/
- public ItemLabelPosition getNegativeItemLabelPosition(int row, int column);
+ public ItemLabelPosition getNegativeItemLabelPosition(@NonNegative int row, @NonNegative int column);
/**
* Returns the item label position for all negative values in a series.
@@ -1169,7 +1171,7 @@ public void setDefaultPositiveItemLabelPosition(ItemLabelPosition position,
*
* @see #setSeriesNegativeItemLabelPosition(int, ItemLabelPosition)
*/
- public ItemLabelPosition getSeriesNegativeItemLabelPosition(int series);
+ public ItemLabelPosition getSeriesNegativeItemLabelPosition(@NonNegative int series);
/**
* Sets the item label position for negative values in a series and sends a
@@ -1180,7 +1182,7 @@ public void setDefaultPositiveItemLabelPosition(ItemLabelPosition position,
*
* @see #getSeriesNegativeItemLabelPosition(int)
*/
- public void setSeriesNegativeItemLabelPosition(int series,
+ public void setSeriesNegativeItemLabelPosition(@NonNegative int series,
ItemLabelPosition position);
/**
@@ -1194,7 +1196,7 @@ public void setSeriesNegativeItemLabelPosition(int series,
*
* @see #getSeriesNegativeItemLabelPosition(int)
*/
- public void setSeriesNegativeItemLabelPosition(int series,
+ public void setSeriesNegativeItemLabelPosition(@NonNegative int series,
ItemLabelPosition position, boolean notify);
/**
@@ -1230,13 +1232,13 @@ public void setDefaultNegativeItemLabelPosition(ItemLabelPosition position,
// CREATE ENTITIES
- public boolean getItemCreateEntity(int series, int item);
+ public boolean getItemCreateEntity(@NonNegative int series, @NonNegative int item);
- public Boolean getSeriesCreateEntities(int series);
+ public Boolean getSeriesCreateEntities(@NonNegative int series);
- public void setSeriesCreateEntities(int series, Boolean create);
+ public void setSeriesCreateEntities(@NonNegative int series, Boolean create);
- public void setSeriesCreateEntities(int series, Boolean create,
+ public void setSeriesCreateEntities(@NonNegative int series, Boolean create,
boolean notify);
public boolean getDefaultCreateEntities();
@@ -1256,7 +1258,7 @@ public void setSeriesCreateEntities(int series, Boolean create,
*
* @return The item URL generator.
*/
- public CategoryURLGenerator getItemURLGenerator(int series, int item);
+ public CategoryURLGenerator getItemURLGenerator(@NonNegative int series, @NonNegative int item);
/**
* Returns the item URL generator for a series.
@@ -1267,7 +1269,7 @@ public void setSeriesCreateEntities(int series, Boolean create,
*
* @see #setSeriesItemURLGenerator(int, CategoryURLGenerator)
*/
- public CategoryURLGenerator getSeriesItemURLGenerator(int series);
+ public CategoryURLGenerator getSeriesItemURLGenerator(@NonNegative int series);
/**
* Sets the item URL generator for a series.
@@ -1277,10 +1279,10 @@ public void setSeriesCreateEntities(int series, Boolean create,
*
* @see #getSeriesItemURLGenerator(int)
*/
- public void setSeriesItemURLGenerator(int series,
+ public void setSeriesItemURLGenerator(@NonNegative int series,
CategoryURLGenerator generator);
- public void setSeriesItemURLGenerator(int series,
+ public void setSeriesItemURLGenerator(@NonNegative int series,
CategoryURLGenerator generator, boolean notify);
/**
@@ -1314,7 +1316,7 @@ public void setSeriesItemURLGenerator(int series,
*
* @return The legend item (possibly {@code null}).
*/
- public LegendItem getLegendItem(int datasetIndex, int series);
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series);
/**
* Draws a background for the data area.
@@ -1352,7 +1354,7 @@ public void drawOutline(Graphics2D g2, CategoryPlot plot,
*/
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass);
/**
diff --git a/src/main/java/org/jfree/chart/renderer/category/CategoryItemRendererState.java b/src/main/java/org/jfree/chart/renderer/category/CategoryItemRendererState.java
index 34373ad34..1e57ab9d3 100644
--- a/src/main/java/org/jfree/chart/renderer/category/CategoryItemRendererState.java
+++ b/src/main/java/org/jfree/chart/renderer/category/CategoryItemRendererState.java
@@ -45,6 +45,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.*;
+
import org.jfree.chart.plot.CategoryCrosshairState;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.renderer.RendererState;
@@ -62,7 +64,7 @@ public class CategoryItemRendererState extends RendererState {
private double seriesRunningTotal;
/** The array with the indices of the visible series.*/
- private int[] visibleSeries;
+ private @NonNegative int[] visibleSeries;
/**
* State information for crosshairs in the plot (this is updated by the
@@ -168,7 +170,7 @@ public void setCrosshairState(CategoryCrosshairState state) {
*
* @since 1.0.13
*/
- public int getVisibleSeriesIndex(int rowIndex) {
+ public int getVisibleSeriesIndex(@NonNegative int rowIndex) {
if (this.visibleSeries == null) {
return rowIndex;
}
@@ -204,11 +206,11 @@ public int getVisibleSeriesCount() {
*
* @since 1.0.13
*/
- public int[] getVisibleSeriesArray() {
+ public @NonNegative int[] getVisibleSeriesArray() {
if (this.visibleSeries == null) {
return null;
}
- int[] result = new int[this.visibleSeries.length];
+ @NonNegative int[] result = new int[this.visibleSeries.length];
System.arraycopy(this.visibleSeries, 0, result, 0,
this.visibleSeries.length);
return result;
@@ -221,7 +223,7 @@ public int[] getVisibleSeriesArray() {
*
* @since 1.0.13
*/
- public void setVisibleSeriesArray(int[] visibleSeries) {
+ public void setVisibleSeriesArray(@NonNegative int[] visibleSeries) {
this.visibleSeries = visibleSeries;
}
diff --git a/src/main/java/org/jfree/chart/renderer/category/CategoryStepRenderer.java b/src/main/java/org/jfree/chart/renderer/category/CategoryStepRenderer.java
index 325e0d020..87af4469a 100644
--- a/src/main/java/org/jfree/chart/renderer/category/CategoryStepRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/CategoryStepRenderer.java
@@ -51,6 +51,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
@@ -166,7 +168,7 @@ public void setStagger(boolean shouldStagger) {
* @return The legend item.
*/
@Override
- public LegendItem getLegendItem(int datasetIndex, int series) {
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series) {
CategoryPlot p = getPlot();
if (p == null) {
@@ -273,8 +275,8 @@ else if (orientation == PlotOrientation.HORIZONTAL) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row,
- int column, int pass) {
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row,
+ @NonNegative int column, int pass) {
// do nothing if item is not visible
if (!getItemVisible(row, column)) {
diff --git a/src/main/java/org/jfree/chart/renderer/category/GanttRenderer.java b/src/main/java/org/jfree/chart/renderer/category/GanttRenderer.java
index d0caa30d9..914f86776 100644
--- a/src/main/java/org/jfree/chart/renderer/category/GanttRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/GanttRenderer.java
@@ -55,6 +55,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
@@ -242,8 +244,8 @@ public void setEndPercent(double percent) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row,
- int column, int pass) {
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row,
+ @NonNegative int column, int pass) {
if (dataset instanceof GanttCategoryDataset) {
GanttCategoryDataset gcd = (GanttCategoryDataset) dataset;
@@ -277,8 +279,8 @@ protected void drawTasks(Graphics2D g2,
CategoryAxis domainAxis,
ValueAxis rangeAxis,
GanttCategoryDataset dataset,
- int row,
- int column) {
+ @NonNegative int row,
+ @NonNegative int column) {
int count = dataset.getSubIntervalCount(row, column);
if (count == 0) {
@@ -383,7 +385,8 @@ else if (orientation == PlotOrientation.VERTICAL) {
if (subinterval == count - 1) {
// submit the current data point as a crosshair candidate
- int datasetIndex = plot.indexOf(dataset);
+ @SuppressWarnings("index") // documentation bug: dataset is assumed to be associated with plot
+ @NonNegative int datasetIndex = plot.indexOf(dataset);
Comparable columnKey = dataset.getColumnKey(column);
Comparable rowKey = dataset.getRowKey(row);
double xx = domainAxis.getCategorySeriesMiddle(columnKey,
@@ -425,8 +428,8 @@ protected void drawTask(Graphics2D g2,
CategoryAxis domainAxis,
ValueAxis rangeAxis,
GanttCategoryDataset dataset,
- int row,
- int column) {
+ @NonNegative int row,
+ @NonNegative int column) {
PlotOrientation orientation = plot.getOrientation();
RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
@@ -533,7 +536,8 @@ else if (plot.getOrientation() == PlotOrientation.VERTICAL) {
}
// submit the current data point as a crosshair candidate
- int datasetIndex = plot.indexOf(dataset);
+ @SuppressWarnings("index") // documentation bug: dataset is assumed to be associated with plot
+ @NonNegative int datasetIndex = plot.indexOf(dataset);
Comparable columnKey = dataset.getColumnKey(column);
Comparable rowKey = dataset.getRowKey(row);
double xx = domainAxis.getCategorySeriesMiddle(columnKey, rowKey,
diff --git a/src/main/java/org/jfree/chart/renderer/category/GradientBarPainter.java b/src/main/java/org/jfree/chart/renderer/category/GradientBarPainter.java
index 981aa8b24..ea486f36f 100644
--- a/src/main/java/org/jfree/chart/renderer/category/GradientBarPainter.java
+++ b/src/main/java/org/jfree/chart/renderer/category/GradientBarPainter.java
@@ -42,6 +42,10 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
@@ -103,8 +107,8 @@ public GradientBarPainter(double g1, double g2, double g3) {
* bar.
*/
@Override
- public void paintBar(Graphics2D g2, BarRenderer renderer, int row,
- int column, RectangularShape bar, RectangleEdge base) {
+ public void paintBar(Graphics2D g2, BarRenderer renderer, @NonNegative int row,
+ @NonNegative int column, RectangularShape bar, RectangleEdge base) {
Paint itemPaint = renderer.getItemPaint(row, column);
@@ -205,8 +209,8 @@ else if (base == RectangleEdge.LEFT || base == RectangleEdge.RIGHT) {
* @param pegShadow peg the shadow to the base of the bar?
*/
@Override
- public void paintBarShadow(Graphics2D g2, BarRenderer renderer, int row,
- int column, RectangularShape bar, RectangleEdge base,
+ public void paintBarShadow(Graphics2D g2, BarRenderer renderer, @NonNegative int row,
+ @NonNegative int column, RectangularShape bar, RectangleEdge base,
boolean pegShadow) {
// handle a special case - if the bar colour has alpha == 0, it is
@@ -289,7 +293,7 @@ else if (base == RectangleEdge.RIGHT) {
*
* @return An array containing four subregions.
*/
- private Rectangle2D[] splitVerticalBar(RectangularShape bar, double a,
+ private Rectangle2D @ArrayLen(4) [] splitVerticalBar(RectangularShape bar, double a,
double b, double c) {
Rectangle2D[] result = new Rectangle2D[4];
double x0 = bar.getMinX();
@@ -318,7 +322,7 @@ private Rectangle2D[] splitVerticalBar(RectangularShape bar, double a,
*
* @return An array containing four subregions.
*/
- private Rectangle2D[] splitHorizontalBar(RectangularShape bar, double a,
+ private Rectangle2D @ArrayLen(4) [] splitHorizontalBar(RectangularShape bar, double a,
double b, double c) {
Rectangle2D[] result = new Rectangle2D[4];
double y0 = bar.getMinY();
diff --git a/src/main/java/org/jfree/chart/renderer/category/GroupedStackedBarRenderer.java b/src/main/java/org/jfree/chart/renderer/category/GroupedStackedBarRenderer.java
index bdb103e3d..5199b74a0 100644
--- a/src/main/java/org/jfree/chart/renderer/category/GroupedStackedBarRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/GroupedStackedBarRenderer.java
@@ -49,6 +49,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
@@ -137,7 +139,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
*/
@Override
protected void calculateBarWidth(CategoryPlot plot, Rectangle2D dataArea,
- int rendererIndex, CategoryItemRendererState state) {
+ @NonNegative int rendererIndex, CategoryItemRendererState state) {
// calculate the bar width
CategoryAxis xAxis = plot.getDomainAxisForDataset(rendererIndex);
@@ -196,7 +198,7 @@ else if (orientation == PlotOrientation.VERTICAL) {
protected double calculateBarW0(CategoryPlot plot,
PlotOrientation orientation, Rectangle2D dataArea,
CategoryAxis domainAxis, CategoryItemRendererState state,
- int row, int column) {
+ @NonNegative int row, @NonNegative int column) {
// calculate bar width...
double space;
if (orientation == PlotOrientation.HORIZONTAL) {
@@ -208,9 +210,10 @@ protected double calculateBarW0(CategoryPlot plot,
double barW0 = domainAxis.getCategoryStart(column, getColumnCount(),
dataArea, plot.getDomainAxisEdge());
int groupCount = this.seriesToGroupMap.getGroupCount();
+ @SuppressWarnings("index") // this renderer is assumed to be associated with the plot passed to this function. If that isn't true, this will fail. A bug?
+ CategoryDataset dataset = plot.getDataset(plot.getIndexOf(this));
int groupIndex = this.seriesToGroupMap.getGroupIndex(
- this.seriesToGroupMap.getGroup(plot.getDataset(
- plot.getIndexOf(this)).getRowKey(row)));
+ this.seriesToGroupMap.getGroup(dataset.getRowKey(row)));
int categoryCount = getColumnCount();
if (groupCount > 1) {
double groupGap = space * getItemMargin()
@@ -245,8 +248,8 @@ protected double calculateBarW0(CategoryPlot plot,
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row,
- int column, int pass) {
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row,
+ @NonNegative int column, int pass) {
// nothing is drawn for null values...
Number dataValue = dataset.getValue(row, column);
diff --git a/src/main/java/org/jfree/chart/renderer/category/IntervalBarRenderer.java b/src/main/java/org/jfree/chart/renderer/category/IntervalBarRenderer.java
index 2da70168b..4e2b52768 100644
--- a/src/main/java/org/jfree/chart/renderer/category/IntervalBarRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/IntervalBarRenderer.java
@@ -69,6 +69,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
@@ -137,7 +139,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
if (dataset instanceof IntervalCategoryDataset) {
@@ -166,8 +168,8 @@ public void drawItem(Graphics2D g2, CategoryItemRendererState state,
*/
protected void drawInterval(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, IntervalCategoryDataset dataset, int row,
- int column) {
+ ValueAxis rangeAxis, IntervalCategoryDataset dataset, @NonNegative int row,
+ @NonNegative int column) {
int visibleRow = state.getVisibleSeriesIndex(row);
if (visibleRow < 0) {
diff --git a/src/main/java/org/jfree/chart/renderer/category/LayeredBarRenderer.java b/src/main/java/org/jfree/chart/renderer/category/LayeredBarRenderer.java
index 80629edc5..ff887c358 100644
--- a/src/main/java/org/jfree/chart/renderer/category/LayeredBarRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/LayeredBarRenderer.java
@@ -54,6 +54,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
@@ -105,7 +107,7 @@ public LayeredBarRenderer() {
*
* @return The width for the series (1.0=100%, it is the maximum).
*/
- public double getSeriesBarWidth(int series) {
+ public double getSeriesBarWidth(@NonNegative int series) {
double result = Double.NaN;
Number n = (Number) this.seriesBarWidthList.get(series);
if (n != null) {
@@ -121,7 +123,7 @@ public double getSeriesBarWidth(int series) {
* @param width the width of the series bar in percentage (1.0=100%, it is
* the maximum).
*/
- public void setSeriesBarWidth(int series, double width) {
+ public void setSeriesBarWidth(@NonNegative int series, double width) {
this.seriesBarWidthList.set(series, new Double(width));
}
@@ -135,7 +137,7 @@ public void setSeriesBarWidth(int series, double width) {
*/
@Override
protected void calculateBarWidth(CategoryPlot plot, Rectangle2D dataArea,
- int rendererIndex, CategoryItemRendererState state) {
+ @NonNegative int rendererIndex, CategoryItemRendererState state) {
// calculate the bar width - this calculation differs from the
// BarRenderer calculation because the bars are layered on top of one
@@ -188,7 +190,7 @@ else if (orientation == PlotOrientation.VERTICAL) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset data, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset data, @NonNegative int row, @NonNegative int column,
int pass) {
PlotOrientation orientation = plot.getOrientation();
@@ -218,7 +220,7 @@ public void drawItem(Graphics2D g2, CategoryItemRendererState state,
protected void drawHorizontalItem(Graphics2D g2,
CategoryItemRendererState state, Rectangle2D dataArea,
CategoryPlot plot, CategoryAxis domainAxis, ValueAxis rangeAxis,
- CategoryDataset dataset, int row, int column) {
+ CategoryDataset dataset, @NonNegative int row, @NonNegative int column) {
// nothing is drawn for null values...
Number dataValue = dataset.getValue(row, column);
@@ -343,7 +345,7 @@ protected void drawHorizontalItem(Graphics2D g2,
protected void drawVerticalItem(Graphics2D g2,
CategoryItemRendererState state, Rectangle2D dataArea,
CategoryPlot plot, CategoryAxis domainAxis, ValueAxis rangeAxis,
- CategoryDataset dataset, int row, int column) {
+ CategoryDataset dataset, @NonNegative int row, @NonNegative int column) {
// nothing is drawn for null values...
Number dataValue = dataset.getValue(row, column);
diff --git a/src/main/java/org/jfree/chart/renderer/category/LevelRenderer.java b/src/main/java/org/jfree/chart/renderer/category/LevelRenderer.java
index 23ee9268b..b9c90e06d 100644
--- a/src/main/java/org/jfree/chart/renderer/category/LevelRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/LevelRenderer.java
@@ -51,6 +51,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
@@ -180,7 +182,7 @@ public void setMaximumItemWidth(double percent) {
*/
@Override
public CategoryItemRendererState initialise(Graphics2D g2,
- Rectangle2D dataArea, CategoryPlot plot, int rendererIndex,
+ Rectangle2D dataArea, CategoryPlot plot, @NonNegative int rendererIndex,
PlotRenderingInfo info) {
CategoryItemRendererState state = super.initialise(g2, dataArea, plot,
rendererIndex, info);
@@ -197,7 +199,7 @@ public CategoryItemRendererState initialise(Graphics2D g2,
* @param state the renderer state.
*/
protected void calculateItemWidth(CategoryPlot plot,
- Rectangle2D dataArea, int rendererIndex,
+ Rectangle2D dataArea, @NonNegative int rendererIndex,
CategoryItemRendererState state) {
CategoryAxis domainAxis = getDomainAxis(plot, rendererIndex);
@@ -250,7 +252,7 @@ protected void calculateItemWidth(CategoryPlot plot,
*/
protected double calculateBarW0(CategoryPlot plot,
PlotOrientation orientation, Rectangle2D dataArea,
- CategoryAxis domainAxis, CategoryItemRendererState state, int row,
+ CategoryAxis domainAxis, CategoryItemRendererState state, @NonNegative int row,
int column) {
// calculate bar width...
double space;
@@ -298,7 +300,7 @@ protected double calculateBarW0(CategoryPlot plot,
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
// nothing is drawn if the row index is not included in the list with
@@ -359,7 +361,8 @@ public void drawItem(Graphics2D g2, CategoryItemRendererState state,
}
// submit the current data point as a crosshair candidate
- int datasetIndex = plot.indexOf(dataset);
+ @SuppressWarnings("index") // documentation bug: dataset is assumed to be associated with plot
+ @NonNegative int datasetIndex = plot.indexOf(dataset);
updateCrosshairValues(state.getCrosshairState(),
dataset.getRowKey(row), dataset.getColumnKey(column), value,
datasetIndex, barW0, barL, orientation);
@@ -383,7 +386,7 @@ public void drawItem(Graphics2D g2, CategoryItemRendererState state,
* @return The width of one series.
*/
protected double calculateSeriesWidth(double space, CategoryAxis axis,
- int categories, int series) {
+ int categories, @NonNegative int series) {
double factor = 1.0 - getItemMargin() - axis.getLowerMargin()
- axis.getUpperMargin();
if (categories > 1) {
diff --git a/src/main/java/org/jfree/chart/renderer/category/LineAndShapeRenderer.java b/src/main/java/org/jfree/chart/renderer/category/LineAndShapeRenderer.java
index aab8a6164..69da120de 100644
--- a/src/main/java/org/jfree/chart/renderer/category/LineAndShapeRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/LineAndShapeRenderer.java
@@ -94,6 +94,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
@@ -230,7 +232,7 @@ public LineAndShapeRenderer(boolean lines, boolean shapes) {
*
* @return A boolean.
*/
- public boolean getItemLineVisible(int series, int item) {
+ public boolean getItemLineVisible(@NonNegative int series, @NonNegative int item) {
Boolean flag = getSeriesLinesVisible(series);
if (flag != null) {
return flag;
@@ -248,7 +250,7 @@ public boolean getItemLineVisible(int series, int item) {
*
* @see #setSeriesLinesVisible(int, Boolean)
*/
- public Boolean getSeriesLinesVisible(int series) {
+ public Boolean getSeriesLinesVisible(@NonNegative int series) {
return this.seriesLinesVisible.getBoolean(series);
}
@@ -261,7 +263,7 @@ public Boolean getSeriesLinesVisible(int series) {
*
* @see #getSeriesLinesVisible(int)
*/
- public void setSeriesLinesVisible(int series, Boolean flag) {
+ public void setSeriesLinesVisible(@NonNegative int series, Boolean flag) {
this.seriesLinesVisible.setBoolean(series, flag);
fireChangeEvent();
}
@@ -275,7 +277,7 @@ public void setSeriesLinesVisible(int series, Boolean flag) {
*
* @see #getSeriesLinesVisible(int)
*/
- public void setSeriesLinesVisible(int series, boolean visible) {
+ public void setSeriesLinesVisible(@NonNegative int series, boolean visible) {
setSeriesLinesVisible(series, Boolean.valueOf(visible));
}
@@ -314,7 +316,7 @@ public void setDefaultLinesVisible(boolean flag) {
*
* @return A boolean.
*/
- public boolean getItemShapeVisible(int series, int item) {
+ public boolean getItemShapeVisible(@NonNegative int series, @NonNegative int item) {
Boolean flag = getSeriesShapesVisible(series);
if (flag != null) {
return flag;
@@ -332,7 +334,7 @@ public boolean getItemShapeVisible(int series, int item) {
*
* @see #setSeriesShapesVisible(int, Boolean)
*/
- public Boolean getSeriesShapesVisible(int series) {
+ public Boolean getSeriesShapesVisible(@NonNegative int series) {
return this.seriesShapesVisible.getBoolean(series);
}
@@ -345,7 +347,7 @@ public Boolean getSeriesShapesVisible(int series) {
*
* @see #getSeriesShapesVisible(int)
*/
- public void setSeriesShapesVisible(int series, boolean visible) {
+ public void setSeriesShapesVisible(@NonNegative int series, boolean visible) {
setSeriesShapesVisible(series, Boolean.valueOf(visible));
}
@@ -358,7 +360,7 @@ public void setSeriesShapesVisible(int series, boolean visible) {
*
* @see #getSeriesShapesVisible(int)
*/
- public void setSeriesShapesVisible(int series, Boolean flag) {
+ public void setSeriesShapesVisible(@NonNegative int series, Boolean flag) {
this.seriesShapesVisible.setBoolean(series, flag);
fireChangeEvent();
}
@@ -455,7 +457,7 @@ public void setUseOutlinePaint(boolean use) {
*
* @return A boolean.
*/
- public boolean getItemShapeFilled(int series, int item) {
+ public boolean getItemShapeFilled(@NonNegative int series, @NonNegative int item) {
return getSeriesShapesFilled(series);
}
@@ -467,7 +469,7 @@ public boolean getItemShapeFilled(int series, int item) {
*
* @return A boolean.
*/
- public boolean getSeriesShapesFilled(int series) {
+ public boolean getSeriesShapesFilled(@NonNegative int series) {
Boolean flag = this.seriesShapesFilled.getBoolean(series);
if (flag != null) {
return flag;
@@ -484,7 +486,7 @@ public boolean getSeriesShapesFilled(int series) {
*
* @see #getSeriesShapesFilled(int)
*/
- public void setSeriesShapesFilled(int series, Boolean filled) {
+ public void setSeriesShapesFilled(@NonNegative int series, Boolean filled) {
this.seriesShapesFilled.setBoolean(series, filled);
fireChangeEvent();
}
@@ -498,7 +500,7 @@ public void setSeriesShapesFilled(int series, Boolean filled) {
*
* @see #getSeriesShapesFilled(int)
*/
- public void setSeriesShapesFilled(int series, boolean filled) {
+ public void setSeriesShapesFilled(@NonNegative int series, boolean filled) {
// delegate
setSeriesShapesFilled(series, Boolean.valueOf(filled));
}
@@ -630,7 +632,7 @@ public void setItemMargin(double margin) {
* @return The legend item.
*/
@Override
- public LegendItem getLegendItem(int datasetIndex, int series) {
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series) {
CategoryPlot cp = getPlot();
if (cp == null) {
@@ -688,7 +690,7 @@ urlText, shapeVisible, shape, getItemShapeFilled(series, 0),
* @return The pass count ({@code 2} for this renderer).
*/
@Override
- public int getPassCount() {
+ public @NonNegative int getPassCount() {
return 2;
}
@@ -709,7 +711,7 @@ public int getPassCount() {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
// do nothing if item is not visible
@@ -832,7 +834,8 @@ else if (orientation == PlotOrientation.VERTICAL) {
}
// submit the current data point as a crosshair candidate
- int datasetIndex = plot.indexOf(dataset);
+ @SuppressWarnings("index") // documentation bug: dataset is assumed to be associated with plot
+ @NonNegative int datasetIndex = plot.indexOf(dataset);
updateCrosshairValues(state.getCrosshairState(),
dataset.getRowKey(row), dataset.getColumnKey(column),
value, datasetIndex, x1, y1, orientation);
diff --git a/src/main/java/org/jfree/chart/renderer/category/MinMaxCategoryRenderer.java b/src/main/java/org/jfree/chart/renderer/category/MinMaxCategoryRenderer.java
index c8b8a507d..8fe8ab1f9 100644
--- a/src/main/java/org/jfree/chart/renderer/category/MinMaxCategoryRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/MinMaxCategoryRenderer.java
@@ -60,6 +60,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
@@ -323,7 +325,7 @@ public void setMinIcon(Icon icon) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
// first check the number we are plotting...
diff --git a/src/main/java/org/jfree/chart/renderer/category/ScatterRenderer.java b/src/main/java/org/jfree/chart/renderer/category/ScatterRenderer.java
index c2b56a35d..7f490e359 100644
--- a/src/main/java/org/jfree/chart/renderer/category/ScatterRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/ScatterRenderer.java
@@ -45,6 +45,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
@@ -264,7 +266,7 @@ public void setUseOutlinePaint(boolean use) {
* @param item the item index (zero-based).
* @return A boolean.
*/
- public boolean getItemShapeFilled(int series, int item) {
+ public boolean getItemShapeFilled(@NonNegative int series, @NonNegative int item) {
return getSeriesShapesFilled(series);
}
@@ -275,7 +277,7 @@ public boolean getItemShapeFilled(int series, int item) {
* @param series the series index (zero-based).
* @return A boolean.
*/
- public boolean getSeriesShapesFilled(int series) {
+ public boolean getSeriesShapesFilled(@NonNegative int series) {
Boolean flag = this.seriesShapesFilled.getBoolean(series);
if (flag != null) {
return flag.booleanValue();
@@ -293,7 +295,7 @@ public boolean getSeriesShapesFilled(int series) {
* @param series the series index (zero-based).
* @param filled the flag.
*/
- public void setSeriesShapesFilled(int series, Boolean filled) {
+ public void setSeriesShapesFilled(@NonNegative int series, Boolean filled) {
this.seriesShapesFilled.setBoolean(series, filled);
fireChangeEvent();
}
@@ -305,7 +307,7 @@ public void setSeriesShapesFilled(int series, Boolean filled) {
* @param series the series index (zero-based).
* @param filled the flag.
*/
- public void setSeriesShapesFilled(int series, boolean filled) {
+ public void setSeriesShapesFilled(@NonNegative int series, boolean filled) {
this.seriesShapesFilled.setBoolean(series, Boolean.valueOf(filled));
fireChangeEvent();
}
@@ -385,7 +387,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
// do nothing if item is not visible
@@ -462,7 +464,7 @@ else if (orientation == PlotOrientation.VERTICAL) {
* @return The legend item.
*/
@Override
- public LegendItem getLegendItem(int datasetIndex, int series) {
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series) {
CategoryPlot cp = getPlot();
if (cp == null) {
diff --git a/src/main/java/org/jfree/chart/renderer/category/StackedAreaRenderer.java b/src/main/java/org/jfree/chart/renderer/category/StackedAreaRenderer.java
index e2037163a..07845967d 100644
--- a/src/main/java/org/jfree/chart/renderer/category/StackedAreaRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/StackedAreaRenderer.java
@@ -68,6 +68,10 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
@@ -158,7 +162,7 @@ public void setRenderAsPercentages(boolean asPercentages) {
* @return The number of passes required by the renderer.
*/
@Override
- public int getPassCount() {
+ public @NonNegative int getPassCount() {
return 2;
}
@@ -200,7 +204,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
if (!isSeriesVisible(row)) {
@@ -251,7 +255,8 @@ public void drawItem(Graphics2D g2, CategoryItemRendererState state,
double xx0 = domainAxis.getCategoryStart(column, getColumnCount(),
dataArea, plot.getDomainAxisEdge());
- int itemCount = dataset.getColumnCount();
+ @SuppressWarnings("index") // Possible bug. I don't see anything that implies that there is an item in the dataset, but I might I have missed it
+ @Positive int itemCount = dataset.getColumnCount();
double y2 = 0.0;
n = dataset.getValue(row, Math.min(column + 1, itemCount - 1));
if (n != null) {
@@ -412,8 +417,8 @@ else if (pass == 1) {
* for all series values up to but excluding {@code series}
* for {@code index}.
*/
- protected double[] getStackValues(CategoryDataset dataset,
- int series, int index, int[] validRows) {
+ protected double @ArrayLen(2) [] getStackValues(CategoryDataset dataset,
+ int series, @NonNegative int index, @NonNegative int[] validRows) {
double[] result = new double[2];
double total = 0.0;
if (this.renderAsPercentages) {
@@ -452,7 +457,7 @@ protected double[] getStackValues(CategoryDataset dataset,
*
* @return A pair of average stack values.
*/
- private double[] averageStackValues(double[] stack1, double[] stack2) {
+ private double @ArrayLen(2) [] averageStackValues(double @MinLen(2) [] stack1, double @MinLen(2) [] stack2) {
double[] result = new double[2];
result[0] = (stack1[0] + stack2[0]) / 2.0;
result[1] = (stack1[1] + stack2[1]) / 2.0;
@@ -469,7 +474,7 @@ private double[] averageStackValues(double[] stack1, double[] stack2) {
*
* @return A pair of average stack values.
*/
- private double[] adjustedStackValues(double[] stack1, double[] stack2) {
+ private double @ArrayLen(2) [] adjustedStackValues(double @MinLen(2) [] stack1, double @MinLen(2) [] stack2) {
double[] result = new double[2];
if (stack1[0] == 0.0 || stack2[0] == 0.0) {
result[0] = 0.0;
diff --git a/src/main/java/org/jfree/chart/renderer/category/StackedBarRenderer.java b/src/main/java/org/jfree/chart/renderer/category/StackedBarRenderer.java
index 979795ddb..89676ba8c 100644
--- a/src/main/java/org/jfree/chart/renderer/category/StackedBarRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/StackedBarRenderer.java
@@ -94,6 +94,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
@@ -200,7 +202,7 @@ public void setRenderAsPercentages(boolean asPercentages) {
* @return The number of passes required by the renderer.
*/
@Override
- public int getPassCount() {
+ public @NonNegative int getPassCount() {
return 3;
}
@@ -235,7 +237,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
*/
@Override
protected void calculateBarWidth(CategoryPlot plot, Rectangle2D dataArea,
- int rendererIndex, CategoryItemRendererState state) {
+ @NonNegative int rendererIndex, CategoryItemRendererState state) {
// calculate the bar width
CategoryAxis xAxis = plot.getDomainAxisForDataset(rendererIndex);
@@ -286,8 +288,8 @@ else if (orientation == PlotOrientation.VERTICAL) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row,
- int column, int pass) {
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row,
+ @NonNegative int column, int pass) {
if (!isSeriesVisible(row)) {
return;
diff --git a/src/main/java/org/jfree/chart/renderer/category/StandardBarPainter.java b/src/main/java/org/jfree/chart/renderer/category/StandardBarPainter.java
index 3ebc7cbb1..d8e101286 100644
--- a/src/main/java/org/jfree/chart/renderer/category/StandardBarPainter.java
+++ b/src/main/java/org/jfree/chart/renderer/category/StandardBarPainter.java
@@ -41,6 +41,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
@@ -81,8 +83,8 @@ public StandardBarPainter() {
* bar.
*/
@Override
- public void paintBar(Graphics2D g2, BarRenderer renderer, int row,
- int column, RectangularShape bar, RectangleEdge base) {
+ public void paintBar(Graphics2D g2, BarRenderer renderer, @NonNegative int row,
+ @NonNegative int column, RectangularShape bar, RectangleEdge base) {
Paint itemPaint = renderer.getItemPaint(row, column);
GradientPaintTransformer t = renderer.getGradientPaintTransformer();
@@ -119,8 +121,8 @@ public void paintBar(Graphics2D g2, BarRenderer renderer, int row,
* @param pegShadow peg the shadow to the base of the bar?
*/
@Override
- public void paintBarShadow(Graphics2D g2, BarRenderer renderer, int row,
- int column, RectangularShape bar, RectangleEdge base,
+ public void paintBarShadow(Graphics2D g2, BarRenderer renderer, @NonNegative int row,
+ @NonNegative int column, RectangularShape bar, RectangleEdge base,
boolean pegShadow) {
// handle a special case - if the bar colour has alpha == 0, it is
diff --git a/src/main/java/org/jfree/chart/renderer/category/StatisticalBarRenderer.java b/src/main/java/org/jfree/chart/renderer/category/StatisticalBarRenderer.java
index 70e9dfce8..1ffb342ba 100644
--- a/src/main/java/org/jfree/chart/renderer/category/StatisticalBarRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/StatisticalBarRenderer.java
@@ -64,6 +64,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.GradientPaint;
@@ -219,7 +221,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset data, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset data, @NonNegative int row, @NonNegative int column,
int pass) {
int visibleRow = state.getVisibleSeriesIndex(row);
@@ -265,9 +267,9 @@ protected void drawHorizontalItem(Graphics2D g2,
CategoryAxis domainAxis,
ValueAxis rangeAxis,
StatisticalCategoryDataset dataset,
- int visibleRow,
- int row,
- int column) {
+ @NonNegative int visibleRow,
+ @NonNegative int row,
+ @NonNegative int column) {
// BAR Y
double rectY = calculateBarW0(plot, PlotOrientation.HORIZONTAL,
@@ -412,9 +414,9 @@ protected void drawVerticalItem(Graphics2D g2,
CategoryAxis domainAxis,
ValueAxis rangeAxis,
StatisticalCategoryDataset dataset,
- int visibleRow,
- int row,
- int column) {
+ @NonNegative int visibleRow,
+ @NonNegative int row,
+ @NonNegative int column) {
// BAR X
double rectX = calculateBarW0(plot, PlotOrientation.VERTICAL, dataArea,
diff --git a/src/main/java/org/jfree/chart/renderer/category/StatisticalLineAndShapeRenderer.java b/src/main/java/org/jfree/chart/renderer/category/StatisticalLineAndShapeRenderer.java
index 298fb1144..1510d3693 100644
--- a/src/main/java/org/jfree/chart/renderer/category/StatisticalLineAndShapeRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/StatisticalLineAndShapeRenderer.java
@@ -58,6 +58,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
@@ -221,7 +223,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
// do nothing if item is not visible
diff --git a/src/main/java/org/jfree/chart/renderer/category/WaterfallBarRenderer.java b/src/main/java/org/jfree/chart/renderer/category/WaterfallBarRenderer.java
index 5accf8a9b..76f45d1d2 100644
--- a/src/main/java/org/jfree/chart/renderer/category/WaterfallBarRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/category/WaterfallBarRenderer.java
@@ -60,6 +60,8 @@
package org.jfree.chart.renderer.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
@@ -311,7 +313,7 @@ public Range findRangeBounds(CategoryDataset dataset) {
@Override
public void drawItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
- ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
+ ValueAxis rangeAxis, CategoryDataset dataset, @NonNegative int row, @NonNegative int column,
int pass) {
double previous = state.getSeriesRunningTotal();
diff --git a/src/main/java/org/jfree/chart/renderer/xy/AbstractXYItemRenderer.java b/src/main/java/org/jfree/chart/renderer/xy/AbstractXYItemRenderer.java
index a3e66fd05..d78986bcc 100644
--- a/src/main/java/org/jfree/chart/renderer/xy/AbstractXYItemRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/xy/AbstractXYItemRenderer.java
@@ -129,6 +129,11 @@
package org.jfree.chart.renderer.xy;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Font;
@@ -264,7 +269,7 @@ protected AbstractXYItemRenderer() {
* @return The pass count.
*/
@Override
- public int getPassCount() {
+ public @NonNegative int getPassCount() {
return 1;
}
@@ -324,7 +329,7 @@ public XYItemRendererState initialise(Graphics2D g2, Rectangle2D dataArea,
* @since 1.0.20
*/
protected void beginElementGroup(Graphics2D g2, Comparable seriesKey,
- int itemIndex) {
+ @NonNegative int itemIndex) {
beginElementGroup(g2, new XYItemKey(seriesKey, itemIndex));
}
@@ -342,7 +347,7 @@ protected void beginElementGroup(Graphics2D g2, Comparable seriesKey,
* @return The generator (possibly {@code null}).
*/
@Override
- public XYItemLabelGenerator getItemLabelGenerator(int series, int item) {
+ public XYItemLabelGenerator getItemLabelGenerator(@NonNegative int series, @NonNegative int item) {
// otherwise look up the generator table
XYItemLabelGenerator generator
@@ -361,7 +366,7 @@ public XYItemLabelGenerator getItemLabelGenerator(int series, int item) {
* @return The generator (possibly {@code null}).
*/
@Override
- public XYItemLabelGenerator getSeriesItemLabelGenerator(int series) {
+ public XYItemLabelGenerator getSeriesItemLabelGenerator(@NonNegative int series) {
return this.itemLabelGeneratorMap.get(series);
}
@@ -373,7 +378,7 @@ public XYItemLabelGenerator getSeriesItemLabelGenerator(int series) {
* @param generator the generator ({@code null} permitted).
*/
@Override
- public void setSeriesItemLabelGenerator(int series,
+ public void setSeriesItemLabelGenerator(@NonNegative int series,
XYItemLabelGenerator generator) {
this.itemLabelGeneratorMap.put(series, generator);
fireChangeEvent();
@@ -414,7 +419,7 @@ public void setDefaultItemLabelGenerator(XYItemLabelGenerator generator) {
* @return The generator (possibly {@code null}).
*/
@Override
- public XYToolTipGenerator getToolTipGenerator(int series, int item) {
+ public XYToolTipGenerator getToolTipGenerator(@NonNegative int series, @NonNegative int item) {
// otherwise look up the generator table
XYToolTipGenerator generator
@@ -433,7 +438,7 @@ public XYToolTipGenerator getToolTipGenerator(int series, int item) {
* @return The generator (possibly {@code null}).
*/
@Override
- public XYToolTipGenerator getSeriesToolTipGenerator(int series) {
+ public XYToolTipGenerator getSeriesToolTipGenerator(@NonNegative int series) {
return this.toolTipGeneratorMap.get(series);
}
@@ -445,7 +450,7 @@ public XYToolTipGenerator getSeriesToolTipGenerator(int series) {
* @param generator the generator ({@code null} permitted).
*/
@Override
- public void setSeriesToolTipGenerator(int series,
+ public void setSeriesToolTipGenerator(@NonNegative int series,
XYToolTipGenerator generator) {
this.toolTipGeneratorMap.put(series, generator);
fireChangeEvent();
@@ -805,7 +810,8 @@ public LegendItemCollection getLegendItems() {
return new LegendItemCollection();
}
LegendItemCollection result = new LegendItemCollection();
- int index = this.plot.getIndexOf(this);
+ @SuppressWarnings("index") // guaranteed index: this is guaranteed to be a renderer for this.plot, so indexOf will return nonnegative
+ @NonNegative int index = this.plot.getIndexOf(this);
XYDataset dataset = this.plot.getDataset(index);
if (dataset != null) {
int seriesCount = dataset.getSeriesCount();
@@ -832,7 +838,7 @@ public LegendItemCollection getLegendItems() {
* @return A legend item for the series.
*/
@Override
- public LegendItem getLegendItem(int datasetIndex, int series) {
+ public LegendItem getLegendItem(@NonNegative int datasetIndex, @NonNegative int series) {
XYPlot xyplot = getPlot();
if (xyplot == null) {
return null;
@@ -1578,7 +1584,7 @@ public DrawingSupplier getDrawingSupplier() {
* @since 1.0.20
*/
protected void updateCrosshairValues(CrosshairState crosshairState,
- double x, double y, int datasetIndex,
+ double x, double y, @NonNegative int datasetIndex,
double transX, double transY, PlotOrientation orientation) {
Args.nullNotPermitted(orientation, "orientation");
@@ -1619,7 +1625,7 @@ protected void updateCrosshairValues(CrosshairState crosshairState,
* label position).
*/
protected void drawItemLabel(Graphics2D g2, PlotOrientation orientation,
- XYDataset dataset, int series, int item, double x, double y,
+ XYDataset dataset, @NonNegative int series, @IndexFor("#3.getSeries(#4)") int item, double x, double y,
boolean negative) {
XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
@@ -1676,7 +1682,8 @@ else if (layer.equals(Layer.BACKGROUND)) {
// should not get here
throw new RuntimeException("Unknown layer.");
}
- int index = this.plot.getIndexOf(this);
+ @SuppressWarnings("index") // guaranteed index: this is a renderer of this.plot by definition, so indexOf will return nonnegative
+ @NonNegative int index = this.plot.getIndexOf(this);
for (XYAnnotation annotation : toDraw) {
annotation.draw(g2, this.plot, dataArea, domainAxis, rangeAxis,
index, info);
@@ -1702,7 +1709,7 @@ else if (layer.equals(Layer.BACKGROUND)) {
* {@code hotspot} is {@code null}).
*/
protected void addEntity(EntityCollection entities, Shape hotspot,
- XYDataset dataset, int series, int item, double entityX,
+ XYDataset dataset, @NonNegative int series, @IndexFor("#3.getSeries(#4)") int item, double entityX,
double entityY) {
if (!getItemCreateEntity(series, item)) {
diff --git a/src/main/java/org/jfree/chart/renderer/xy/CandlestickRenderer.java b/src/main/java/org/jfree/chart/renderer/xy/CandlestickRenderer.java
index 38db9cd4b..5cd2b593b 100644
--- a/src/main/java/org/jfree/chart/renderer/xy/CandlestickRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/xy/CandlestickRenderer.java
@@ -88,6 +88,10 @@
package org.jfree.chart.renderer.xy;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
@@ -646,7 +650,7 @@ public XYItemRendererState initialise(Graphics2D g2, Rectangle2D dataArea,
public void drawItem(Graphics2D g2, XYItemRendererState state,
Rectangle2D dataArea, PlotRenderingInfo info, XYPlot plot,
ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset,
- int series, int item, CrosshairState crosshairState, int pass) {
+ @NonNegative int series, @IndexFor("#8.getSeries(#9)") int item, CrosshairState crosshairState, int pass) {
boolean horiz;
PlotOrientation orientation = plot.getOrientation();
@@ -667,12 +671,14 @@ else if (orientation == PlotOrientation.VERTICAL) {
}
OHLCDataset highLowData = (OHLCDataset) dataset;
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ @IndexFor("highLowData.getSeries(series)") int highLowItem = item;
- double x = highLowData.getXValue(series, item);
- double yHigh = highLowData.getHighValue(series, item);
- double yLow = highLowData.getLowValue(series, item);
- double yOpen = highLowData.getOpenValue(series, item);
- double yClose = highLowData.getCloseValue(series, item);
+ double x = highLowData.getXValue(series, highLowItem);
+ double yHigh = highLowData.getHighValue(series, highLowItem);
+ double yLow = highLowData.getLowValue(series, highLowItem);
+ double yOpen = highLowData.getOpenValue(series, highLowItem);
+ double yClose = highLowData.getCloseValue(series, highLowItem);
RectangleEdge domainEdge = plot.getDomainAxisEdge();
double xx = domainAxis.valueToJava2D(x, dataArea, domainEdge);
@@ -724,13 +730,15 @@ else if (orientation == PlotOrientation.VERTICAL) {
break;
case WIDTHMETHOD_INTERVALDATA:
- IntervalXYDataset intervalXYData
+ IntervalXYDataset intervalDataset
= (IntervalXYDataset) dataset;
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ @NonNegative @UpperBoundBottom int intervalXYItem = item;
double startPos = domainAxis.valueToJava2D(
- intervalXYData.getStartXValue(series, item),
+ intervalDataset.getStartXValue(series, intervalXYItem),
dataArea, plot.getDomainAxisEdge());
double endPos = domainAxis.valueToJava2D(
- intervalXYData.getEndXValue(series, item),
+ intervalDataset.getEndXValue(series, intervalXYItem),
dataArea, plot.getDomainAxisEdge());
xxWidth = Math.abs(endPos - startPos);
break;
@@ -753,7 +761,7 @@ else if (orientation == PlotOrientation.VERTICAL) {
g2.setStroke(s);
if (this.drawVolume) {
- int volume = (int) highLowData.getVolumeValue(series, item);
+ int volume = (int) highLowData.getVolumeValue(series, highLowItem);
double volumeHeight = volume / this.maxVolume;
double min, max;
diff --git a/src/main/java/org/jfree/chart/renderer/xy/ClusteredXYBarRenderer.java b/src/main/java/org/jfree/chart/renderer/xy/ClusteredXYBarRenderer.java
index 578d8fd5c..3891dfcdc 100644
--- a/src/main/java/org/jfree/chart/renderer/xy/ClusteredXYBarRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/xy/ClusteredXYBarRenderer.java
@@ -66,6 +66,8 @@
package org.jfree.chart.renderer.xy;
+import org.checkerframework.checker.index.qual.*;
+
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
@@ -136,7 +138,7 @@ public ClusteredXYBarRenderer(double margin,
* @return {@code 2}.
*/
@Override
- public int getPassCount() {
+ public @NonNegative int getPassCount() {
return 2;
}
@@ -225,19 +227,21 @@ protected Range findDomainBoundsWithOffset(IntervalXYDataset dataset) {
public void drawItem(Graphics2D g2, XYItemRendererState state,
Rectangle2D dataArea, PlotRenderingInfo info, XYPlot plot,
ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset,
- int series, int item, CrosshairState crosshairState, int pass) {
+ @NonNegative int series, @IndexFor("#8.getSeries(#9)") int item, CrosshairState crosshairState, int pass) {
IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ @IndexFor("intervalDataset.getSeries(series)") int intervalXYItem = item;
double y0;
double y1;
if (getUseYInterval()) {
- y0 = intervalDataset.getStartYValue(series, item);
- y1 = intervalDataset.getEndYValue(series, item);
+ y0 = intervalDataset.getStartYValue(series, intervalXYItem);
+ y1 = intervalDataset.getEndYValue(series, intervalXYItem);
}
else {
y0 = getBase();
- y1 = intervalDataset.getYValue(series, item);
+ y1 = intervalDataset.getYValue(series, intervalXYItem);
}
if (Double.isNaN(y0) || Double.isNaN(y1)) {
return;
@@ -249,10 +253,10 @@ public void drawItem(Graphics2D g2, XYItemRendererState state,
plot.getRangeAxisEdge());
RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
- double x0 = intervalDataset.getStartXValue(series, item);
+ double x0 = intervalDataset.getStartXValue(series, intervalXYItem);
double xx0 = domainAxis.valueToJava2D(x0, dataArea, xAxisLocation);
- double x1 = intervalDataset.getEndXValue(series, item);
+ double x1 = intervalDataset.getEndXValue(series, intervalXYItem);
double xx1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
double intervalW = xx1 - xx0; // this may be negative
diff --git a/src/main/java/org/jfree/chart/renderer/xy/CyclicXYItemRenderer.java b/src/main/java/org/jfree/chart/renderer/xy/CyclicXYItemRenderer.java
index 0be7fc1e8..db56b3887 100644
--- a/src/main/java/org/jfree/chart/renderer/xy/CyclicXYItemRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/xy/CyclicXYItemRenderer.java
@@ -47,6 +47,10 @@
package org.jfree.chart.renderer.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
@@ -61,6 +65,7 @@
import org.jfree.data.DomainOrder;
import org.jfree.data.general.DatasetChangeListener;
import org.jfree.data.general.DatasetGroup;
+import org.jfree.data.general.Series;
import org.jfree.data.xy.XYDataset;
/**
@@ -144,7 +149,7 @@ public CyclicXYItemRenderer(int type,
public void drawItem(Graphics2D g2, XYItemRendererState state,
Rectangle2D dataArea, PlotRenderingInfo info, XYPlot plot,
ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset,
- int series, int item, CrosshairState crosshairState, int pass) {
+ @NonNegative int series, @IndexFor("#8.getSeries(#9)") int item, CrosshairState crosshairState, int pass) {
if ((!getPlotLines()) || ((!(domainAxis instanceof CyclicNumberAxis))
&& (!(rangeAxis instanceof CyclicNumberAxis))) || (item <= 0)) {
@@ -220,12 +225,16 @@ public void drawItem(Graphics2D g2, XYItemRendererState state,
ny[1] = ycycleBound;
nx[1] = (x[1] - x[0]) * (ycycleBound - y[0])
/ (y[1] - y[0]) + x[0];
+
if (x.length == 3) {
- nx[3] = x[2]; ny[3] = y[2];
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/202: x's length is exactly one less than both nx and ny; x and y's lengths are the same
+ double dead = (nx[3] = x[2]);
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/202: x's length is exactly one less than both nx and ny; x and y's lengths are the same
+ double dead2 = (ny[3] = y[2]);
}
x = nx; y = ny;
}
- else if ((x.length == 3) && (y[1] != y[2]) && ((ycycleBound >= y[1])
+ else if ((x.length == 3) && (y.length == 3) && (y[1] != y[2]) && ((ycycleBound >= y[1])
&& (ycycleBound <= y[2])
|| (ycycleBound >= y[2]) && (ycycleBound <= y[1]))) {
double[] nx = new double[4];
@@ -240,12 +249,13 @@ else if ((x.length == 3) && (y[1] != y[2]) && ((ycycleBound >= y[1])
}
// If the line is not wrapping, then parent is OK
- if (x.length == 2) {
+ if (x.length == 2 && y.length == 2) {
super.drawItem(g2, state, dataArea, info, plot, domainAxis,
rangeAxis, dataset, series, item, crosshairState, pass);
return;
}
+ @SuppressWarnings("index") // x and y always have the same length here
OverwriteDataSet newset = new OverwriteDataSet(x, y, dataset);
if (cnax != null) {
@@ -264,11 +274,19 @@ else if ((x.length == 3) && (y[1] != y[2]) && ((ycycleBound >= y[1])
cnay.setBoundMappedToLastCycle(y[0] <= ycycleBound);
}
}
+
+ @SuppressWarnings("index") // newset is created from x and y, which are both arrays with at least two elements. So one is always a valid index to either
+ @LTLengthOf("newset.getSeries(series)") int one = 1;
super.drawItem(
g2, state, dataArea, info, plot, domainAxis, rangeAxis,
- newset, series, 1, crosshairState, pass
+ newset, series, one, crosshairState, pass
);
+ if (x.length < 3 || y.length < 3) {
+ // dead code, necessary for typechecking. x and y have correlated lengths
+ return;
+ }
+
if (cnax != null) {
if (xcycleBound == x[1]) {
cnax.setBoundMappedToLastCycle(x[2] <= xcycleBound);
@@ -285,10 +303,14 @@ else if ((x.length == 3) && (y[1] != y[2]) && ((ycycleBound >= y[1])
cnay.setBoundMappedToLastCycle(y[1] <= ycycleBound);
}
}
+
+ @SuppressWarnings("index") // newset is created from x and y, which are both arrays with at least two elements. But, if x and y were of length two we already returned. So, two is a valid index into newset.
+ @LTLengthOf("newset.getSeries(series)") int two = 2;
+
super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis,
- newset, series, 2, crosshairState, pass);
+ newset, series, two, crosshairState, pass);
- if (x.length == 4) {
+ if (x.length == 4 && y.length == 4) {
if (cnax != null) {
if (xcycleBound == x[2]) {
cnax.setBoundMappedToLastCycle(x[3] <= xcycleBound);
@@ -305,8 +327,12 @@ else if ((x.length == 3) && (y[1] != y[2]) && ((ycycleBound >= y[1])
cnay.setBoundMappedToLastCycle(y[2] <= ycycleBound);
}
}
+
+ @SuppressWarnings("index") // newset is created from x and y, which are both arrays with exactly four elements.
+ @LTLengthOf("newset.getSeries(series)") int three = 3;
+
super.drawItem(g2, state, dataArea, info, plot, domainAxis,
- rangeAxis, newset, series, 3, crosshairState, pass);
+ rangeAxis, newset, series, three, crosshairState, pass);
}
if (cnax != null) {
@@ -335,7 +361,7 @@ protected static class OverwriteDataSet implements XYDataset {
* @param y the y values.
* @param delegateSet the dataset.
*/
- public OverwriteDataSet(double [] x, double[] y,
+ public OverwriteDataSet(double @SameLen("#2") [] x, double @SameLen("#1") [] y,
XYDataset delegateSet) {
this.delegateSet = delegateSet;
this.x = new Double[x.length]; this.y = new Double[y.length];
@@ -363,7 +389,8 @@ public DomainOrder getDomainOrder() {
* @return The item count.
*/
@Override
- public int getItemCount(int series) {
+ @SuppressWarnings("index") // SameLen to a method with any argument https://github.com/kelloggm/checker-framework/issues/209
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
return this.x.length;
}
@@ -376,7 +403,8 @@ public int getItemCount(int series) {
* @return The x-value.
*/
@Override
- public Number getX(int series, int item) {
+ @SuppressWarnings("index") // SameLen to a method with any argument https://github.com/kelloggm/checker-framework/issues/209
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return this.x[item];
}
@@ -390,7 +418,7 @@ public Number getX(int series, int item) {
* @return The x-value.
*/
@Override
- public double getXValue(int series, int item) {
+ public double getXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number xx = getX(series, item);
if (xx != null) {
@@ -408,7 +436,8 @@ public double getXValue(int series, int item) {
* @return The y-value.
*/
@Override
- public Number getY(int series, int item) {
+ @SuppressWarnings("index") // SameLen to a method with any argument https://github.com/kelloggm/checker-framework/issues/209
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return this.y[item];
}
@@ -422,7 +451,7 @@ public Number getY(int series, int item) {
* @return The y-value.
*/
@Override
- public double getYValue(int series, int item) {
+ public double getYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number yy = getY(series, item);
if (yy != null) {
@@ -437,7 +466,7 @@ public double getYValue(int series, int item) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.delegateSet.getSeriesCount();
}
@@ -449,7 +478,7 @@ public int getSeriesCount() {
* @return The series name.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
return this.delegateSet.getSeriesKey(series);
}
@@ -461,7 +490,7 @@ public Comparable getSeriesKey(int series) {
* @return The index.
*/
@Override
- public int indexOf(Comparable seriesName) {
+ public @GTENegativeOne int indexOf(Comparable seriesName) {
return this.delegateSet.indexOf(seriesName);
}
@@ -506,6 +535,14 @@ public void setGroup(DatasetGroup group) {
// unused in parent
}
+ /**
+ * A ghost method. Do not call.
+ */
+ @Override
+ public Series getSeries(@NonNegative int series) {
+ return null;
+ }
+
}
}
diff --git a/src/main/java/org/jfree/chart/renderer/xy/DeviationRenderer.java b/src/main/java/org/jfree/chart/renderer/xy/DeviationRenderer.java
index 606de1b7c..cb9d837f3 100644
--- a/src/main/java/org/jfree/chart/renderer/xy/DeviationRenderer.java
+++ b/src/main/java/org/jfree/chart/renderer/xy/DeviationRenderer.java
@@ -45,6 +45,12 @@
package org.jfree.chart.renderer.xy;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
@@ -88,13 +94,13 @@ public static class State extends XYLineAndShapeRenderer.State {
* A list of coordinates for the upper y-values in the current series
* (after translation into Java2D space).
*/
- public List upperCoordinates;
+ public List
@@ -46,7 +50,7 @@ public ObjectList() {
*
* @param initialCapacity the initial capacity.
*/
- public ObjectList(int initialCapacity) {
+ public ObjectList(@NonNegative int initialCapacity) {
super(initialCapacity);
}
@@ -64,7 +68,7 @@ public ObjectList(int initialCapacity) {
* @return The object or {@code null}.
*/
@Override
- public Object get(int index) {
+ public Object get(@NonNegative int index) {
return super.get(index);
}
@@ -75,7 +79,7 @@ public Object get(int index) {
* @param object the object ({@code null} permitted).
*/
@Override
- public void set(int index, Object object) {
+ public void set(@NonNegative int index, Object object) {
super.set(index, object);
}
@@ -87,7 +91,7 @@ public void set(int index, Object object) {
* @return The index or -1.
*/
@Override
- public int indexOf(Object object) {
+ public @GTENegativeOne int indexOf(Object object) {
return super.indexOf(object);
}
diff --git a/src/main/java/org/jfree/chart/util/PaintAlpha.java b/src/main/java/org/jfree/chart/util/PaintAlpha.java
index 2348aa118..56497a7e3 100644
--- a/src/main/java/org/jfree/chart/util/PaintAlpha.java
+++ b/src/main/java/org/jfree/chart/util/PaintAlpha.java
@@ -43,6 +43,9 @@
package org.jfree.chart.util;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.LinearGradientPaint;
@@ -250,7 +253,10 @@ private static TexturePaint darkerTexturePaint(TexturePaint paint) {
final int wid = ras.getWidth();
- /**/ int[] pix = new int[wid * img.getSampleModel().getNumBands()];
+ @SuppressWarnings("index") // wid is NN, as is img.getSampleModel().getNumBands(). Both require JDK annotations on classes in java.awt.image
+ @NonNegative int pixLength = wid * img.getSampleModel().getNumBands();
+
+ /**/ int[] pix = new int[pixLength];
/* (pix-buffer is large enough for all pixels of one row) */
/**
@@ -281,7 +287,7 @@ private static TexturePaint darkerTexturePaint(TexturePaint paint) {
pix = ras.getPixels(miX, y, wid, 1, pix);
for (int p = 0; p < pix.length; p++) {
- nco = img.getColorModel().getComponents(pix[p], nco, 0);
+ nco = img.getColorModel().getComponents(pix[p], nco, 0);
nco[0] *= FACTOR; // Red
nco[1] *= FACTOR; // Green
nco[2] *= FACTOR; // Blue. Now map computed colour to
@@ -312,11 +318,16 @@ private static TexturePaint darkerTexturePaint(TexturePaint paint) {
pix = ras.getPixels(miX, y, wid, 1, pix);
- for (int p = 0; p < pix.length;) {
- pix[p] = (int)(pix[p++] * FACTOR); // Red
- pix[p] = (int)(pix[p++] * FACTOR); // Green
- pix[p] = (int)(pix[p++] * FACTOR); // Blue
- /* Ignore alpha-channel -> */p++;
+ for (int p = 0; p < pix.length; p++) {
+ switch(p % 4) {
+ case 0: // Red
+ case 1: // Green
+ case 2: // Blue
+ pix[p] = (int)(pix[p] * FACTOR);
+ break;
+ case 3:
+ /* Ignore alpha-channel -> */continue;
+ }
}
/**/ ras.setPixels(miX, y, wid, 1, pix);
}
diff --git a/src/main/java/org/jfree/chart/util/PaintList.java b/src/main/java/org/jfree/chart/util/PaintList.java
index f3f02994c..51a710244 100644
--- a/src/main/java/org/jfree/chart/util/PaintList.java
+++ b/src/main/java/org/jfree/chart/util/PaintList.java
@@ -28,6 +28,8 @@
package org.jfree.chart.util;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Paint;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -54,7 +56,7 @@ public PaintList() {
*
* @return The object.
*/
- public Paint getPaint(int index) {
+ public Paint getPaint(@NonNegative int index) {
return (Paint) get(index);
}
@@ -64,7 +66,7 @@ public Paint getPaint(int index) {
* @param index the index (zero-based).
* @param paint the {@link Paint}.
*/
- public void setPaint(int index, Paint paint) {
+ public void setPaint(@NonNegative int index, Paint paint) {
set(index, paint);
}
@@ -139,6 +141,7 @@ private void writeObject(ObjectOutputStream stream) throws IOException {
* @throws IOException if there is an I/O error.
* @throws ClassNotFoundException if there is a classpath problem.
*/
+ @SuppressWarnings("index") // stream must have been constructed from an instance of this class
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
diff --git a/src/main/java/org/jfree/chart/util/ShapeList.java b/src/main/java/org/jfree/chart/util/ShapeList.java
index 60cb8c9fa..6939d5017 100644
--- a/src/main/java/org/jfree/chart/util/ShapeList.java
+++ b/src/main/java/org/jfree/chart/util/ShapeList.java
@@ -28,6 +28,8 @@
package org.jfree.chart.util;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Shape;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -52,7 +54,7 @@ public ShapeList() {
*
* @return The object.
*/
- public Shape getShape(int index) {
+ public Shape getShape(@NonNegative int index) {
return (Shape) get(index);
}
@@ -63,7 +65,7 @@ public Shape getShape(int index) {
* @param index the index (zero-based).
* @param shape the {@link Shape}.
*/
- public void setShape(int index, Shape shape) {
+ public void setShape(@NonNegative int index, Shape shape) {
set(index, shape);
}
@@ -148,6 +150,7 @@ private void writeObject(ObjectOutputStream stream) throws IOException {
* @throws IOException if there is an I/O error.
* @throws ClassNotFoundException if there is a classpath problem.
*/
+ @SuppressWarnings("index") // readObject assumes that the object read is actually an object of this class
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
diff --git a/src/main/java/org/jfree/chart/util/StringUtils.java b/src/main/java/org/jfree/chart/util/StringUtils.java
index 9299ed405..2f37a13c2 100644
--- a/src/main/java/org/jfree/chart/util/StringUtils.java
+++ b/src/main/java/org/jfree/chart/util/StringUtils.java
@@ -28,6 +28,8 @@
package org.jfree.chart.util;
+import org.checkerframework.checker.index.qual.*;
+
/**
* String utilities.
*/
@@ -63,10 +65,11 @@ public static boolean startsWithIgnoreCase(String base, String start) {
* @return true, if the string ends with the given ending text.
*/
public static boolean endsWithIgnoreCase(String base, String end) {
- if (base.length() < end.length()) {
+ int baseLen = base.length();
+ if (baseLen < end.length()) {
return false;
}
- return base.regionMatches(true, base.length() - end.length(), end, 0, end.length());
+ return base.regionMatches(true, baseLen - end.length(), end, 0, end.length());
}
/**
diff --git a/src/main/java/org/jfree/chart/util/StrokeList.java b/src/main/java/org/jfree/chart/util/StrokeList.java
index 72cf3208f..9ea014f98 100644
--- a/src/main/java/org/jfree/chart/util/StrokeList.java
+++ b/src/main/java/org/jfree/chart/util/StrokeList.java
@@ -28,6 +28,8 @@
package org.jfree.chart.util;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Stroke;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -52,7 +54,7 @@ public StrokeList() {
*
* @return The object.
*/
- public Stroke getStroke(int index) {
+ public Stroke getStroke(@NonNegative int index) {
return (Stroke) get(index);
}
@@ -62,7 +64,7 @@ public Stroke getStroke(int index) {
* @param index the index (zero-based).
* @param stroke the {@link Stroke}.
*/
- public void setStroke(int index, Stroke stroke) {
+ public void setStroke(@NonNegative int index, Stroke stroke) {
set(index, stroke);
}
@@ -145,6 +147,7 @@ private void writeObject(ObjectOutputStream stream) throws IOException {
* @throws IOException if there is an I/O error.
* @throws ClassNotFoundException if there is a classpath problem.
*/
+ @SuppressWarnings("index") // stream must have been constructed from an instance of this class
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
diff --git a/src/main/java/org/jfree/data/ComparableObjectSeries.java b/src/main/java/org/jfree/data/ComparableObjectSeries.java
index 34f844ced..d70daedad 100644
--- a/src/main/java/org/jfree/data/ComparableObjectSeries.java
+++ b/src/main/java/org/jfree/data/ComparableObjectSeries.java
@@ -42,6 +42,9 @@
package org.jfree.data;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
@@ -64,7 +67,7 @@ public class ComparableObjectSeries extends Series
protected List data;
/** The maximum number of items for the series. */
- private int maximumItemCount = Integer.MAX_VALUE;
+ private @NonNegative int maximumItemCount = Integer.MAX_VALUE;
/** A flag that controls whether the items are automatically sorted. */
private boolean autoSort;
@@ -128,7 +131,7 @@ public boolean getAllowDuplicateXValues() {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.data.size();
}
@@ -139,7 +142,7 @@ public int getItemCount() {
* @return The maximum item count.
* @see #setMaximumItemCount(int)
*/
- public int getMaximumItemCount() {
+ public @NonNegative int getMaximumItemCount() {
return this.maximumItemCount;
}
@@ -157,7 +160,7 @@ public int getMaximumItemCount() {
*
* @param maximum the maximum number of items for the series.
*/
- public void setMaximumItemCount(int maximum) {
+ public void setMaximumItemCount(@NonNegative int maximum) {
this.maximumItemCount = maximum;
boolean dataRemoved = false;
while (this.data.size() > maximum) {
@@ -218,7 +221,9 @@ protected void add(ComparableObjectItem item, boolean notify) {
if (this.autoSort) {
int index = Collections.binarySearch(this.data, item);
if (index < 0) {
- this.data.add(-index - 1, item);
+ @SuppressWarnings("index") // binary search on list, which SearchIndex does not handle because lists are not fixed-size data structure
+ @NonNegative int reverseIndex = -index - 1;
+ this.data.add(reverseIndex, item);
}
else {
if (this.allowDuplicateXValues) {
@@ -314,7 +319,7 @@ protected void update(Comparable x, Object y) {
* @param index the item (zero based index).
* @param y the new value ({@code null} permitted).
*/
- protected void updateByIndex(int index, Object y) {
+ protected void updateByIndex(@NonNegative int index, Object y) {
ComparableObjectItem item = getDataItem(index);
item.setObject(y);
fireSeriesChanged();
@@ -327,7 +332,7 @@ protected void updateByIndex(int index, Object y) {
*
* @return The data item with the specified index.
*/
- protected ComparableObjectItem getDataItem(int index) {
+ protected ComparableObjectItem getDataItem(@NonNegative int index) {
return (ComparableObjectItem) this.data.get(index);
}
@@ -338,7 +343,7 @@ protected ComparableObjectItem getDataItem(int index) {
* @param start the start index (zero-based).
* @param end the end index (zero-based).
*/
- protected void delete(int start, int end) {
+ protected void delete(@NonNegative int start, @NonNegative int end) {
for (int i = start; i <= end; i++) {
this.data.remove(start);
}
@@ -365,7 +370,7 @@ public void clear() {
*
* @return The item removed.
*/
- protected ComparableObjectItem remove(int index) {
+ protected ComparableObjectItem remove(@NonNegative int index) {
ComparableObjectItem result = (ComparableObjectItem) this.data.remove(
index);
fireSeriesChanged();
@@ -380,6 +385,7 @@ protected ComparableObjectItem remove(int index) {
* @return The item removed.
*/
+ @SuppressWarnings("index") // guaranteed index: method precondition is that this element is in the list, so indexOf will return NN
public ComparableObjectItem remove(Comparable x) {
return remove(indexOf(x));
}
diff --git a/src/main/java/org/jfree/data/DataUtils.java b/src/main/java/org/jfree/data/DataUtils.java
index 2361b4ade..6008139d5 100644
--- a/src/main/java/org/jfree/data/DataUtils.java
+++ b/src/main/java/org/jfree/data/DataUtils.java
@@ -48,6 +48,10 @@
package org.jfree.data;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.Arrays;
import org.jfree.chart.util.Args;
import org.jfree.data.general.DatasetUtils;
@@ -98,7 +102,7 @@ public static boolean equal(double[][] a, double[][] b) {
*
* @since 1.0.13
*/
- public static double[][] clone(double[][] source) {
+ public static double @SameLen("#1") [][] clone(double[][] source) {
Args.nullNotPermitted(source, "source");
double[][] clone = new double[source.length][];
for (int i = 0; i < source.length; i++) {
@@ -120,7 +124,7 @@ public static double[][] clone(double[][] source) {
*
* @return The total of the values in the specified column.
*/
- public static double calculateColumnTotal(Values2D data, int column) {
+ public static double calculateColumnTotal(Values2D data, @NonNegative int column) {
Args.nullNotPermitted(data, "data");
double total = 0.0;
int rowCount = data.getRowCount();
@@ -145,8 +149,8 @@ public static double calculateColumnTotal(Values2D data, int column) {
*
* @since 1.0.13
*/
- public static double calculateColumnTotal(Values2D data, int column,
- int[] validRows) {
+ public static double calculateColumnTotal(Values2D data, @NonNegative int column,
+ @NonNegative int[] validRows) {
Args.nullNotPermitted(data, "data");
double total = 0.0;
int rowCount = data.getRowCount();
@@ -171,7 +175,7 @@ public static double calculateColumnTotal(Values2D data, int column,
*
* @return The total of the values in the specified row.
*/
- public static double calculateRowTotal(Values2D data, int row) {
+ public static double calculateRowTotal(Values2D data, @NonNegative int row) {
Args.nullNotPermitted(data, "data");
double total = 0.0;
int columnCount = data.getColumnCount();
@@ -196,8 +200,8 @@ public static double calculateRowTotal(Values2D data, int row) {
*
* @since 1.0.13
*/
- public static double calculateRowTotal(Values2D data, int row,
- int[] validCols) {
+ public static double calculateRowTotal(Values2D data, @NonNegative int row,
+ @NonNegative int[] validCols) {
Args.nullNotPermitted(data, "data");
double total = 0.0;
int colCount = data.getColumnCount();
@@ -238,10 +242,11 @@ public static Number[] createNumberArray(double[] data) {
*
* @return An array of {@code double}.
*/
- public static Number[][] createNumberArray2D(double[][] data) {
+ @SuppressWarnings("value") // the result array is manifestly the same size as the parameter
+ public static Number @SameLen("#1") @PolyValue [][] createNumberArray2D(double @PolyValue [][] data) {
Args.nullNotPermitted(data, "data");
int l1 = data.length;
- Number[][] result = new Number[l1][];
+ Number[][] result = new Number[data.length][];
for (int i = 0; i < l1; i++) {
result[i] = createNumberArray(data[i]);
}
diff --git a/src/main/java/org/jfree/data/DefaultKeyedValues.java b/src/main/java/org/jfree/data/DefaultKeyedValues.java
index 47915a2b8..1e72d36dd 100644
--- a/src/main/java/org/jfree/data/DefaultKeyedValues.java
+++ b/src/main/java/org/jfree/data/DefaultKeyedValues.java
@@ -60,6 +60,9 @@
package org.jfree.data;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -107,7 +110,7 @@ public DefaultKeyedValues() {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.indexMap.size();
}
@@ -121,7 +124,7 @@ public int getItemCount() {
* @throws IndexOutOfBoundsException if {@code item} is out of bounds.
*/
@Override
- public Number getValue(int item) {
+ public Number getValue(@NonNegative int item) {
return (Number) this.values.get(item);
}
@@ -135,7 +138,7 @@ public Number getValue(int item) {
* @throws IndexOutOfBoundsException if {@code item} is out of bounds.
*/
@Override
- public Comparable getKey(int index) {
+ public Comparable getKey(@NonNegative int index) {
return (Comparable) this.keys.get(index);
}
@@ -150,13 +153,15 @@ public Comparable getKey(int index) {
* {@code null}.
*/
@Override
- public int getIndex(Comparable key) {
+ public @GTENegativeOne int getIndex(Comparable key) {
Args.nullNotPermitted(key, "key");
final Integer i = (Integer) this.indexMap.get(key);
if (i == null) {
return -1; // key not found
}
- return i.intValue();
+ @SuppressWarnings("index") // the map only contains indices, so if the value is in the map, then result is non-negative
+ @NonNegative int result = i.intValue();
+ return result;
}
/**
@@ -254,7 +259,7 @@ public void setValue(Comparable key, Number value) {
*
* @since 1.0.6
*/
- public void insertValue(int position, Comparable key, double value) {
+ public void insertValue(@NonNegative int position, Comparable key, double value) {
insertValue(position, key, new Double(value));
}
@@ -269,7 +274,7 @@ public void insertValue(int position, Comparable key, double value) {
*
* @since 1.0.6
*/
- public void insertValue(int position, Comparable key, Number value) {
+ public void insertValue(@NonNegative int position, Comparable key, Number value) {
if (position < 0 || position > getItemCount()) {
throw new IllegalArgumentException("'position' out of bounds.");
}
@@ -312,7 +317,7 @@ private void rebuildIndex () {
* @throws IndexOutOfBoundsException if {@code index} is not within
* the specified range.
*/
- public void removeValue(int index) {
+ public void removeValue(@NonNegative int index) {
this.keys.remove(index);
this.values.remove(index);
rebuildIndex();
diff --git a/src/main/java/org/jfree/data/DefaultKeyedValues2D.java b/src/main/java/org/jfree/data/DefaultKeyedValues2D.java
index 16cd05775..afa822720 100644
--- a/src/main/java/org/jfree/data/DefaultKeyedValues2D.java
+++ b/src/main/java/org/jfree/data/DefaultKeyedValues2D.java
@@ -58,6 +58,10 @@
package org.jfree.data;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
@@ -116,7 +120,7 @@ public DefaultKeyedValues2D(boolean sortRowKeys) {
* @see #getColumnCount()
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.rowKeys.size();
}
@@ -128,7 +132,8 @@ public int getRowCount() {
* @see #getRowCount()
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
return this.columnKeys.size();
}
@@ -143,7 +148,8 @@ public int getColumnCount() {
* @see #getValue(Comparable, Comparable)
*/
@Override
- public Number getValue(int row, int column) {
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column) {
Number result = null;
DefaultKeyedValues rowData = (DefaultKeyedValues) this.rows.get(row);
if (rowData != null) {
@@ -169,7 +175,7 @@ public Number getValue(int row, int column) {
* @see #getColumnKey(int)
*/
@Override
- public Comparable getRowKey(int row) {
+ public Comparable getRowKey(@NonNegative int row) {
return (Comparable) this.rowKeys.get(row);
}
@@ -184,7 +190,8 @@ public Comparable getRowKey(int row) {
* @see #getColumnIndex(Comparable)
*/
@Override
- public int getRowIndex(Comparable key) {
+ @SuppressWarnings("index") // I think this is a bug. Binary search can return a search index, inconsistent with docs on this method
+ public @GTENegativeOne int getRowIndex(Comparable key) {
Args.nullNotPermitted(key, "key");
if (this.sortRowKeys) {
return Collections.binarySearch(this.rowKeys, key);
@@ -218,7 +225,7 @@ public List getRowKeys() {
* @see #getRowKey(int)
*/
@Override
- public Comparable getColumnKey(int column) {
+ public Comparable getColumnKey(@NonNegative int column) {
return (Comparable) this.columnKeys.get(column);
}
@@ -233,7 +240,7 @@ public Comparable getColumnKey(int column) {
* @see #getRowIndex(Comparable)
*/
@Override
- public int getColumnIndex(Comparable key) {
+ public @GTENegativeOne int getColumnIndex(Comparable key) {
Args.nullNotPermitted(key, "key");
return this.columnKeys.indexOf(key);
}
@@ -360,7 +367,8 @@ public void removeValue(Comparable rowKey, Comparable columnKey) {
// 1. check whether the row is now empty.
boolean allNull = true;
- int rowIndex = getRowIndex(rowKey);
+ @SuppressWarnings("index") // array-list interop: this method assumes that the rowKey is valid, which can't be checked b/c it's a list
+ @NonNegative int rowIndex = getRowIndex(rowKey);
DefaultKeyedValues row = (DefaultKeyedValues) this.rows.get(rowIndex);
for (int item = 0, itemCount = row.getItemCount(); item < itemCount;
@@ -411,7 +419,7 @@ public void removeValue(Comparable rowKey, Comparable columnKey) {
* @see #removeRow(Comparable)
* @see #removeColumn(int)
*/
- public void removeRow(int rowIndex) {
+ public void removeRow(@NonNegative int rowIndex) {
this.rowKeys.remove(rowIndex);
this.rows.remove(rowIndex);
}
@@ -446,7 +454,7 @@ public void removeRow(Comparable rowKey) {
* @see #removeColumn(Comparable)
* @see #removeRow(int)
*/
- public void removeColumn(int columnIndex) {
+ public void removeColumn(@NonNegative int columnIndex) {
Comparable columnKey = getColumnKey(columnIndex);
removeColumn(columnKey);
}
diff --git a/src/main/java/org/jfree/data/KeyToGroupMap.java b/src/main/java/org/jfree/data/KeyToGroupMap.java
index 60fed49e0..964dc8ae6 100644
--- a/src/main/java/org/jfree/data/KeyToGroupMap.java
+++ b/src/main/java/org/jfree/data/KeyToGroupMap.java
@@ -45,6 +45,9 @@
package org.jfree.data;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -99,7 +102,8 @@ public KeyToGroupMap(Comparable defaultGroup) {
*
* @return The number of groups in the map.
*/
- public int getGroupCount() {
+ @Pure
+ public @Positive int getGroupCount() {
return this.groups.size() + 1;
}
@@ -131,7 +135,7 @@ public List getGroups() {
* @return The group index (or -1 if the group is not represented within
* the map).
*/
- public int getGroupIndex(Comparable group) {
+ public @GTENegativeOne int getGroupIndex(Comparable group) {
int result = this.groups.indexOf(group);
if (result < 0) {
if (this.defaultGroup.equals(group)) {
@@ -202,7 +206,7 @@ public void mapKeyToGroup(Comparable key, Comparable group) {
*
* @return The key count.
*/
- public int getKeyCount(Comparable group) {
+ public @NonNegative int getKeyCount(Comparable group) {
Args.nullNotPermitted(group, "group");
int result = 0;
Iterator iterator = this.keyToGroupMap.values().iterator();
diff --git a/src/main/java/org/jfree/data/KeyedObjects.java b/src/main/java/org/jfree/data/KeyedObjects.java
index 4a6a3149e..eb702dd2f 100644
--- a/src/main/java/org/jfree/data/KeyedObjects.java
+++ b/src/main/java/org/jfree/data/KeyedObjects.java
@@ -44,6 +44,9 @@
package org.jfree.data;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
@@ -73,7 +76,7 @@ public KeyedObjects() {
*
* @return The item count.
*/
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.data.size();
}
@@ -86,7 +89,7 @@ public int getItemCount() {
*
* @throws IndexOutOfBoundsException if {@code item} is out of bounds.
*/
- public Object getObject(int item) {
+ public Object getObject(@NonNegative int item) {
Object result = null;
KeyedObject kobj = (KeyedObject) this.data.get(item);
if (kobj != null) {
@@ -106,7 +109,7 @@ public Object getObject(int item) {
*
* @see #getIndex(Comparable)
*/
- public Comparable getKey(int index) {
+ public Comparable getKey(@NonNegative int index) {
Comparable result = null;
KeyedObject item = (KeyedObject) this.data.get(index);
if (item != null) {
@@ -124,7 +127,7 @@ public Comparable getKey(int index) {
*
* @see #getKey(int)
*/
- public int getIndex(Comparable key) {
+ public @GTENegativeOne int getIndex(Comparable key) {
Args.nullNotPermitted(key, "key");
int i = 0;
Iterator iterator = this.data.iterator();
@@ -244,7 +247,7 @@ public void insertValue(int position, Comparable key, Object value) {
*
* @see #removeValue(Comparable)
*/
- public void removeValue(int index) {
+ public void removeValue(@NonNegative int index) {
this.data.remove(index);
}
diff --git a/src/main/java/org/jfree/data/KeyedObjects2D.java b/src/main/java/org/jfree/data/KeyedObjects2D.java
index c02ab6210..d2943eb16 100644
--- a/src/main/java/org/jfree/data/KeyedObjects2D.java
+++ b/src/main/java/org/jfree/data/KeyedObjects2D.java
@@ -45,6 +45,9 @@
package org.jfree.data;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
@@ -85,7 +88,7 @@ public KeyedObjects2D() {
*
* @see #getColumnCount()
*/
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.rowKeys.size();
}
@@ -96,7 +99,7 @@ public int getRowCount() {
*
* @see #getRowCount()
*/
- public int getColumnCount() {
+ public @NonNegative int getColumnCount() {
return this.columnKeys.size();
}
@@ -110,7 +113,7 @@ public int getColumnCount() {
*
* @see #getObject(Comparable, Comparable)
*/
- public Object getObject(int row, int column) {
+ public Object getObject(@NonNegative int row, @NonNegative int column) {
Object result = null;
KeyedObjects rowData = (KeyedObjects) this.rows.get(row);
if (rowData != null) {
@@ -134,7 +137,7 @@ public Object getObject(int row, int column) {
*
* @see #getRowIndex(Comparable)
*/
- public Comparable getRowKey(int row) {
+ public Comparable getRowKey(@NonNegative int row) {
return (Comparable) this.rowKeys.get(row);
}
@@ -148,7 +151,7 @@ public Comparable getRowKey(int row) {
*
* @see #getRowKey(int)
*/
- public int getRowIndex(Comparable key) {
+ public @GTENegativeOne int getRowIndex(Comparable key) {
Args.nullNotPermitted(key, "key");
return this.rowKeys.indexOf(key);
}
@@ -173,7 +176,7 @@ public List getRowKeys() {
*
* @see #getColumnIndex(Comparable)
*/
- public Comparable getColumnKey(int column) {
+ public Comparable getColumnKey(@NonNegative int column) {
return (Comparable) this.columnKeys.get(column);
}
@@ -187,7 +190,7 @@ public Comparable getColumnKey(int column) {
*
* @see #getColumnKey(int)
*/
- public int getColumnIndex(Comparable key) {
+ public @GTENegativeOne int getColumnIndex(Comparable key) {
Args.nullNotPermitted(key, "key");
return this.columnKeys.indexOf(key);
}
@@ -352,7 +355,7 @@ public void removeObject(Comparable rowKey, Comparable columnKey) {
*
* @see #removeColumn(int)
*/
- public void removeRow(int rowIndex) {
+ public void removeRow(@NonNegative int rowIndex) {
this.rowKeys.remove(rowIndex);
this.rows.remove(rowIndex);
}
@@ -382,7 +385,7 @@ public void removeRow(Comparable rowKey) {
*
* @see #removeRow(int)
*/
- public void removeColumn(int columnIndex) {
+ public void removeColumn(@NonNegative int columnIndex) {
Comparable columnKey = getColumnKey(columnIndex);
removeColumn(columnKey);
}
diff --git a/src/main/java/org/jfree/data/KeyedValues.java b/src/main/java/org/jfree/data/KeyedValues.java
index ee4f6a2f5..53462e9c0 100644
--- a/src/main/java/org/jfree/data/KeyedValues.java
+++ b/src/main/java/org/jfree/data/KeyedValues.java
@@ -44,6 +44,9 @@
package org.jfree.data;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.List;
/**
@@ -68,7 +71,7 @@ public interface KeyedValues extends Values {
* @throws IndexOutOfBoundsException if {@code index} is not in the
* specified range.
*/
- public Comparable getKey(int index);
+ public Comparable getKey(@NonNegative int index);
/**
* Returns the index for a given key.
@@ -79,7 +82,7 @@ public interface KeyedValues extends Values {
*
* @throws IllegalArgumentException if {@code key} is {@code null}.
*/
- public int getIndex(Comparable key);
+ public @GTENegativeOne int getIndex(Comparable key);
/**
* Returns the keys for the values in the collection. Note that you can
diff --git a/src/main/java/org/jfree/data/KeyedValues2D.java b/src/main/java/org/jfree/data/KeyedValues2D.java
index af15e5c38..ba0a7efe2 100644
--- a/src/main/java/org/jfree/data/KeyedValues2D.java
+++ b/src/main/java/org/jfree/data/KeyedValues2D.java
@@ -41,6 +41,9 @@
package org.jfree.data;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.List;
/**
@@ -58,7 +61,7 @@ public interface KeyedValues2D extends Values2D {
*
* @throws IndexOutOfBoundsException if {@code row} is out of bounds.
*/
- public Comparable getRowKey(int row);
+ public Comparable getRowKey(@NonNegative int row);
/**
* Returns the row index for a given key.
@@ -67,7 +70,7 @@ public interface KeyedValues2D extends Values2D {
*
* @return The row index, or {@code -1} if the key is unrecognised.
*/
- public int getRowIndex(Comparable key);
+ public @GTENegativeOne int getRowIndex(Comparable key);
/**
* Returns the row keys.
@@ -85,7 +88,7 @@ public interface KeyedValues2D extends Values2D {
*
* @throws IndexOutOfBoundsException if {@code row} is out of bounds.
*/
- public Comparable getColumnKey(int column);
+ public Comparable getColumnKey(@NonNegative int column);
/**
* Returns the column index for a given key.
@@ -94,7 +97,7 @@ public interface KeyedValues2D extends Values2D {
*
* @return The column index, or {@code -1} if the key is unrecognised.
*/
- public int getColumnIndex(Comparable key);
+ public @GTENegativeOne int getColumnIndex(Comparable key);
/**
* Returns the column keys.
diff --git a/src/main/java/org/jfree/data/Values.java b/src/main/java/org/jfree/data/Values.java
index f26892f8d..02a69d421 100644
--- a/src/main/java/org/jfree/data/Values.java
+++ b/src/main/java/org/jfree/data/Values.java
@@ -43,6 +43,8 @@
package org.jfree.data;
+import org.checkerframework.checker.index.qual.NonNegative;
+
/**
* An interface through which (single-dimension) data values can be accessed.
*/
@@ -53,7 +55,7 @@ public interface Values {
*
* @return The item count (possibly zero).
*/
- public int getItemCount();
+ public @NonNegative int getItemCount();
/**
* Returns the value with the specified index.
@@ -66,6 +68,6 @@ public interface Values {
* @throws IndexOutOfBoundsException if {@code index} is not in the
* specified range.
*/
- public Number getValue(int index);
+ public Number getValue(@NonNegative int index);
}
diff --git a/src/main/java/org/jfree/data/Values2D.java b/src/main/java/org/jfree/data/Values2D.java
index 0fd3df209..bbf04f959 100644
--- a/src/main/java/org/jfree/data/Values2D.java
+++ b/src/main/java/org/jfree/data/Values2D.java
@@ -40,6 +40,9 @@
package org.jfree.data;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.NonNegative;
+
/**
* A general purpose interface that can be used to access a table of values.
*/
@@ -50,14 +53,15 @@ public interface Values2D {
*
* @return The row count.
*/
- public int getRowCount();
+ public @NonNegative int getRowCount();
/**
* Returns the number of columns in the table.
*
* @return The column count.
*/
- public int getColumnCount();
+ @Pure
+ public @NonNegative int getColumnCount();
/**
* Returns a value from the table.
@@ -70,6 +74,7 @@ public interface Values2D {
* @throws IndexOutOfBoundsException if the {@code row}
* or {@code column} is out of bounds.
*/
- public Number getValue(int row, int column);
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column);
}
diff --git a/src/main/java/org/jfree/data/category/CategoryToPieDataset.java b/src/main/java/org/jfree/data/category/CategoryToPieDataset.java
index 26cb792d9..b4baf4e9c 100644
--- a/src/main/java/org/jfree/data/category/CategoryToPieDataset.java
+++ b/src/main/java/org/jfree/data/category/CategoryToPieDataset.java
@@ -49,6 +49,9 @@
package org.jfree.data.category;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.Collections;
import java.util.List;
import org.jfree.chart.util.Args;
@@ -76,7 +79,7 @@ public class CategoryToPieDataset extends AbstractDataset
private TableOrder extract;
/** The row or column index. */
- private int index;
+ private @NonNegative int index;
/**
* An adaptor class that converts any {@link CategoryDataset} into a
@@ -91,7 +94,7 @@ public class CategoryToPieDataset extends AbstractDataset
* @param index the row or column index.
*/
public CategoryToPieDataset(CategoryDataset source, TableOrder extract,
- int index) {
+ @NonNegative int index) {
Args.nullNotPermitted(extract, "extract");
this.source = source;
if (this.source != null) {
@@ -131,7 +134,7 @@ public TableOrder getExtractType() {
*
* @since 1.0.2
*/
- public int getExtractIndex() {
+ public @NonNegative int getExtractIndex() {
return this.index;
}
@@ -142,7 +145,7 @@ public int getExtractIndex() {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
int result = 0;
if (this.source != null) {
if (this.extract == TableOrder.BY_ROW) {
@@ -166,7 +169,7 @@ else if (this.extract == TableOrder.BY_COLUMN) {
* range {@code 0} to {@code getItemCount() -1}.
*/
@Override
- public Number getValue(int item) {
+ public Number getValue(@NonNegative int item) {
Number result = null;
if (item < 0 || item >= getItemCount()) {
// this will include the case where the underlying dataset is null
@@ -194,7 +197,7 @@ else if (this.extract == TableOrder.BY_COLUMN) {
* specified range.
*/
@Override
- public Comparable getKey(int index) {
+ public Comparable getKey(@NonNegative int index) {
Comparable result = null;
if (index < 0 || index >= getItemCount()) {
// this includes the case where the underlying dataset is null
@@ -218,7 +221,7 @@ else if (this.extract == TableOrder.BY_COLUMN) {
* @return The index for the key, or {@code -1}.
*/
@Override
- public int getIndex(Comparable key) {
+ public @GTENegativeOne int getIndex(Comparable key) {
int result = -1;
if (this.source != null) {
if (this.extract == TableOrder.BY_ROW) {
diff --git a/src/main/java/org/jfree/data/category/DefaultCategoryDataset.java b/src/main/java/org/jfree/data/category/DefaultCategoryDataset.java
index 9c2b7bfc5..b5b363c71 100644
--- a/src/main/java/org/jfree/data/category/DefaultCategoryDataset.java
+++ b/src/main/java/org/jfree/data/category/DefaultCategoryDataset.java
@@ -48,6 +48,10 @@
package org.jfree.data.category;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.List;
import org.jfree.chart.util.PublicCloneable;
@@ -84,7 +88,7 @@ public DefaultCategoryDataset() {
* @see #getColumnCount()
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.data.getRowCount();
}
@@ -96,7 +100,8 @@ public int getRowCount() {
* @see #getRowCount()
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
return this.data.getColumnCount();
}
@@ -112,7 +117,8 @@ public int getColumnCount() {
* @see #removeValue(Comparable, Comparable)
*/
@Override
- public Number getValue(int row, int column) {
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column) {
return this.data.getValue(row, column);
}
@@ -128,7 +134,7 @@ public Number getValue(int row, int column) {
* @see #getColumnKey(int)
*/
@Override
- public Comparable getRowKey(int row) {
+ public Comparable getRowKey(@NonNegative int row) {
return this.data.getRowKey(row);
}
@@ -142,7 +148,7 @@ public Comparable getRowKey(int row) {
* @see #getRowKey(int)
*/
@Override
- public int getRowIndex(Comparable key) {
+ public @GTENegativeOne int getRowIndex(Comparable key) {
// defer null argument check
return this.data.getRowIndex(key);
}
@@ -169,7 +175,7 @@ public List getRowKeys() {
* @see #getColumnIndex(Comparable)
*/
@Override
- public Comparable getColumnKey(int column) {
+ public Comparable getColumnKey(@NonNegative int column) {
return this.data.getColumnKey(column);
}
@@ -183,7 +189,7 @@ public Comparable getColumnKey(int column) {
* @see #getColumnKey(int)
*/
@Override
- public int getColumnIndex(Comparable key) {
+ public @GTENegativeOne int getColumnIndex(Comparable key) {
// defer null argument check
return this.data.getColumnIndex(key);
}
@@ -321,7 +327,7 @@ public void removeValue(Comparable rowKey, Comparable columnKey) {
*
* @see #removeColumn(int)
*/
- public void removeRow(int rowIndex) {
+ public void removeRow(@NonNegative int rowIndex) {
this.data.removeRow(rowIndex);
fireDatasetChanged();
}
@@ -347,7 +353,7 @@ public void removeRow(Comparable rowKey) {
*
* @see #removeRow(int)
*/
- public void removeColumn(int columnIndex) {
+ public void removeColumn(@NonNegative int columnIndex) {
this.data.removeColumn(columnIndex);
fireDatasetChanged();
}
diff --git a/src/main/java/org/jfree/data/category/DefaultIntervalCategoryDataset.java b/src/main/java/org/jfree/data/category/DefaultIntervalCategoryDataset.java
index 458ce1e47..5cd3672ed 100644
--- a/src/main/java/org/jfree/data/category/DefaultIntervalCategoryDataset.java
+++ b/src/main/java/org/jfree/data/category/DefaultIntervalCategoryDataset.java
@@ -48,6 +48,10 @@
package org.jfree.data.category;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -56,6 +60,7 @@
import org.jfree.chart.util.Args;
import org.jfree.chart.util.ResourceBundleWrapper;
+import org.jfree.data.ComparableObjectSeries;
import org.jfree.data.DataUtils;
import org.jfree.data.UnknownKeyException;
import org.jfree.data.general.AbstractSeriesDataset;
@@ -91,7 +96,8 @@ public class DefaultIntervalCategoryDataset extends AbstractSeriesDataset
* @param ends the ending values for the intervals ({@code null} not
* permitted).
*/
- public DefaultIntervalCategoryDataset(double[][] starts, double[][] ends) {
+ @SuppressWarnings("index") // results of DataUtils.createNumberArray should have the same length as their inputs, but SameLens don't propagate correctly :(
+ public DefaultIntervalCategoryDataset(double @SameLen({"#1", "#2"}) [][] starts, double @SameLen({"#1", "#2"}) [][] ends) {
this(DataUtils.createNumberArray2D(starts),
DataUtils.createNumberArray2D(ends));
}
@@ -107,7 +113,7 @@ public DefaultIntervalCategoryDataset(double[][] starts, double[][] ends) {
* @param starts the start values data.
* @param ends the end values data.
*/
- public DefaultIntervalCategoryDataset(Number[][] starts, Number[][] ends) {
+ public DefaultIntervalCategoryDataset(Number @SameLen({"#1", "#2"}) [][] starts, Number @SameLen({"#1", "#2"}) [][] ends) {
this(null, null, starts, ends);
}
@@ -124,8 +130,8 @@ public DefaultIntervalCategoryDataset(Number[][] starts, Number[][] ends) {
* @param ends the end values data, indexed as data[series][category].
*/
public DefaultIntervalCategoryDataset(String[] seriesNames,
- Number[][] starts,
- Number[][] ends) {
+ Number @SameLen({"#2", "#3"}) [][] starts,
+ Number @SameLen({"#2", "#3"}) [][] ends) {
this(seriesNames, null, starts, ends);
@@ -145,8 +151,8 @@ public DefaultIntervalCategoryDataset(String[] seriesNames,
*/
public DefaultIntervalCategoryDataset(Comparable[] seriesKeys,
Comparable[] categoryKeys,
- Number[][] starts,
- Number[][] ends) {
+ Number @SameLen("#4") [][] starts,
+ Number @SameLen("#3") [][] ends) {
this.startData = starts;
this.endData = ends;
@@ -167,6 +173,14 @@ public DefaultIntervalCategoryDataset(Comparable[] seriesKeys,
}
if (seriesCount > 0) {
+ @SuppressWarnings({"index", "value"}) // seriesCount is the length of starts, so checking it against zero implies minlen(1)
+ Number @MinLen(1) [][] starts1 = starts;
+ starts = starts1;
+
+ @SuppressWarnings({"index", "value"}) // seriesCount is the length of starts, so checking it against zero implies minlen(1)
+ Number @MinLen(1) [][] ends1 = ends;
+ ends = ends1;
+
// set up the series names...
if (seriesKeys != null) {
@@ -225,7 +239,7 @@ public DefaultIntervalCategoryDataset(Comparable[] seriesKeys,
* @see #getCategoryCount()
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
int result = 0;
if (this.startData != null) {
result = this.startData.length;
@@ -243,7 +257,7 @@ public int getSeriesCount() {
* @see #getRowIndex(Comparable)
* @see #getSeriesKey(int)
*/
- public int getSeriesIndex(Comparable seriesKey) {
+ public @GTENegativeOne int getSeriesIndex(Comparable seriesKey) {
int result = -1;
for (int i = 0; i < this.seriesKeys.length; i++) {
if (seriesKey.equals(this.seriesKeys[i])) {
@@ -264,11 +278,13 @@ public int getSeriesIndex(Comparable seriesKey) {
* @see #getSeriesIndex(Comparable)
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
if ((series >= getSeriesCount()) || (series < 0)) {
throw new IllegalArgumentException("No such series : " + series);
}
- return this.seriesKeys[series];
+ @SuppressWarnings("index") // array-list interop: getSeriesCount() should be annotated as LengthOf, but because most implementations of this interface implement the series with a list it isn't
+ Comparable result = this.seriesKeys[series];
+ return result;
}
/**
@@ -297,11 +313,13 @@ public void setSeriesKeys(Comparable[] seriesKeys) {
*
* @see #getColumnCount()
*/
- public int getCategoryCount() {
+ public @NonNegative int getCategoryCount() {
int result = 0;
if (this.startData != null) {
if (getSeriesCount() > 0) {
- result = this.startData[0].length;
+ @SuppressWarnings("index") // array-list interop: getSeriesCount is the length of startData, but can't be annotated that way b/c implementation detail
+ int newResult = this.startData[0].length;
+ result = newResult;
}
}
return result;
@@ -394,7 +412,8 @@ public Number getValue(Comparable series, Comparable category) {
* @see #getEndValue(int, int)
*/
@Override
- public Number getValue(int series, int category) {
+ @Pure
+ public Number getValue(@NonNegative int series, @NonNegative int category) {
return getEndValue(series, category);
}
@@ -434,7 +453,7 @@ public Number getStartValue(Comparable series, Comparable category) {
* @see #getStartValue(Comparable, Comparable)
*/
@Override
- public Number getStartValue(int series, int category) {
+ public Number getStartValue(@NonNegative int series, @NonNegative int category) {
// check arguments...
if ((series < 0) || (series >= getSeriesCount())) {
@@ -450,8 +469,9 @@ public Number getStartValue(int series, int category) {
}
// fetch the value...
- return this.startData[series][category];
-
+ @SuppressWarnings("index") // array-list interop: that these are indices into these arrays is an implementation detail. Most implementations of this interface are backed by a list.
+ Number result = this.startData[series][category];
+ return result;
}
/**
@@ -488,7 +508,7 @@ public Number getEndValue(Comparable series, Comparable category) {
* @see #getEndValue(Comparable, Comparable)
*/
@Override
- public Number getEndValue(int series, int category) {
+ public Number getEndValue(@NonNegative int series, @NonNegative int category) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException(
"DefaultIntervalCategoryDataset.getValue(): "
@@ -500,8 +520,9 @@ public Number getEndValue(int series, int category) {
"DefaultIntervalCategoryDataset.getValue(): "
+ "category index out of range.");
}
-
- return this.endData[series][category];
+ @SuppressWarnings("index") // array-list interop: that these are indices into these arrays is an implementation detail. Most implementations of this interface are backed by a list.
+ Number result = this.endData[series][category];
+ return result;
}
/**
@@ -514,7 +535,7 @@ public Number getEndValue(int series, int category) {
*
* @see #setEndValue(int, Comparable, Number)
*/
- public void setStartValue(int series, Comparable category, Number value) {
+ public void setStartValue(@NonNegative int series, Comparable category, Number value) {
// does the series exist?
if ((series < 0) || (series > getSeriesCount() - 1)) {
@@ -532,7 +553,8 @@ public void setStartValue(int series, Comparable category, Number value) {
}
// update the data...
- this.startData[series][categoryIndex] = value;
+ @SuppressWarnings("index") // array-list interop: that these are indices into these arrays is an implementation detail. Most implementations of this interface are backed by a list.
+ Number tmp = (this.startData[series][categoryIndex] = value);
fireDatasetChanged();
}
@@ -547,7 +569,7 @@ public void setStartValue(int series, Comparable category, Number value) {
*
* @see #setStartValue(int, Comparable, Number)
*/
- public void setEndValue(int series, Comparable category, Number value) {
+ public void setEndValue(@NonNegative int series, Comparable category, Number value) {
// does the series exist?
if ((series < 0) || (series > getSeriesCount() - 1)) {
@@ -565,7 +587,8 @@ public void setEndValue(int series, Comparable category, Number value) {
}
// update the data...
- this.endData[series][categoryIndex] = value;
+ @SuppressWarnings("index") // array-list interop: that these are indices into these arrays is an implementation detail. Most implementations of this interface are backed by a list.
+ Number tmp = (this.endData[series][categoryIndex] = value);
fireDatasetChanged();
}
@@ -579,7 +602,7 @@ public void setEndValue(int series, Comparable category, Number value) {
*
* @see #getColumnIndex(Comparable)
*/
- public int getCategoryIndex(Comparable category) {
+ public @GTENegativeOne int getCategoryIndex(Comparable category) {
int result = -1;
for (int i = 0; i < this.categoryKeys.length; i++) {
if (category.equals(this.categoryKeys[i])) {
@@ -599,7 +622,7 @@ public int getCategoryIndex(Comparable category) {
*
* @return An array of prefixN with N = { 1 .. count}.
*/
- private Comparable[] generateKeys(int count, String prefix) {
+ private Comparable[] generateKeys(@NonNegative int count, String prefix) {
Comparable[] result = new Comparable[count];
String name;
for (int i = 0; i < count; i++) {
@@ -619,7 +642,8 @@ private Comparable[] generateKeys(int count, String prefix) {
* @see #getRowKey(int)
*/
@Override
- public Comparable getColumnKey(int column) {
+ @SuppressWarnings("index") // array-list interop: because this underlying array isn't exposed by the interface this method is inherited from, there is no way to write an upperbound annotation on column
+ public Comparable getColumnKey(@NonNegative int column) {
return this.categoryKeys[column];
}
@@ -633,7 +657,7 @@ public Comparable getColumnKey(int column) {
* @see #getCategoryIndex(Comparable)
*/
@Override
- public int getColumnIndex(Comparable columnKey) {
+ public @GTENegativeOne int getColumnIndex(Comparable columnKey) {
Args.nullNotPermitted(columnKey, "columnKey");
return getCategoryIndex(columnKey);
}
@@ -648,7 +672,7 @@ public int getColumnIndex(Comparable columnKey) {
* @see #getSeriesIndex(Comparable)
*/
@Override
- public int getRowIndex(Comparable rowKey) {
+ public @GTENegativeOne int getRowIndex(Comparable rowKey) {
return getSeriesIndex(rowKey);
}
@@ -682,7 +706,8 @@ public List getRowKeys() {
* @see #getColumnKey(int)
*/
@Override
- public Comparable getRowKey(int row) {
+ @SuppressWarnings("index") // array-list interop: because this underlying array isn't exposed by the interface this method is inherited from, there is no way to write an upperbound annotation on column
+ public Comparable getRowKey(@NonNegative int row) {
if ((row >= getRowCount()) || (row < 0)) {
throw new IllegalArgumentException(
"The 'row' argument is out of bounds.");
@@ -700,7 +725,8 @@ public Comparable getRowKey(int row) {
* @see #getRowCount()
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
return this.categoryKeys.length;
}
@@ -713,7 +739,7 @@ public int getColumnCount() {
* @see #getColumnCount()
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.seriesKeys.length;
}
diff --git a/src/main/java/org/jfree/data/category/IntervalCategoryDataset.java b/src/main/java/org/jfree/data/category/IntervalCategoryDataset.java
index 1dc829105..2d313e603 100644
--- a/src/main/java/org/jfree/data/category/IntervalCategoryDataset.java
+++ b/src/main/java/org/jfree/data/category/IntervalCategoryDataset.java
@@ -46,6 +46,8 @@
package org.jfree.data.category;
+import org.checkerframework.checker.index.qual.NonNegative;
+
/**
* A category dataset that defines a value range for each series/category
* combination.
@@ -62,7 +64,7 @@ public interface IntervalCategoryDataset extends CategoryDataset {
*
* @see #getEndValue(int, int)
*/
- public Number getStartValue(int series, int category);
+ public Number getStartValue(@NonNegative int series, @NonNegative int category);
/**
* Returns the start value for the interval for a given series and category.
@@ -86,7 +88,7 @@ public interface IntervalCategoryDataset extends CategoryDataset {
*
* @see #getStartValue(int, int)
*/
- public Number getEndValue(int series, int category);
+ public Number getEndValue(@NonNegative int series, @NonNegative int category);
/**
* Returns the end value for the interval for a given series and category.
diff --git a/src/main/java/org/jfree/data/category/SlidingCategoryDataset.java b/src/main/java/org/jfree/data/category/SlidingCategoryDataset.java
index 6575a4394..4eea10c53 100644
--- a/src/main/java/org/jfree/data/category/SlidingCategoryDataset.java
+++ b/src/main/java/org/jfree/data/category/SlidingCategoryDataset.java
@@ -41,6 +41,10 @@
package org.jfree.data.category;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.Collections;
import java.util.List;
import org.jfree.chart.util.PublicCloneable;
@@ -64,10 +68,10 @@ public class SlidingCategoryDataset extends AbstractDataset
private CategoryDataset underlying;
/** The index of the first category to present. */
- private int firstCategoryIndex;
+ private @NonNegative int firstCategoryIndex;
/** The maximum number of categories to present. */
- private int maximumCategoryCount;
+ private @NonNegative int maximumCategoryCount;
/**
* Creates a new instance.
@@ -78,8 +82,8 @@ public class SlidingCategoryDataset extends AbstractDataset
* underlying dataset.
* @param maxColumns the maximumColumnCount.
*/
- public SlidingCategoryDataset(CategoryDataset underlying, int firstColumn,
- int maxColumns) {
+ public SlidingCategoryDataset(CategoryDataset underlying, @NonNegative int firstColumn,
+ @NonNegative int maxColumns) {
this.underlying = underlying;
this.firstCategoryIndex = firstColumn;
this.maximumCategoryCount = maxColumns;
@@ -101,7 +105,7 @@ public CategoryDataset getUnderlyingDataset() {
*
* @see #setFirstCategoryIndex(int)
*/
- public int getFirstCategoryIndex() {
+ public @NonNegative int getFirstCategoryIndex() {
return this.firstCategoryIndex;
}
@@ -114,7 +118,7 @@ public int getFirstCategoryIndex() {
*
* @see #getFirstCategoryIndex()
*/
- public void setFirstCategoryIndex(int first) {
+ public void setFirstCategoryIndex(@NonNegative int first) {
if (first < 0 || first >= this.underlying.getColumnCount()) {
throw new IllegalArgumentException("Invalid index.");
}
@@ -129,7 +133,7 @@ public void setFirstCategoryIndex(int first) {
*
* @see #setMaximumCategoryCount(int)
*/
- public int getMaximumCategoryCount() {
+ public @NonNegative int getMaximumCategoryCount() {
return this.maximumCategoryCount;
}
@@ -141,7 +145,7 @@ public int getMaximumCategoryCount() {
*
* @see #getMaximumCategoryCount()
*/
- public void setMaximumCategoryCount(int max) {
+ public void setMaximumCategoryCount(@NonNegative int max) {
if (max < 0) {
throw new IllegalArgumentException("Requires 'max' >= 0.");
}
@@ -154,7 +158,8 @@ public void setMaximumCategoryCount(int max) {
*
* @return The index.
*/
- private int lastCategoryIndex() {
+ @Pure
+ private @GTENegativeOne int lastCategoryIndex() {
if (this.maximumCategoryCount == 0) {
return -1;
}
@@ -170,7 +175,7 @@ private int lastCategoryIndex() {
* @return The column index, or -1 if the key is not recognised.
*/
@Override
- public int getColumnIndex(Comparable key) {
+ public @GTENegativeOne int getColumnIndex(Comparable key) {
int index = this.underlying.getColumnIndex(key);
if (index >= this.firstCategoryIndex && index <= lastCategoryIndex()) {
return index - this.firstCategoryIndex;
@@ -188,7 +193,7 @@ public int getColumnIndex(Comparable key) {
* @throws IndexOutOfBoundsException if {@code row} is out of bounds.
*/
@Override
- public Comparable getColumnKey(int column) {
+ public Comparable getColumnKey(@NonNegative int column) {
return this.underlying.getColumnKey(column + this.firstCategoryIndex);
}
@@ -217,7 +222,7 @@ public List getColumnKeys() {
* @return The row index, or {@code -1} if the key is unrecognised.
*/
@Override
- public int getRowIndex(Comparable key) {
+ public @GTENegativeOne int getRowIndex(Comparable key) {
return this.underlying.getRowIndex(key);
}
@@ -231,7 +236,7 @@ public int getRowIndex(Comparable key) {
* @throws IndexOutOfBoundsException if {@code row} is out of bounds.
*/
@Override
- public Comparable getRowKey(int row) {
+ public Comparable getRowKey(@NonNegative int row) {
return this.underlying.getRowKey(row);
}
@@ -276,7 +281,8 @@ else if (r == -1) {
* @return The column count.
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
int last = lastCategoryIndex();
if (last == -1) {
return 0;
@@ -292,7 +298,7 @@ public int getColumnCount() {
* @return The row count.
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.underlying.getRowCount();
}
@@ -305,7 +311,8 @@ public int getRowCount() {
* @return The value (possibly {@code null}).
*/
@Override
- public Number getValue(int row, int column) {
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column) {
return this.underlying.getValue(row, column + this.firstCategoryIndex);
}
diff --git a/src/main/java/org/jfree/data/gantt/GanttCategoryDataset.java b/src/main/java/org/jfree/data/gantt/GanttCategoryDataset.java
index 300d73f2f..610c21213 100644
--- a/src/main/java/org/jfree/data/gantt/GanttCategoryDataset.java
+++ b/src/main/java/org/jfree/data/gantt/GanttCategoryDataset.java
@@ -42,6 +42,8 @@
package org.jfree.data.gantt;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.data.category.IntervalCategoryDataset;
/**
@@ -60,7 +62,7 @@ public interface GanttCategoryDataset extends IntervalCategoryDataset {
*
* @see #getPercentComplete(Comparable, Comparable)
*/
- public Number getPercentComplete(int row, int column);
+ public Number getPercentComplete(@NonNegative int row, @NonNegative int column);
/**
* Returns the percent complete for a given item.
@@ -84,7 +86,7 @@ public interface GanttCategoryDataset extends IntervalCategoryDataset {
*
* @see #getSubIntervalCount(Comparable, Comparable)
*/
- public int getSubIntervalCount(int row, int column);
+ public @NonNegative int getSubIntervalCount(@NonNegative int row, @NonNegative int column);
/**
* Returns the number of sub-intervals for a given item.
@@ -96,7 +98,7 @@ public interface GanttCategoryDataset extends IntervalCategoryDataset {
*
* @see #getSubIntervalCount(int, int)
*/
- public int getSubIntervalCount(Comparable rowKey, Comparable columnKey);
+ public @NonNegative int getSubIntervalCount(Comparable rowKey, Comparable columnKey);
/**
* Returns the start value of a sub-interval for a given item.
@@ -109,7 +111,7 @@ public interface GanttCategoryDataset extends IntervalCategoryDataset {
*
* @see #getEndValue(int, int, int)
*/
- public Number getStartValue(int row, int column, int subinterval);
+ public Number getStartValue(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval);
/**
* Returns the start value of a sub-interval for a given item.
@@ -123,7 +125,7 @@ public interface GanttCategoryDataset extends IntervalCategoryDataset {
* @see #getEndValue(Comparable, Comparable, int)
*/
public Number getStartValue(Comparable rowKey, Comparable columnKey,
- int subinterval);
+ @NonNegative int subinterval);
/**
* Returns the end value of a sub-interval for a given item.
@@ -136,7 +138,7 @@ public Number getStartValue(Comparable rowKey, Comparable columnKey,
*
* @see #getStartValue(int, int, int)
*/
- public Number getEndValue(int row, int column, int subinterval);
+ public Number getEndValue(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval);
/**
* Returns the end value of a sub-interval for a given item.
@@ -150,7 +152,7 @@ public Number getStartValue(Comparable rowKey, Comparable columnKey,
* @see #getStartValue(Comparable, Comparable, int)
*/
public Number getEndValue(Comparable rowKey, Comparable columnKey,
- int subinterval);
+ @NonNegative int subinterval);
/**
* Returns the percentage complete value of a sub-interval for a given item.
@@ -163,7 +165,7 @@ public Number getEndValue(Comparable rowKey, Comparable columnKey,
*
* @see #getPercentComplete(Comparable, Comparable, int)
*/
- public Number getPercentComplete(int row, int column, int subinterval);
+ public Number getPercentComplete(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval);
/**
* Returns the percentage complete value of a sub-interval for a given item.
@@ -177,6 +179,6 @@ public Number getEndValue(Comparable rowKey, Comparable columnKey,
* @see #getPercentComplete(int, int, int)
*/
public Number getPercentComplete(Comparable rowKey, Comparable columnKey,
- int subinterval);
+ @NonNegative int subinterval);
}
diff --git a/src/main/java/org/jfree/data/gantt/SlidingGanttCategoryDataset.java b/src/main/java/org/jfree/data/gantt/SlidingGanttCategoryDataset.java
index a7cbe817f..87471baef 100644
--- a/src/main/java/org/jfree/data/gantt/SlidingGanttCategoryDataset.java
+++ b/src/main/java/org/jfree/data/gantt/SlidingGanttCategoryDataset.java
@@ -40,6 +40,11 @@
package org.jfree.data.gantt;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.Collections;
import java.util.List;
import org.jfree.chart.util.PublicCloneable;
@@ -63,10 +68,10 @@ public class SlidingGanttCategoryDataset extends AbstractDataset
private GanttCategoryDataset underlying;
/** The index of the first category to present. */
- private int firstCategoryIndex;
+ private @NonNegative int firstCategoryIndex;
/** The maximum number of categories to present. */
- private int maximumCategoryCount;
+ private @NonNegative int maximumCategoryCount;
/**
* Creates a new instance.
@@ -78,7 +83,7 @@ public class SlidingGanttCategoryDataset extends AbstractDataset
* @param maxColumns the maximumColumnCount.
*/
public SlidingGanttCategoryDataset(GanttCategoryDataset underlying,
- int firstColumn, int maxColumns) {
+ @NonNegative int firstColumn, @NonNegative int maxColumns) {
this.underlying = underlying;
this.firstCategoryIndex = firstColumn;
this.maximumCategoryCount = maxColumns;
@@ -100,7 +105,7 @@ public GanttCategoryDataset getUnderlyingDataset() {
*
* @see #setFirstCategoryIndex(int)
*/
- public int getFirstCategoryIndex() {
+ public @NonNegative int getFirstCategoryIndex() {
return this.firstCategoryIndex;
}
@@ -113,7 +118,7 @@ public int getFirstCategoryIndex() {
*
* @see #getFirstCategoryIndex()
*/
- public void setFirstCategoryIndex(int first) {
+ public void setFirstCategoryIndex(@NonNegative int first) {
if (first < 0 || first >= this.underlying.getColumnCount()) {
throw new IllegalArgumentException("Invalid index.");
}
@@ -128,7 +133,7 @@ public void setFirstCategoryIndex(int first) {
*
* @see #setMaximumCategoryCount(int)
*/
- public int getMaximumCategoryCount() {
+ public @NonNegative int getMaximumCategoryCount() {
return this.maximumCategoryCount;
}
@@ -140,7 +145,7 @@ public int getMaximumCategoryCount() {
*
* @see #getMaximumCategoryCount()
*/
- public void setMaximumCategoryCount(int max) {
+ public void setMaximumCategoryCount(@NonNegative int max) {
if (max < 0) {
throw new IllegalArgumentException("Requires 'max' >= 0.");
}
@@ -153,7 +158,7 @@ public void setMaximumCategoryCount(int max) {
*
* @return The index.
*/
- private int lastCategoryIndex() {
+ private @GTENegativeOne int lastCategoryIndex() {
if (this.maximumCategoryCount == 0) {
return -1;
}
@@ -169,10 +174,11 @@ private int lastCategoryIndex() {
* @return The column index, or -1 if the key is not recognised.
*/
@Override
- public int getColumnIndex(Comparable key) {
+ public @GTENegativeOne int getColumnIndex(Comparable key) {
int index = this.underlying.getColumnIndex(key);
- if (index >= this.firstCategoryIndex && index <= lastCategoryIndex()) {
- return index - this.firstCategoryIndex;
+ int firstCategoryIndex = this.firstCategoryIndex;
+ if (index >= firstCategoryIndex && index <= lastCategoryIndex()) {
+ return index - firstCategoryIndex;
}
return -1; // we didn't find the key
}
@@ -187,7 +193,7 @@ public int getColumnIndex(Comparable key) {
* @throws IndexOutOfBoundsException if {@code row} is out of bounds.
*/
@Override
- public Comparable getColumnKey(int column) {
+ public Comparable getColumnKey(@NonNegative int column) {
return this.underlying.getColumnKey(column + this.firstCategoryIndex);
}
@@ -216,7 +222,7 @@ public List getColumnKeys() {
* @return The row index, or {@code -1} if the key is unrecognised.
*/
@Override
- public int getRowIndex(Comparable key) {
+ public @GTENegativeOne int getRowIndex(Comparable key) {
return this.underlying.getRowIndex(key);
}
@@ -230,7 +236,7 @@ public int getRowIndex(Comparable key) {
* @throws IndexOutOfBoundsException if {@code row} is out of bounds.
*/
@Override
- public Comparable getRowKey(int row) {
+ public Comparable getRowKey(@NonNegative int row) {
return this.underlying.getRowKey(row);
}
@@ -275,7 +281,8 @@ else if (r == -1) {
* @return The column count.
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
int last = lastCategoryIndex();
if (last == -1) {
return 0;
@@ -291,7 +298,7 @@ public int getColumnCount() {
* @return The row count.
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.underlying.getRowCount();
}
@@ -304,7 +311,8 @@ public int getRowCount() {
* @return The value (possibly {@code null}).
*/
@Override
- public Number getValue(int row, int column) {
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column) {
return this.underlying.getValue(row, column + this.firstCategoryIndex);
}
@@ -345,7 +353,7 @@ else if (r == -1) {
*/
@Override
public Number getPercentComplete(Comparable rowKey, Comparable columnKey,
- int subinterval) {
+ @NonNegative int subinterval) {
int r = getRowIndex(rowKey);
int c = getColumnIndex(columnKey);
if (c == -1) {
@@ -373,7 +381,7 @@ else if (r == -1) {
*/
@Override
public Number getEndValue(Comparable rowKey, Comparable columnKey,
- int subinterval) {
+ @NonNegative int subinterval) {
int r = getRowIndex(rowKey);
int c = getColumnIndex(columnKey);
if (c == -1) {
@@ -400,7 +408,7 @@ else if (r == -1) {
* @see #getStartValue(int, int, int)
*/
@Override
- public Number getEndValue(int row, int column, int subinterval) {
+ public Number getEndValue(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval) {
return this.underlying.getEndValue(row,
column + this.firstCategoryIndex, subinterval);
}
@@ -414,7 +422,7 @@ public Number getEndValue(int row, int column, int subinterval) {
* @return The percent complete.
*/
@Override
- public Number getPercentComplete(int series, int category) {
+ public Number getPercentComplete(@NonNegative int series, @NonNegative int category) {
return this.underlying.getPercentComplete(series,
category + this.firstCategoryIndex);
}
@@ -431,7 +439,7 @@ public Number getPercentComplete(int series, int category) {
* @see #getPercentComplete(Comparable, Comparable, int)
*/
@Override
- public Number getPercentComplete(int row, int column, int subinterval) {
+ public Number getPercentComplete(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval) {
return this.underlying.getPercentComplete(row,
column + this.firstCategoryIndex, subinterval);
}
@@ -449,7 +457,7 @@ public Number getPercentComplete(int row, int column, int subinterval) {
*/
@Override
public Number getStartValue(Comparable rowKey, Comparable columnKey,
- int subinterval) {
+ @NonNegative int subinterval) {
int r = getRowIndex(rowKey);
int c = getColumnIndex(columnKey);
if (c == -1) {
@@ -476,7 +484,7 @@ else if (r == -1) {
* @see #getEndValue(int, int, int)
*/
@Override
- public Number getStartValue(int row, int column, int subinterval) {
+ public Number getStartValue(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval) {
return this.underlying.getStartValue(row,
column + this.firstCategoryIndex, subinterval);
}
@@ -492,7 +500,7 @@ public Number getStartValue(int row, int column, int subinterval) {
* @see #getSubIntervalCount(int, int)
*/
@Override
- public int getSubIntervalCount(Comparable rowKey, Comparable columnKey) {
+ public @NonNegative int getSubIntervalCount(Comparable rowKey, Comparable columnKey) {
int r = getRowIndex(rowKey);
int c = getColumnIndex(columnKey);
if (c == -1) {
@@ -517,7 +525,7 @@ public int getSubIntervalCount(Comparable rowKey, Comparable columnKey) {
* @see #getSubIntervalCount(Comparable, Comparable)
*/
@Override
- public int getSubIntervalCount(int row, int column) {
+ public @NonNegative int getSubIntervalCount(@NonNegative int row, @NonNegative int column) {
return this.underlying.getSubIntervalCount(row,
column + this.firstCategoryIndex);
}
@@ -558,7 +566,7 @@ public Number getStartValue(Comparable rowKey, Comparable columnKey) {
* @see #getEndValue(int, int)
*/
@Override
- public Number getStartValue(int row, int column) {
+ public Number getStartValue(@NonNegative int row, @NonNegative int column) {
return this.underlying.getStartValue(row,
column + this.firstCategoryIndex);
}
@@ -596,7 +604,7 @@ public Number getEndValue(Comparable rowKey, Comparable columnKey) {
* @return The end value (possibly {@code null}).
*/
@Override
- public Number getEndValue(int series, int category) {
+ public Number getEndValue(@NonNegative int series, @NonNegative int category) {
return this.underlying.getEndValue(series,
category + this.firstCategoryIndex);
}
diff --git a/src/main/java/org/jfree/data/gantt/Task.java b/src/main/java/org/jfree/data/gantt/Task.java
index 9b2338de3..0d3145ce8 100644
--- a/src/main/java/org/jfree/data/gantt/Task.java
+++ b/src/main/java/org/jfree/data/gantt/Task.java
@@ -44,6 +44,8 @@
package org.jfree.data.gantt;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@@ -190,7 +192,7 @@ public void removeSubtask(Task subtask) {
*
* @return The sub-task count.
*/
- public int getSubtaskCount() {
+ public @NonNegative int getSubtaskCount() {
return this.subtasks.size();
}
@@ -201,7 +203,7 @@ public int getSubtaskCount() {
*
* @return The sub-task.
*/
- public Task getSubtask(int index) {
+ public Task getSubtask(@NonNegative int index) {
return (Task) this.subtasks.get(index);
}
diff --git a/src/main/java/org/jfree/data/gantt/TaskSeries.java b/src/main/java/org/jfree/data/gantt/TaskSeries.java
index 852266b64..5e30da466 100644
--- a/src/main/java/org/jfree/data/gantt/TaskSeries.java
+++ b/src/main/java/org/jfree/data/gantt/TaskSeries.java
@@ -46,6 +46,8 @@
package org.jfree.data.gantt;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.Collections;
import java.util.List;
import org.jfree.chart.util.ObjectUtils;
@@ -115,7 +117,7 @@ public void removeAll() {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.tasks.size();
}
@@ -126,7 +128,7 @@ public int getItemCount() {
*
* @return The task.
*/
- public Task get(int index) {
+ public Task get(@NonNegative int index) {
return (Task) this.tasks.get(index);
}
diff --git a/src/main/java/org/jfree/data/gantt/TaskSeriesCollection.java b/src/main/java/org/jfree/data/gantt/TaskSeriesCollection.java
index 7894844a5..7379e846d 100644
--- a/src/main/java/org/jfree/data/gantt/TaskSeriesCollection.java
+++ b/src/main/java/org/jfree/data/gantt/TaskSeriesCollection.java
@@ -51,6 +51,11 @@
package org.jfree.data.gantt;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
@@ -120,7 +125,7 @@ public TaskSeries getSeries(Comparable key) {
*
* @since 1.0.1
*/
- public TaskSeries getSeries(int series) {
+ public TaskSeries getSeries(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds");
}
@@ -133,7 +138,7 @@ public TaskSeries getSeries(int series) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return getRowCount();
}
@@ -145,7 +150,7 @@ public int getSeriesCount() {
* @return The name of a series.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
TaskSeries ts = (TaskSeries) this.data.get(series);
return ts.getKey();
}
@@ -156,7 +161,7 @@ public Comparable getSeriesKey(int series) {
* @return The series count.
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.data.size();
}
@@ -176,7 +181,8 @@ public List getRowKeys() {
* @return The column count.
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
return this.keys.size();
}
@@ -198,7 +204,7 @@ public List getColumnKeys() {
* @return The column key.
*/
@Override
- public Comparable getColumnKey(int index) {
+ public Comparable getColumnKey(@NonNegative int index) {
return (Comparable) this.keys.get(index);
}
@@ -210,7 +216,7 @@ public Comparable getColumnKey(int index) {
* @return The column index.
*/
@Override
- public int getColumnIndex(Comparable columnKey) {
+ public @GTENegativeOne int getColumnIndex(Comparable columnKey) {
Args.nullNotPermitted(columnKey, "columnKey");
return this.keys.indexOf(columnKey);
}
@@ -223,7 +229,7 @@ public int getColumnIndex(Comparable columnKey) {
* @return The index.
*/
@Override
- public int getRowIndex(Comparable rowKey) {
+ public @GTENegativeOne int getRowIndex(Comparable rowKey) {
int result = -1;
int count = this.data.size();
for (int i = 0; i < count; i++) {
@@ -244,7 +250,7 @@ public int getRowIndex(Comparable rowKey) {
* @return The key.
*/
@Override
- public Comparable getRowKey(int index) {
+ public Comparable getRowKey(@NonNegative int index) {
TaskSeries series = (TaskSeries) this.data.get(index);
return series.getKey();
}
@@ -297,7 +303,7 @@ public void remove(TaskSeries series) {
*
* @param series the series (zero based index).
*/
- public void remove(int series) {
+ public void remove(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException(
"TaskSeriesCollection.remove(): index outside valid range.");
@@ -354,7 +360,8 @@ public Number getValue(Comparable rowKey, Comparable columnKey) {
* @return The start value.
*/
@Override
- public Number getValue(int row, int column) {
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column) {
return getStartValue(row, column);
}
@@ -370,7 +377,8 @@ public Number getValue(int row, int column) {
@Override
public Number getStartValue(Comparable rowKey, Comparable columnKey) {
Number result = null;
- int row = getRowIndex(rowKey);
+ @SuppressWarnings("index") // rowKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int row = getRowIndex(rowKey);
TaskSeries series = (TaskSeries) this.data.get(row);
Task task = series.get(columnKey.toString());
if (task != null) {
@@ -391,7 +399,7 @@ public Number getStartValue(Comparable rowKey, Comparable columnKey) {
* @return The start value.
*/
@Override
- public Number getStartValue(int row, int column) {
+ public Number getStartValue(@NonNegative int row, @NonNegative int column) {
Comparable rowKey = getRowKey(row);
Comparable columnKey = getColumnKey(column);
return getStartValue(rowKey, columnKey);
@@ -409,7 +417,8 @@ public Number getStartValue(int row, int column) {
@Override
public Number getEndValue(Comparable rowKey, Comparable columnKey) {
Number result = null;
- int row = getRowIndex(rowKey);
+ @SuppressWarnings("index") // rowKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int row = getRowIndex(rowKey);
TaskSeries series = (TaskSeries) this.data.get(row);
Task task = series.get(columnKey.toString());
if (task != null) {
@@ -430,7 +439,7 @@ public Number getEndValue(Comparable rowKey, Comparable columnKey) {
* @return The end value.
*/
@Override
- public Number getEndValue(int row, int column) {
+ public Number getEndValue(@NonNegative int row, @NonNegative int column) {
Comparable rowKey = getRowKey(row);
Comparable columnKey = getColumnKey(column);
return getEndValue(rowKey, columnKey);
@@ -445,7 +454,7 @@ public Number getEndValue(int row, int column) {
* @return The percent complete (possibly {@code null}).
*/
@Override
- public Number getPercentComplete(int row, int column) {
+ public Number getPercentComplete(@NonNegative int row, @NonNegative int column) {
Comparable rowKey = getRowKey(row);
Comparable columnKey = getColumnKey(column);
return getPercentComplete(rowKey, columnKey);
@@ -462,7 +471,8 @@ public Number getPercentComplete(int row, int column) {
@Override
public Number getPercentComplete(Comparable rowKey, Comparable columnKey) {
Number result = null;
- int row = getRowIndex(rowKey);
+ @SuppressWarnings("index") // rowKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int row = getRowIndex(rowKey);
TaskSeries series = (TaskSeries) this.data.get(row);
Task task = series.get(columnKey.toString());
if (task != null) {
@@ -480,7 +490,7 @@ public Number getPercentComplete(Comparable rowKey, Comparable columnKey) {
* @return The sub-interval count.
*/
@Override
- public int getSubIntervalCount(int row, int column) {
+ public @NonNegative int getSubIntervalCount(@NonNegative int row, @NonNegative int column) {
Comparable rowKey = getRowKey(row);
Comparable columnKey = getColumnKey(column);
return getSubIntervalCount(rowKey, columnKey);
@@ -495,9 +505,10 @@ public int getSubIntervalCount(int row, int column) {
* @return The sub-interval count.
*/
@Override
- public int getSubIntervalCount(Comparable rowKey, Comparable columnKey) {
+ public @NonNegative int getSubIntervalCount(Comparable rowKey, Comparable columnKey) {
int result = 0;
- int row = getRowIndex(rowKey);
+ @SuppressWarnings("index") // rowKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int row = getRowIndex(rowKey);
TaskSeries series = (TaskSeries) this.data.get(row);
Task task = series.get(columnKey.toString());
if (task != null) {
@@ -516,7 +527,7 @@ public int getSubIntervalCount(Comparable rowKey, Comparable columnKey) {
* @return The start value (possibly {@code null}).
*/
@Override
- public Number getStartValue(int row, int column, int subinterval) {
+ public Number getStartValue(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval) {
Comparable rowKey = getRowKey(row);
Comparable columnKey = getColumnKey(column);
return getStartValue(rowKey, columnKey, subinterval);
@@ -533,9 +544,10 @@ public Number getStartValue(int row, int column, int subinterval) {
*/
@Override
public Number getStartValue(Comparable rowKey, Comparable columnKey,
- int subinterval) {
+ @NonNegative int subinterval) {
Number result = null;
- int row = getRowIndex(rowKey);
+ @SuppressWarnings("index") // rowKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int row = getRowIndex(rowKey);
TaskSeries series = (TaskSeries) this.data.get(row);
Task task = series.get(columnKey.toString());
if (task != null) {
@@ -558,7 +570,7 @@ public Number getStartValue(Comparable rowKey, Comparable columnKey,
* @return The end value (possibly {@code null}).
*/
@Override
- public Number getEndValue(int row, int column, int subinterval) {
+ public Number getEndValue(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval) {
Comparable rowKey = getRowKey(row);
Comparable columnKey = getColumnKey(column);
return getEndValue(rowKey, columnKey, subinterval);
@@ -575,9 +587,10 @@ public Number getEndValue(int row, int column, int subinterval) {
*/
@Override
public Number getEndValue(Comparable rowKey, Comparable columnKey,
- int subinterval) {
+ @NonNegative int subinterval) {
Number result = null;
- int row = getRowIndex(rowKey);
+ @SuppressWarnings("index") // rowKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int row = getRowIndex(rowKey);
TaskSeries series = (TaskSeries) this.data.get(row);
Task task = series.get(columnKey.toString());
if (task != null) {
@@ -600,7 +613,7 @@ public Number getEndValue(Comparable rowKey, Comparable columnKey,
* @return The percent complete value (possibly {@code null}).
*/
@Override
- public Number getPercentComplete(int row, int column, int subinterval) {
+ public Number getPercentComplete(@NonNegative int row, @NonNegative int column, @NonNegative int subinterval) {
Comparable rowKey = getRowKey(row);
Comparable columnKey = getColumnKey(column);
return getPercentComplete(rowKey, columnKey, subinterval);
@@ -617,9 +630,10 @@ public Number getPercentComplete(int row, int column, int subinterval) {
*/
@Override
public Number getPercentComplete(Comparable rowKey, Comparable columnKey,
- int subinterval) {
+ @NonNegative int subinterval) {
Number result = null;
- int row = getRowIndex(rowKey);
+ @SuppressWarnings("index") // rowKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int row = getRowIndex(rowKey);
TaskSeries series = (TaskSeries) this.data.get(row);
Task task = series.get(columnKey.toString());
if (task != null) {
diff --git a/src/main/java/org/jfree/data/gantt/XYTaskDataset.java b/src/main/java/org/jfree/data/gantt/XYTaskDataset.java
index 3f4a27894..8ca740b08 100644
--- a/src/main/java/org/jfree/data/gantt/XYTaskDataset.java
+++ b/src/main/java/org/jfree/data/gantt/XYTaskDataset.java
@@ -41,6 +41,10 @@
package org.jfree.data.gantt;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.Date;
import org.jfree.chart.axis.SymbolAxis;
@@ -157,7 +161,7 @@ public void setTransposed(boolean transposed) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.underlying.getSeriesCount();
}
@@ -169,7 +173,7 @@ public int getSeriesCount() {
* @return The name of a series.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
return this.underlying.getSeriesKey(series);
}
@@ -181,7 +185,8 @@ public Comparable getSeriesKey(int series) {
* @return The item count.
*/
@Override
- public int getItemCount(int series) {
+ @SuppressWarnings("index") // array-list interop: The underlying representation here is a mutable collection, but this annotation is needed to match the interface
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
return this.underlying.getSeries(series).getItemCount();
}
@@ -194,7 +199,7 @@ public int getItemCount(int series) {
* @return The value.
*/
@Override
- public double getXValue(int series, int item) {
+ public double getXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
if (!this.transposed) {
return getSeriesValue(series);
}
@@ -214,7 +219,7 @@ public double getXValue(int series, int item) {
* @return The start date/time.
*/
@Override
- public double getStartXValue(int series, int item) {
+ public double getStartXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
if (!this.transposed) {
return getSeriesStartValue(series);
}
@@ -234,7 +239,7 @@ public double getStartXValue(int series, int item) {
* @return The end date/time.
*/
@Override
- public double getEndXValue(int series, int item) {
+ public double getEndXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
if (!this.transposed) {
return getSeriesEndValue(series);
}
@@ -252,7 +257,7 @@ public double getEndXValue(int series, int item) {
* @return The x-value (in milliseconds).
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getXValue(series, item));
}
@@ -267,7 +272,7 @@ public Number getX(int series, int item) {
* @return The start date/time.
*/
@Override
- public Number getStartX(int series, int item) {
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getStartXValue(series, item));
}
@@ -282,7 +287,7 @@ public Number getStartX(int series, int item) {
* @return The end date/time.
*/
@Override
- public Number getEndX(int series, int item) {
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getEndXValue(series, item));
}
@@ -295,7 +300,7 @@ public Number getEndX(int series, int item) {
* @return The value.
*/
@Override
- public double getYValue(int series, int item) {
+ public double getYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
if (!this.transposed) {
return getItemValue(series, item);
}
@@ -314,7 +319,7 @@ public double getYValue(int series, int item) {
* @return The y-interval start.
*/
@Override
- public double getStartYValue(int series, int item) {
+ public double getStartYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
if (!this.transposed) {
return getItemStartValue(series, item);
}
@@ -333,7 +338,7 @@ public double getStartYValue(int series, int item) {
* @return The y-interval end.
*/
@Override
- public double getEndYValue(int series, int item) {
+ public double getEndYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
if (!this.transposed) {
return getItemEndValue(series, item);
}
@@ -353,7 +358,7 @@ public double getEndYValue(int series, int item) {
* @return The y-value.
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getYValue(series, item));
}
@@ -367,7 +372,7 @@ public Number getY(int series, int item) {
* @return The y-interval start.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getStartYValue(series, item));
}
@@ -381,23 +386,23 @@ public Number getStartY(int series, int item) {
* @return The y-interval end.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getEndYValue(series, item));
}
- private double getSeriesValue(int series) {
+ private double getSeriesValue(@NonNegative int series) {
return series;
}
- private double getSeriesStartValue(int series) {
+ private double getSeriesStartValue(@NonNegative int series) {
return series - this.seriesWidth / 2.0;
}
- private double getSeriesEndValue(int series) {
+ private double getSeriesEndValue(@NonNegative int series) {
return series + this.seriesWidth / 2.0;
}
- private double getItemValue(int series, int item) {
+ private double getItemValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TaskSeries s = this.underlying.getSeries(series);
Task t = s.get(item);
TimePeriod duration = t.getDuration();
@@ -406,7 +411,7 @@ private double getItemValue(int series, int item) {
return (start.getTime() + end.getTime()) / 2.0;
}
- private double getItemStartValue(int series, int item) {
+ private double getItemStartValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TaskSeries s = this.underlying.getSeries(series);
Task t = s.get(item);
TimePeriod duration = t.getDuration();
@@ -414,7 +419,7 @@ private double getItemStartValue(int series, int item) {
return start.getTime();
}
- private double getItemEndValue(int series, int item) {
+ private double getItemEndValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TaskSeries s = this.underlying.getSeries(series);
Task t = s.get(item);
TimePeriod duration = t.getDuration();
diff --git a/src/main/java/org/jfree/data/general/AbstractSeriesDataset.java b/src/main/java/org/jfree/data/general/AbstractSeriesDataset.java
index 060ee959d..b3cb30355 100644
--- a/src/main/java/org/jfree/data/general/AbstractSeriesDataset.java
+++ b/src/main/java/org/jfree/data/general/AbstractSeriesDataset.java
@@ -44,6 +44,10 @@
package org.jfree.data.general;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
/**
@@ -69,7 +73,7 @@ protected AbstractSeriesDataset() {
* @return The series count.
*/
@Override
- public abstract int getSeriesCount();
+ public abstract @NonNegative int getSeriesCount();
/**
* Returns the key for a series.
@@ -84,7 +88,7 @@ protected AbstractSeriesDataset() {
* @return The series key.
*/
@Override
- public abstract Comparable getSeriesKey(int series);
+ public abstract Comparable getSeriesKey(@NonNegative int series);
/**
* Returns the index of the named series, or -1.
@@ -94,7 +98,7 @@ protected AbstractSeriesDataset() {
* @return The index.
*/
@Override
- public int indexOf(Comparable seriesKey) {
+ public @GTENegativeOne int indexOf(Comparable seriesKey) {
int seriesCount = getSeriesCount();
for (int s = 0; s < seriesCount; s++) {
if (getSeriesKey(s).equals(seriesKey)) {
@@ -114,4 +118,12 @@ public void seriesChanged(SeriesChangeEvent event) {
fireDatasetChanged();
}
+ /**
+ * This is a ghost method that should never be called. It is used only in annotations
+ * to represent the conceptual "series" that the dataset provides.
+ */
+ @Override
+ public Series getSeries(@NonNegative int series) throws Exception{
+ throw new Exception("unimplemented");
+ }
}
diff --git a/src/main/java/org/jfree/data/general/DatasetUtils.java b/src/main/java/org/jfree/data/general/DatasetUtils.java
index 57fedbdb6..85b3d1fec 100644
--- a/src/main/java/org/jfree/data/general/DatasetUtils.java
+++ b/src/main/java/org/jfree/data/general/DatasetUtils.java
@@ -129,6 +129,12 @@
package org.jfree.data.general;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -213,7 +219,8 @@ public static double calculatePieDatasetTotal(PieDataset dataset) {
*/
public static PieDataset createPieDatasetForRow(CategoryDataset dataset,
Comparable rowKey) {
- int row = dataset.getRowIndex(rowKey);
+ @SuppressWarnings("index") // rowKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int row = dataset.getRowIndex(rowKey);
return createPieDatasetForRow(dataset, row);
}
@@ -227,7 +234,7 @@ public static PieDataset createPieDatasetForRow(CategoryDataset dataset,
* @return A pie dataset.
*/
public static PieDataset createPieDatasetForRow(CategoryDataset dataset,
- int row) {
+ @NonNegative int row) {
DefaultPieDataset result = new DefaultPieDataset();
int columnCount = dataset.getColumnCount();
for (int current = 0; current < columnCount; current++) {
@@ -248,7 +255,8 @@ public static PieDataset createPieDatasetForRow(CategoryDataset dataset,
*/
public static PieDataset createPieDatasetForColumn(CategoryDataset dataset,
Comparable columnKey) {
- int column = dataset.getColumnIndex(columnKey);
+ @SuppressWarnings("index") // columnKey is being assumed to be a valid key. It should probably be checked - this is a bug
+ @NonNegative int column = dataset.getColumnIndex(columnKey);
return createPieDatasetForColumn(dataset, column);
}
@@ -262,7 +270,7 @@ public static PieDataset createPieDatasetForColumn(CategoryDataset dataset,
* @return A pie dataset.
*/
public static PieDataset createPieDatasetForColumn(CategoryDataset dataset,
- int column) {
+ @NonNegative int column) {
DefaultPieDataset result = new DefaultPieDataset();
int rowCount = dataset.getRowCount();
for (int i = 0; i < rowCount; i++) {
@@ -422,8 +430,8 @@ public static CategoryDataset createCategoryDataset(String rowKeyPrefix,
*
* @return The dataset.
*/
- public static CategoryDataset createCategoryDataset(Comparable[] rowKeys,
- Comparable[] columnKeys, double[][] data) {
+ public static CategoryDataset createCategoryDataset(Comparable @SameLen("#3") [] rowKeys,
+ Comparable[] columnKeys, double @SameLen("#1") [] @SameLen("#2") [] data) {
Args.nullNotPermitted(rowKeys, "rowKeys");
Args.nullNotPermitted(columnKeys, "columnKeys");
@@ -498,7 +506,7 @@ public static CategoryDataset createCategoryDataset(Comparable rowKey,
* @return A dataset.
*/
public static XYDataset sampleFunction2D(Function2D f, double start,
- double end, int samples, Comparable seriesKey) {
+ double end, @Positive int samples, Comparable seriesKey) {
// defer argument checking
XYSeries series = sampleFunction2DToSeries(f, start, end, samples,
@@ -523,7 +531,7 @@ public static XYDataset sampleFunction2D(Function2D f, double start,
* @since 1.0.13
*/
public static XYSeries sampleFunction2DToSeries(Function2D f,
- double start, double end, int samples, Comparable seriesKey) {
+ double start, double end, @Positive int samples, Comparable seriesKey) {
Args.nullNotPermitted(f, "f");
Args.nullNotPermitted(seriesKey, "seriesKey");
@@ -733,7 +741,7 @@ public static Range iterateDomainBounds(XYDataset dataset,
if (includeInterval && dataset instanceof IntervalXYDataset) {
IntervalXYDataset intervalXYData = (IntervalXYDataset) dataset;
for (int series = 0; series < seriesCount; series++) {
- int itemCount = dataset.getItemCount(series);
+ int itemCount = intervalXYData.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double value = intervalXYData.getXValue(series, item);
lvalue = intervalXYData.getStartXValue(series, item);
@@ -1020,7 +1028,8 @@ public static Range iterateToFindRangeBounds(CategoryDataset dataset,
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.getRowIndex(seriesKey);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.getRowIndex(seriesKey);
int itemCount = dataset.getColumnCount();
for (int item = 0; item < itemCount; item++) {
Number lvalue = bx.getMinRegularValue(series, item);
@@ -1049,7 +1058,8 @@ else if (includeInterval
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.getRowIndex(seriesKey);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.getRowIndex(seriesKey);
for (int column = 0; column < columnCount; column++) {
lvalue = icd.getStartValue(series, column);
uvalue = icd.getEndValue(series, column);
@@ -1071,7 +1081,8 @@ else if (includeInterval
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.getRowIndex(seriesKey);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.getRowIndex(seriesKey);
for (int column = 0; column < columnCount; column++) {
List values = mvcd.getValues(series, column);
Iterator valueIterator = values.iterator();
@@ -1097,7 +1108,8 @@ else if (includeInterval
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.getRowIndex(seriesKey);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.getRowIndex(seriesKey);
for (int column = 0; column < columnCount; column++) {
Number meanN = scd.getMeanValue(series, column);
if (meanN != null) {
@@ -1123,7 +1135,8 @@ else if (includeInterval
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.getRowIndex(seriesKey);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.getRowIndex(seriesKey);
for (int column = 0; column < columnCount; column++) {
Number value = dataset.getValue(series, column);
if (value != null) {
@@ -1182,7 +1195,7 @@ public static Range iterateRangeBounds(XYDataset dataset,
// handle special case of IntervalXYDataset
IntervalXYDataset ixyd = (IntervalXYDataset) dataset;
for (int series = 0; series < seriesCount; series++) {
- int itemCount = dataset.getItemCount(series);
+ int itemCount = ixyd.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double value = ixyd.getYValue(series, item);
double lvalue = ixyd.getStartYValue(series, item);
@@ -1206,7 +1219,7 @@ else if (includeInterval && dataset instanceof OHLCDataset) {
// handle special case of OHLCDataset
OHLCDataset ohlc = (OHLCDataset) dataset;
for (int series = 0; series < seriesCount; series++) {
- int itemCount = dataset.getItemCount(series);
+ int itemCount = ohlc.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double lvalue = ohlc.getLowValue(series, item);
double uvalue = ohlc.getHighValue(series, item);
@@ -1370,8 +1383,9 @@ public static Range iterateToFindDomainBounds(XYDataset dataset,
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.indexOf(seriesKey);
- int itemCount = dataset.getItemCount(series);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.indexOf(seriesKey);
+ int itemCount = ixyd.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double xvalue = ixyd.getXValue(series, item);
double lvalue = ixyd.getStartXValue(series, item);
@@ -1393,7 +1407,8 @@ public static Range iterateToFindDomainBounds(XYDataset dataset,
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.indexOf(seriesKey);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.indexOf(seriesKey);
int itemCount = dataset.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double x = dataset.getXValue(series, item);
@@ -1446,8 +1461,9 @@ public static Range iterateToFindRangeBounds(XYDataset dataset,
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.indexOf(seriesKey);
- int itemCount = dataset.getItemCount(series);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.indexOf(seriesKey);
+ int itemCount = ohlc.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double x = ohlc.getXValue(series, item);
if (xRange.contains(x)) {
@@ -1469,8 +1485,9 @@ else if (includeInterval && dataset instanceof BoxAndWhiskerXYDataset) {
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.indexOf(seriesKey);
- int itemCount = dataset.getItemCount(series);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.indexOf(seriesKey);
+ int itemCount = bx.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double x = bx.getXValue(series, item);
if (xRange.contains(x)) {
@@ -1492,8 +1509,9 @@ else if (includeInterval && dataset instanceof IntervalXYDataset) {
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.indexOf(seriesKey);
- int itemCount = dataset.getItemCount(series);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.indexOf(seriesKey);
+ int itemCount = ixyd.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double x = ixyd.getXValue(series, item);
if (xRange.contains(x)) {
@@ -1518,7 +1536,8 @@ else if (includeInterval && dataset instanceof IntervalXYDataset) {
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.indexOf(seriesKey);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.indexOf(seriesKey);
int itemCount = dataset.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double x = dataset.getXValue(series, item);
@@ -1566,7 +1585,8 @@ public static Range iterateToFindZBounds(XYZDataset dataset,
Iterator iterator = visibleSeriesKeys.iterator();
while (iterator.hasNext()) {
Comparable seriesKey = (Comparable) iterator.next();
- int series = dataset.indexOf(seriesKey);
+ @SuppressWarnings("index") // guaranteed index: guaranteed to be an index since getRowIndex called on a key known to be in the dataset
+ @NonNegative int series = dataset.indexOf(seriesKey);
int itemCount = dataset.getItemCount(series);
for (int item = 0; item < itemCount; item++) {
double x = dataset.getXValue(series, item);
@@ -1619,7 +1639,9 @@ public static Number findMinimumDomainValue(XYDataset dataset) {
if (dataset instanceof IntervalXYDataset) {
IntervalXYDataset intervalXYData
= (IntervalXYDataset) dataset;
- value = intervalXYData.getStartXValue(series, item);
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ double valueTmp = intervalXYData.getStartXValue(series, item);
+ value = valueTmp;
}
else {
value = dataset.getXValue(series, item);
@@ -1674,7 +1696,9 @@ public static Number findMaximumDomainValue(XYDataset dataset) {
if (dataset instanceof IntervalXYDataset) {
IntervalXYDataset intervalXYData
= (IntervalXYDataset) dataset;
- value = intervalXYData.getEndXValue(series, item);
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ double valueTmp = intervalXYData.getEndXValue(series, item);
+ value = valueTmp;
}
else {
value = dataset.getXValue(series, item);
@@ -1726,7 +1750,8 @@ public static Number findMinimumRangeValue(CategoryDataset dataset) {
if (dataset instanceof IntervalCategoryDataset) {
IntervalCategoryDataset icd
= (IntervalCategoryDataset) dataset;
- value = icd.getStartValue(series, item);
+ Number valueTmp = icd.getStartValue(series, item);
+ value = valueTmp;
}
else {
value = dataset.getValue(series, item);
@@ -1780,11 +1805,15 @@ public static Number findMinimumRangeValue(XYDataset dataset) {
if (dataset instanceof IntervalXYDataset) {
IntervalXYDataset intervalXYData
= (IntervalXYDataset) dataset;
- value = intervalXYData.getStartYValue(series, item);
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ double valueTmp = intervalXYData.getStartYValue(series, item);
+ value = valueTmp;
}
else if (dataset instanceof OHLCDataset) {
OHLCDataset highLowData = (OHLCDataset) dataset;
- value = highLowData.getLowValue(series, item);
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ double valueTmp = highLowData.getLowValue(series, item);
+ value = valueTmp;
}
else {
value = dataset.getYValue(series, item);
@@ -1893,11 +1922,15 @@ public static Number findMaximumRangeValue(XYDataset dataset) {
if (dataset instanceof IntervalXYDataset) {
IntervalXYDataset intervalXYData
= (IntervalXYDataset) dataset;
- value = intervalXYData.getEndYValue(series, item);
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ double valueTmp = intervalXYData.getEndYValue(series, item);
+ value = valueTmp;
}
else if (dataset instanceof OHLCDataset) {
OHLCDataset highLowData = (OHLCDataset) dataset;
- value = highLowData.getHighValue(series, item);
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212
+ double valueTmp = highLowData.getHighValue(series, item);
+ value = valueTmp;
}
else {
value = dataset.getYValue(series, item);
@@ -1990,8 +2023,9 @@ public static Range findStackedRangeBounds(CategoryDataset dataset,
Range result = null;
// create an array holding the group indices for each series...
- int[] groupIndex = new int[dataset.getRowCount()];
- for (int i = 0; i < dataset.getRowCount(); i++) {
+ int rowCount = dataset.getRowCount();
+ int[] groupIndex = new int[rowCount];
+ for (int i = 0; i < rowCount; i++) {
groupIndex[i] = map.getGroupIndex(map.getGroup(
dataset.getRowKey(i)));
}
@@ -2005,19 +2039,20 @@ public static Range findStackedRangeBounds(CategoryDataset dataset,
for (int item = 0; item < categoryCount; item++) {
double[] positive = new double[groupCount];
double[] negative = new double[groupCount];
- int seriesCount = dataset.getRowCount();
- for (int series = 0; series < seriesCount; series++) {
+ for (int series = 0; series < rowCount; series++) {
Number number = dataset.getValue(series, item);
if (number != null) {
hasValidData = true;
double value = number.doubleValue();
+ @SuppressWarnings("index") // group indices are all <= group count by definition
+ @IndexFor({"positive", "negative", "maximum", "minimum"}) int groupIndexTmp = groupIndex[series];
if (value > 0.0) {
- positive[groupIndex[series]]
- = positive[groupIndex[series]] + value;
+ positive[groupIndexTmp]
+ = positive[groupIndexTmp] + value;
}
if (value < 0.0) {
- negative[groupIndex[series]]
- = negative[groupIndex[series]] + value;
+ negative[groupIndexTmp]
+ = negative[groupIndexTmp] + value;
// '+', remember value is negative
}
}
@@ -2142,6 +2177,7 @@ public static Range findStackedRangeBounds(TableXYDataset dataset,
double negative = base;
int seriesCount = dataset.getSeriesCount();
for (int seriesNo = 0; seriesNo < seriesCount; seriesNo++) {
+ @SuppressWarnings("index") // all the series of a TableXYDataset have the same length
double y = dataset.getYValue(seriesNo, itemNo);
if (!Double.isNaN(y)) {
if (y > 0.0) {
@@ -2178,10 +2214,11 @@ public static Range findStackedRangeBounds(TableXYDataset dataset,
*
* @since 1.0.5
*/
- public static double calculateStackTotal(TableXYDataset dataset, int item) {
+ public static double calculateStackTotal(TableXYDataset dataset, @NonNegative int item) {
double total = 0.0;
int seriesCount = dataset.getSeriesCount();
for (int s = 0; s < seriesCount; s++) {
+ @SuppressWarnings("index") // This assumes that all series in the dataset have the same number of items
double value = dataset.getYValue(s, item);
if (!Double.isNaN(value)) {
total = total + value;
@@ -2243,19 +2280,25 @@ public static Range findCumulativeRangeBounds(CategoryDataset dataset) {
*
* @since 1.0.16
*/
- public static double findYValue(XYDataset dataset, int series, double x) {
+ public static double findYValue(XYDataset dataset, @NonNegative int series, double x) {
// delegate null check on dataset
- int[] indices = findItemIndicesForX(dataset, series, x);
+ @IndexOrLow("dataset.getSeries(series)") int[] indices = findItemIndicesForX(dataset, series, x);
if (indices[0] == -1) {
return Double.NaN;
}
- if (indices[0] == indices[1]) {
- return dataset.getYValue(series, indices[0]);
+
+ @IndexFor("dataset.getSeries(series)") int indices0 = indices[0];
+
+ @SuppressWarnings("index") // guaranteed index: the check above is sufficient to establish that no entries in indices are negative, since the values are correlated.
+ @IndexFor("dataset.getSeries(series)") int indices1 = indices[1];
+
+ if (indices0 == indices1) {
+ return dataset.getYValue(series, indices0);
}
- double x0 = dataset.getXValue(series, indices[0]);
- double x1 = dataset.getXValue(series, indices[1]);
- double y0 = dataset.getYValue(series, indices[0]);
- double y1 = dataset.getYValue(series, indices[1]);
+ double x0 = dataset.getXValue(series, indices0);
+ double x1 = dataset.getXValue(series, indices1);
+ double y0 = dataset.getYValue(series, indices0);
+ double y1 = dataset.getYValue(series, indices1);
return y0 + (y1 - y0) * (x - x0) / (x1 - x0);
}
@@ -2280,7 +2323,7 @@ public static double findYValue(XYDataset dataset, int series, double x) {
*
* @see #findYValue(org.jfree.data.xy.XYDataset, int, double)
*/
- public static int[] findItemIndicesForX(XYDataset dataset, int series,
+ public static @IndexOrLow("#1.getSeries(#2)") int @ArrayLen(2) [] findItemIndicesForX(XYDataset dataset, @NonNegative int series,
double x) {
Args.nullNotPermitted(dataset, "dataset");
int itemCount = dataset.getItemCount(series);
@@ -2288,15 +2331,19 @@ public static int[] findItemIndicesForX(XYDataset dataset, int series,
return new int[] {-1, -1};
}
if (itemCount == 1) {
- if (x == dataset.getXValue(series, 0)) {
- return new int[] {0, 0};
+ @SuppressWarnings("index") // 0 is a valid index, because itemCount > 1
+ @IndexFor("dataset.getSeries(series)") int zero = 0;
+ double xValue = dataset.getXValue(series, zero);
+ if (x == xValue) {
+ return new int[] {zero, zero};
} else {
return new int[] {-1, -1};
}
}
if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
- int low = 0;
- int high = itemCount - 1;
+ @SuppressWarnings("index") // 0 is a valid index, because itemCount > 1
+ @IndexFor("dataset.getSeries(series)") int low = 0;
+ @IndexFor("dataset.getSeries(series)") int high = itemCount - 1;
double lowValue = dataset.getXValue(series, low);
if (lowValue > x) {
return new int[] {-1, -1};
@@ -2328,8 +2375,9 @@ public static int[] findItemIndicesForX(XYDataset dataset, int series,
return new int[] {low, high};
}
else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
- int high = 0;
- int low = itemCount - 1;
+ @SuppressWarnings("index") // 0 is a valid index, because itemCount > 1
+ @IndexFor("dataset.getSeries(series)") int high = 0;
+ @IndexFor("dataset.getSeries(series)") int low = itemCount - 1;
double lowValue = dataset.getXValue(series, low);
if (lowValue > x) {
return new int[] {-1, -1};
@@ -2358,9 +2406,11 @@ else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
// we don't know anything about the ordering of the x-values,
// so we iterate until we find the first crossing of x (if any)
// we know there are at least 2 items in the series at this point
- double prev = dataset.getXValue(series, 0);
+ @SuppressWarnings("index") // 0 is a valid index, because itemCount > 1
+ @IndexFor("dataset.getSeries(series)") int zero = 0;
+ double prev = dataset.getXValue(series, zero);
if (x == prev) {
- return new int[] {0, 0}; // exact match on first item
+ return new int[] {zero, zero}; // exact match on first item
}
for (int i = 1; i < itemCount; i++) {
double next = dataset.getXValue(series, i);
diff --git a/src/main/java/org/jfree/data/general/DefaultHeatMapDataset.java b/src/main/java/org/jfree/data/general/DefaultHeatMapDataset.java
index cd09f2938..77977c870 100644
--- a/src/main/java/org/jfree/data/general/DefaultHeatMapDataset.java
+++ b/src/main/java/org/jfree/data/general/DefaultHeatMapDataset.java
@@ -40,6 +40,9 @@
package org.jfree.data.general;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
import java.io.Serializable;
import org.jfree.chart.util.PublicCloneable;
import org.jfree.data.DataUtils;
@@ -53,10 +56,10 @@ public class DefaultHeatMapDataset extends AbstractDataset
implements HeatMapDataset, Cloneable, PublicCloneable, Serializable {
/** The number of samples in this dataset for the x-dimension. */
- private int xSamples;
+ private @Positive @LTEqLengthOf("this.getData()") int xSamples;
/** The number of samples in this dataset for the y-dimension. */
- private int ySamples;
+ private @Positive @LTEqLengthOf("this.getData()[0]") int ySamples;
/** The minimum x-value in the dataset. */
private double minX;
@@ -71,7 +74,7 @@ public class DefaultHeatMapDataset extends AbstractDataset
private double maxY;
/** Storage for the z-values. */
- private double[][] zValues;
+ private double @MinLen(1) @SameLen("this.getData()") [] @MinLen(1) @SameLen("this.getData()[0]") [] zValues;
/**
* Creates a new dataset where all the z-values are initially 0. This is
@@ -84,7 +87,7 @@ public class DefaultHeatMapDataset extends AbstractDataset
* @param minY the minimum y-value in the dataset.
* @param maxY the maximum y-value in the dataset.
*/
- public DefaultHeatMapDataset(int xSamples, int ySamples, double minX,
+ public DefaultHeatMapDataset(@Positive int xSamples, @Positive int ySamples, double minX,
double maxX, double minY, double maxY) {
if (xSamples < 1) {
@@ -106,15 +109,23 @@ public DefaultHeatMapDataset(int xSamples, int ySamples, double minX,
throw new IllegalArgumentException("'maxY' cannot be INF or NaN.");
}
- this.xSamples = xSamples;
- this.ySamples = ySamples;
+ @SuppressWarnings("index") // establishing invariant of a ghost method
+ @Positive @LTEqLengthOf("this.getData()") int xSamplesTmp = xSamples;
+ this.xSamples = xSamplesTmp;
+ @SuppressWarnings("index") // establishing invariant of a ghost method
+ @Positive @LTEqLengthOf("this.getData()[0]") int ySamplesTmp = ySamples;
+ this.ySamples = ySamplesTmp;
this.minX = minX;
this.maxX = maxX;
this.minY = minY;
this.maxY = maxY;
- this.zValues = new double[xSamples][];
+ @SuppressWarnings({"index", "value"}) // establishing invariant of a ghost method: since ySamples is positive and will be used to create each inner array, the MinLen is true
+ double @SameLen("this.getData()") [] @SameLen("this.getData()[0]") @MinLen(1) [] zValues = new double[xSamples][];
+ this.zValues = zValues;
for (int x = 0; x < xSamples; x++) {
- this.zValues[x] = new double[ySamples];
+ @SuppressWarnings("index") // establishing invariant of a ghost method
+ double @SameLen("this.getData()[0]") [] zValuesX = new double[ySamples];
+ this.zValues[x] = zValuesX;
}
}
@@ -126,7 +137,7 @@ public DefaultHeatMapDataset(int xSamples, int ySamples, double minX,
* @return The number of x-values (always > 0).
*/
@Override
- public int getXSampleCount() {
+ public @Positive @LTEqLengthOf("this.getData()") int getXSampleCount() {
return this.xSamples;
}
@@ -138,7 +149,7 @@ public int getXSampleCount() {
* @return The number of y-values (always > 0).
*/
@Override
- public int getYSampleCount() {
+ public @Positive @LTEqLengthOf("this.getData()[0]") int getYSampleCount() {
return this.ySamples;
}
@@ -198,7 +209,7 @@ public double getMaximumYValue() {
* @return The x-value.
*/
@Override
- public double getXValue(int xIndex) {
+ public double getXValue(@NonNegative int xIndex) {
double x = this.minX
+ (this.maxX - this.minX) * (xIndex / (double) this.xSamples);
return x;
@@ -212,7 +223,7 @@ public double getXValue(int xIndex) {
* @return The y-value.
*/
@Override
- public double getYValue(int yIndex) {
+ public double getYValue(@NonNegative int yIndex) {
double y = this.minY
+ (this.maxY - this.minY) * (yIndex / (double) this.ySamples);
return y;
@@ -228,7 +239,7 @@ public double getYValue(int yIndex) {
* @return The z-value.
*/
@Override
- public double getZValue(int xIndex, int yIndex) {
+ public double getZValue(@IndexFor("this.getData()") int xIndex, @IndexFor("this.getData()[0]") int yIndex) {
return this.zValues[xIndex][yIndex];
}
@@ -244,10 +255,18 @@ public double getZValue(int xIndex, int yIndex) {
* @return The z-value.
*/
@Override
- public Number getZ(int xIndex, int yIndex) {
+ public Number getZ(@IndexFor("this.getData()") int xIndex, @IndexFor("this.getData()[0]") int yIndex) {
return new Double(getZValue(xIndex, yIndex));
}
+ /**
+ * This is a ghost method. Implementations should return null.
+ */
+ @Override
+ public double @MinLen(1) [] @MinLen(1) [] getData() {
+ return null;
+ }
+
/**
* Updates a z-value in the dataset and sends a {@link DatasetChangeEvent}
* to all registered listeners.
@@ -256,7 +275,7 @@ public Number getZ(int xIndex, int yIndex) {
* @param yIndex the y-index.
* @param z the new z-value.
*/
- public void setZValue(int xIndex, int yIndex, double z) {
+ public void setZValue(@IndexFor("this.getData()") int xIndex, @IndexFor("this.getData()[0]") int yIndex, double z) {
setZValue(xIndex, yIndex, z, true);
}
@@ -269,7 +288,7 @@ public void setZValue(int xIndex, int yIndex, double z) {
* @param z the new z-value.
* @param notify notify listeners?
*/
- public void setZValue(int xIndex, int yIndex, double z, boolean notify) {
+ public void setZValue(@IndexFor("this.getData()") int xIndex, @IndexFor("this.getData()[0]") int yIndex, double z, boolean notify) {
this.zValues[xIndex][yIndex] = z;
if (notify) {
fireDatasetChanged();
@@ -326,6 +345,7 @@ public boolean equals(Object obj) {
* cloning.
*/
@Override
+ @SuppressWarnings({"index", "value"}) // clone's internal state and this object's internal state are the same. Not inferred by SameLen Checker.
public Object clone() throws CloneNotSupportedException {
DefaultHeatMapDataset clone = (DefaultHeatMapDataset) super.clone();
clone.zValues = DataUtils.clone(this.zValues);
diff --git a/src/main/java/org/jfree/data/general/DefaultPieDataset.java b/src/main/java/org/jfree/data/general/DefaultPieDataset.java
index 7078722ce..5bda8893e 100644
--- a/src/main/java/org/jfree/data/general/DefaultPieDataset.java
+++ b/src/main/java/org/jfree/data/general/DefaultPieDataset.java
@@ -57,6 +57,9 @@
package org.jfree.data.general;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
@@ -107,7 +110,7 @@ public DefaultPieDataset(KeyedValues data) {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.data.getItemCount();
}
@@ -134,7 +137,7 @@ public List getKeys() {
* specified range.
*/
@Override
- public Comparable getKey(int item) {
+ public Comparable getKey(@NonNegative int item) {
return this.data.getKey(item);
}
@@ -149,7 +152,7 @@ public Comparable getKey(int item) {
* {@code null}.
*/
@Override
- public int getIndex(Comparable key) {
+ public @GTENegativeOne int getIndex(Comparable key) {
return this.data.getIndex(key);
}
@@ -161,7 +164,7 @@ public int getIndex(Comparable key) {
* @return The value (possibly {@code null}).
*/
@Override
- public Number getValue(int item) {
+ public Number getValue(@NonNegative int item) {
Number result = null;
if (getItemCount() > item) {
result = this.data.getValue(item);
@@ -226,7 +229,7 @@ public void setValue(Comparable key, double value) {
*
* @since 1.0.6
*/
- public void insertValue(int position, Comparable key, double value) {
+ public void insertValue(@NonNegative int position, Comparable key, double value) {
insertValue(position, key, new Double(value));
}
@@ -243,7 +246,7 @@ public void insertValue(int position, Comparable key, double value) {
*
* @since 1.0.6
*/
- public void insertValue(int position, Comparable key, Number value) {
+ public void insertValue(@NonNegative int position, Comparable key, Number value) {
this.data.insertValue(position, key, value);
fireDatasetChanged();
}
diff --git a/src/main/java/org/jfree/data/general/HeatMapDataset.java b/src/main/java/org/jfree/data/general/HeatMapDataset.java
index db7f8e979..4f4458789 100644
--- a/src/main/java/org/jfree/data/general/HeatMapDataset.java
+++ b/src/main/java/org/jfree/data/general/HeatMapDataset.java
@@ -40,6 +40,10 @@
package org.jfree.data.general;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
/**
* A dataset that represents a rectangular grid of (x, y, z) values. The x
* and y values appear at regular intervals in the dataset, while the z-values
@@ -56,7 +60,7 @@ public interface HeatMapDataset {
*
* @return The number of x-values (always > 0).
*/
- public int getXSampleCount();
+ public @Positive @LTEqLengthOf("this.getData()") int getXSampleCount();
/**
* Returns the number of y values (or samples) for the dataset. The
@@ -65,7 +69,7 @@ public interface HeatMapDataset {
*
* @return The number of y-values (always > 0).
*/
- public int getYSampleCount();
+ public @Positive @LTEqLengthOf("this.getData()[0]") int getYSampleCount();
/**
* Returns the lowest x-value represented in this dataset. A requirement
@@ -110,7 +114,7 @@ public interface HeatMapDataset {
*
* @return The x-value.
*/
- public double getXValue(int xIndex);
+ public double getXValue(@NonNegative int xIndex);
/**
* A convenience method that returns the y-value for the given index.
@@ -119,7 +123,7 @@ public interface HeatMapDataset {
*
* @return The y-value.
*/
- public double getYValue(int yIndex);
+ public double getYValue(@NonNegative int yIndex);
/**
* Returns the z-value at the specified sample position in the dataset.
@@ -130,7 +134,7 @@ public interface HeatMapDataset {
*
* @return The z-value.
*/
- public double getZValue(int xIndex, int yIndex);
+ public double getZValue(@IndexFor("this.getData()") int xIndex, @IndexFor("this.getData()[0]") int yIndex);
/**
* Returns the z-value at the specified sample position in the dataset.
@@ -149,6 +153,10 @@ public interface HeatMapDataset {
*
* @return The z-value (possibly {@code null}).
*/
- public Number getZ(int xIndex, int yIndex);
+ public Number getZ(@IndexFor("this.getData()") int xIndex, @IndexFor("this.getData()[0]") int yIndex);
+ /**
+ * This is a ghost method. Implementations should return null.
+ */
+ public double @MinLen(1) [] @MinLen(1) [] getData();
}
diff --git a/src/main/java/org/jfree/data/general/HeatMapUtils.java b/src/main/java/org/jfree/data/general/HeatMapUtils.java
index ec43459f4..4e0c072ec 100644
--- a/src/main/java/org/jfree/data/general/HeatMapUtils.java
+++ b/src/main/java/org/jfree/data/general/HeatMapUtils.java
@@ -41,6 +41,9 @@
package org.jfree.data.general;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.image.BufferedImage;
@@ -68,7 +71,7 @@ public abstract class HeatMapUtils {
* @return The dataset.
*/
public static XYDataset extractRowFromHeatMapDataset(HeatMapDataset dataset,
- int row, Comparable seriesName) {
+ @IndexFor("#1.getData()[0]") int row, Comparable seriesName) {
XYSeries series = new XYSeries(seriesName);
int cols = dataset.getXSampleCount();
for (int c = 0; c < cols; c++) {
@@ -89,7 +92,7 @@ public static XYDataset extractRowFromHeatMapDataset(HeatMapDataset dataset,
* @return The dataset.
*/
public static XYDataset extractColumnFromHeatMapDataset(
- HeatMapDataset dataset, int column, Comparable seriesName) {
+ HeatMapDataset dataset, @IndexFor("#1.getData()") int column, Comparable seriesName) {
XYSeries series = new XYSeries(seriesName);
int rows = dataset.getYSampleCount();
for (int r = 0; r < rows; r++) {
diff --git a/src/main/java/org/jfree/data/general/Series.java b/src/main/java/org/jfree/data/general/Series.java
index 7c755dd0d..914050727 100644
--- a/src/main/java/org/jfree/data/general/Series.java
+++ b/src/main/java/org/jfree/data/general/Series.java
@@ -56,6 +56,8 @@
package org.jfree.data.general;
+import org.checkerframework.checker.index.qual.*;
+
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
@@ -235,7 +237,7 @@ public boolean isEmpty() {
*
* @return The number of data items in the series.
*/
- public abstract int getItemCount();
+ public abstract @NonNegative int getItemCount();
/**
* Returns a clone of the series.
diff --git a/src/main/java/org/jfree/data/general/SeriesDataset.java b/src/main/java/org/jfree/data/general/SeriesDataset.java
index aa04441a7..acc52a69b 100644
--- a/src/main/java/org/jfree/data/general/SeriesDataset.java
+++ b/src/main/java/org/jfree/data/general/SeriesDataset.java
@@ -43,6 +43,10 @@
package org.jfree.data.general;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.IntervalXYZDataset;
@@ -65,7 +69,7 @@ public interface SeriesDataset extends Dataset {
*
* @return The series count.
*/
- public int getSeriesCount();
+ public @NonNegative int getSeriesCount();
/**
* Returns the key for a series.
@@ -75,7 +79,7 @@ public interface SeriesDataset extends Dataset {
*
* @return The key for the series.
*/
- public Comparable getSeriesKey(int series);
+ public Comparable getSeriesKey(@NonNegative int series);
/**
* Returns the index of the series with the specified key, or -1 if there
@@ -85,6 +89,16 @@ public interface SeriesDataset extends Dataset {
*
* @return The index, or -1.
*/
- public int indexOf(Comparable seriesKey);
+ public @GTENegativeOne int indexOf(Comparable seriesKey);
+
+ /**
+ * This is a ghost method for use in annotations. It is never called at runtime, and should never be invoked.
+ * Implementing classes should have this method throw an exception indicating that it is unimplemented.
+ * I'd rather use a default method here, but JFreeChart only compiles using Java 7.
+ *
+ * @param series a series index
+ * @return a representation of the series
+ */
+ Series getSeries(@NonNegative int series) throws Exception;
}
diff --git a/src/main/java/org/jfree/data/general/WaferMapDataset.java b/src/main/java/org/jfree/data/general/WaferMapDataset.java
index c836b8cbe..2df257fdb 100644
--- a/src/main/java/org/jfree/data/general/WaferMapDataset.java
+++ b/src/main/java/org/jfree/data/general/WaferMapDataset.java
@@ -43,6 +43,8 @@
package org.jfree.data.general;
+import org.checkerframework.checker.index.qual.*;
+
import java.util.Set;
import java.util.TreeSet;
@@ -61,10 +63,10 @@ public class WaferMapDataset extends AbstractDataset {
private DefaultKeyedValues2D data;
/** wafer x dimension */
- private int maxChipX;
+ private @NonNegative int maxChipX;
/** wafer y dimension */
- private int maxChipY;
+ private @NonNegative int maxChipY;
/** space to draw between chips */
private double chipSpace;
@@ -84,7 +86,7 @@ public class WaferMapDataset extends AbstractDataset {
* @param maxChipX the wafer x-dimension.
* @param maxChipY the wafer y-dimension.
*/
- public WaferMapDataset(int maxChipX, int maxChipY) {
+ public WaferMapDataset(@NonNegative int maxChipX, @NonNegative int maxChipY) {
this(maxChipX, maxChipY, null);
}
@@ -95,7 +97,7 @@ public WaferMapDataset(int maxChipX, int maxChipY) {
* @param maxChipY the wafer y-dimension.
* @param chipSpace the space between chips.
*/
- public WaferMapDataset(int maxChipX, int maxChipY, Number chipSpace) {
+ public WaferMapDataset(@NonNegative int maxChipX, @NonNegative int maxChipY, Number chipSpace) {
this.maxValue = new Double(Double.NEGATIVE_INFINITY);
this.minValue = new Double(Double.POSITIVE_INFINITY);
@@ -130,7 +132,7 @@ public void addValue(Number value, Comparable chipx, Comparable chipy) {
* @param x the x-index.
* @param y the y-index.
*/
- public void addValue(int v, int x, int y) {
+ public void addValue(int v, @NonNegative int x, @NonNegative int y) {
setValue(new Double(v), new Integer(x), new Integer(y));
}
@@ -156,7 +158,7 @@ public void setValue(Number value, Comparable chipx, Comparable chipy) {
*
* @return The number of unique values.
*/
- public int getUniqueValueCount() {
+ public @NonNegative int getUniqueValueCount() {
return getUniqueValues().size();
}
@@ -262,7 +264,7 @@ public Number getMinValue() {
*
* @return The number of chips in the x-dimension.
*/
- public int getMaxChipX() {
+ public @NonNegative int getMaxChipX() {
return this.maxChipX;
}
@@ -271,7 +273,7 @@ public int getMaxChipX() {
*
* @param maxChipX the number of chips in the x-dimension.
*/
- public void setMaxChipX(int maxChipX) {
+ public void setMaxChipX(@NonNegative int maxChipX) {
this.maxChipX = maxChipX;
}
@@ -280,7 +282,7 @@ public void setMaxChipX(int maxChipX) {
*
* @return The number of chips.
*/
- public int getMaxChipY() {
+ public @NonNegative int getMaxChipY() {
return this.maxChipY;
}
@@ -289,7 +291,7 @@ public int getMaxChipY() {
*
* @param maxChipY the number of chips.
*/
- public void setMaxChipY(int maxChipY) {
+ public void setMaxChipY(@NonNegative int maxChipY) {
this.maxChipY = maxChipY;
}
diff --git a/src/main/java/org/jfree/data/io/CSV.java b/src/main/java/org/jfree/data/io/CSV.java
index 8dfad2694..4f5a7eafc 100644
--- a/src/main/java/org/jfree/data/io/CSV.java
+++ b/src/main/java/org/jfree/data/io/CSV.java
@@ -40,6 +40,9 @@
package org.jfree.data.io;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
@@ -127,6 +130,7 @@ private List extractColumnKeys(String line) {
if (line.charAt(i) == this.fieldDelimiter) {
if (fieldIndex > 0) { // first field is ignored, since
// column 0 is for row keys
+ @SuppressWarnings("index") // MinLen type refinement in for loop https://github.com/kelloggm/checker-framework/issues/138
String key = line.substring(start, i);
keys.add(removeStringDelimiters(key));
}
@@ -134,6 +138,7 @@ private List extractColumnKeys(String line) {
fieldIndex++;
}
}
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/219: the for loop above cannot increment start more than line.length times, so start is IOH of line
String key = line.substring(start, line.length());
keys.add(removeStringDelimiters(key));
return keys;
@@ -151,11 +156,11 @@ private void extractRowKeyAndData(String line,
List columnKeys) {
Comparable rowKey = null;
int fieldIndex = 0;
- int start = 0;
+ @IndexOrHigh("line") int start = 0;
for (int i = 0; i < line.length(); i++) {
if (line.charAt(i) == this.fieldDelimiter) {
if (fieldIndex == 0) { // first field contains the row key
- String key = line.substring(start, i);
+ String key = line.substring(start, i);
rowKey = removeStringDelimiters(key);
}
else { // remaining fields contain values
@@ -167,10 +172,16 @@ private void extractRowKeyAndData(String line,
(Comparable) columnKeys.get(fieldIndex - 1)
);
}
- start = i + 1;
+ @IndexOrHigh("line") int skipIndex = i + 1;
+ start = skipIndex;
fieldIndex++;
}
}
+
+ @SuppressWarnings("index") // CSV format guarantees at least one field
+ @Positive int fieldIndexTmp = fieldIndex;
+ fieldIndex = fieldIndexTmp;
+
Double value = Double.valueOf(
removeStringDelimiters(line.substring(start, line.length()))
);
@@ -187,6 +198,7 @@ private void extractRowKeyAndData(String line,
*
* @return The key without delimiters.
*/
+ @SuppressWarnings({"index", "value"}) // I manually audited this. It relies on several properties of the passed String that I can't express: that removing whitespace leaves a MinLen(1) string, that if the first character of the trimmed string is a delimiter, there is another character, that if the last character is a delimiter, it isn't the only character
private String removeStringDelimiters(String key) {
String k = key.trim();
if (k.charAt(0) == this.textDelimiter) {
diff --git a/src/main/java/org/jfree/data/jdbc/JDBCXYDataset.java b/src/main/java/org/jfree/data/jdbc/JDBCXYDataset.java
index 514ac0433..059e3b95e 100644
--- a/src/main/java/org/jfree/data/jdbc/JDBCXYDataset.java
+++ b/src/main/java/org/jfree/data/jdbc/JDBCXYDataset.java
@@ -72,6 +72,8 @@
package org.jfree.data.jdbc;
+import org.checkerframework.checker.index.qual.*;
+
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
@@ -242,7 +244,8 @@ public void executeQuery(Connection con, String query)
resultSet = statement.executeQuery(query);
ResultSetMetaData metaData = resultSet.getMetaData();
- int numberOfColumns = metaData.getColumnCount();
+ @SuppressWarnings("index") // ResultSetMetaData#getColumnCount needs an annotation
+ @Positive int numberOfColumns = metaData.getColumnCount();
int numberOfValidColumns = 0;
int [] columnTypes = new int[numberOfColumns];
for (int column = 0; column < numberOfColumns; column++) {
@@ -286,12 +289,14 @@ public void executeQuery(Connection con, String query)
/// First column is X data
this.columnNames = new String[numberOfValidColumns - 1];
/// Get the column names and cache them.
- int currentColumn = 0;
+ @IndexFor("this.columnNames") int currentColumn = 0;
for (int column = 1; column < numberOfColumns; column++) {
if (columnTypes[column] != Types.NULL) {
this.columnNames[currentColumn]
= metaData.getColumnLabel(column + 1);
- ++currentColumn;
+ @SuppressWarnings("index") // this update only happens when the column is valid
+ @IndexFor("this.columnNames") int currentColumnTmp = currentColumn + 1;
+ currentColumn = currentColumnTmp;
}
}
@@ -423,7 +428,7 @@ public void executeQuery(Connection con, String query)
* @see XYDataset
*/
@Override
- public Number getX(int seriesIndex, int itemIndex) {
+ public Number getX(@NonNegative int seriesIndex, @IndexFor("this.getSeries(#1)") int itemIndex) {
ArrayList row = (ArrayList) this.rows.get(itemIndex);
return (Number) row.get(0);
}
@@ -439,7 +444,7 @@ public Number getX(int seriesIndex, int itemIndex) {
* @see XYDataset
*/
@Override
- public Number getY(int seriesIndex, int itemIndex) {
+ public Number getY(@NonNegative int seriesIndex, @IndexFor("this.getSeries(#1)") int itemIndex) {
ArrayList row = (ArrayList) this.rows.get(itemIndex);
return (Number) row.get(seriesIndex + 1);
}
@@ -454,7 +459,8 @@ public Number getY(int seriesIndex, int itemIndex) {
* @see XYDataset
*/
@Override
- public int getItemCount(int seriesIndex) {
+ @SuppressWarnings("index") // array-list interop: getItemCount needs to have this type for the other implementations
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int seriesIndex) {
return this.rows.size();
}
@@ -465,7 +471,7 @@ public int getItemCount(int seriesIndex) {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return getItemCount(0);
}
@@ -478,7 +484,7 @@ public int getItemCount() {
* @see Dataset
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.columnNames.length;
}
@@ -493,7 +499,7 @@ public int getSeriesCount() {
* @see Dataset
*/
@Override
- public Comparable getSeriesKey(int seriesIndex) {
+ public Comparable getSeriesKey(@NonNegative int seriesIndex) {
if ((seriesIndex < this.columnNames.length)
&& (this.columnNames[seriesIndex] != null)) {
diff --git a/src/main/java/org/jfree/data/json/impl/JSONObject.java b/src/main/java/org/jfree/data/json/impl/JSONObject.java
index 58eae99a1..0209fed3b 100644
--- a/src/main/java/org/jfree/data/json/impl/JSONObject.java
+++ b/src/main/java/org/jfree/data/json/impl/JSONObject.java
@@ -23,7 +23,6 @@
package org.jfree.data.json.impl;
-
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
diff --git a/src/main/java/org/jfree/data/json/impl/JSONStreamAware.java b/src/main/java/org/jfree/data/json/impl/JSONStreamAware.java
index e036f832e..1135c0100 100644
--- a/src/main/java/org/jfree/data/json/impl/JSONStreamAware.java
+++ b/src/main/java/org/jfree/data/json/impl/JSONStreamAware.java
@@ -23,7 +23,6 @@
package org.jfree.data.json.impl;
-
import java.io.IOException;
import java.io.Writer;
diff --git a/src/main/java/org/jfree/data/statistics/BoxAndWhiskerCalculator.java b/src/main/java/org/jfree/data/statistics/BoxAndWhiskerCalculator.java
index 17caaada3..bbec3c871 100644
--- a/src/main/java/org/jfree/data/statistics/BoxAndWhiskerCalculator.java
+++ b/src/main/java/org/jfree/data/statistics/BoxAndWhiskerCalculator.java
@@ -47,6 +47,9 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -186,14 +189,18 @@ public static double calculateQ1(List values) {
if (count > 0) {
if (count % 2 == 1) {
if (count > 1) {
- result = Statistics.calculateMedian(values, 0, count / 2);
+ int count1 = count / 2;
+ result = Statistics.calculateMedian(values, 0, count1);
}
else {
result = Statistics.calculateMedian(values, 0, 0);
}
}
else {
- result = Statistics.calculateMedian(values, 0, count / 2 - 1);
+ @SuppressWarnings({"index","value"}) // since count is a nonnegative even number, this expression is >= 0
+ @IntRange(from=0) int count1 = count / 2 - 1;
+ count1 = count1;
+ result = Statistics.calculateMedian(values, 0, count1);
}
}
@@ -218,16 +225,21 @@ public static double calculateQ3(List values) {
if (count > 0) {
if (count % 2 == 1) {
if (count > 1) {
- result = Statistics.calculateMedian(values, count / 2,
- count - 1);
+ int countDiv2 = count / 2;
+ int countMinus1 = count - 1;
+ result = Statistics.calculateMedian(values, countDiv2,
+ countMinus1);
}
else {
result = Statistics.calculateMedian(values, 0, 0);
}
}
else {
- result = Statistics.calculateMedian(values, count / 2,
- count - 1);
+ int countDiv2 = count / 2;
+ int countMinus1 = count - 1;
+
+ result = Statistics.calculateMedian(values, countDiv2,
+ countMinus1);
}
}
return result;
diff --git a/src/main/java/org/jfree/data/statistics/BoxAndWhiskerCategoryDataset.java b/src/main/java/org/jfree/data/statistics/BoxAndWhiskerCategoryDataset.java
index 66e0bd14f..17d22704b 100644
--- a/src/main/java/org/jfree/data/statistics/BoxAndWhiskerCategoryDataset.java
+++ b/src/main/java/org/jfree/data/statistics/BoxAndWhiskerCategoryDataset.java
@@ -45,6 +45,8 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.List;
import org.jfree.data.category.CategoryDataset;
@@ -63,7 +65,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return The mean value.
*/
- public Number getMeanValue(int row, int column);
+ public Number getMeanValue(@NonNegative int row, @NonNegative int column);
/**
* Returns the average value for an item.
@@ -83,7 +85,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return The median value.
*/
- public Number getMedianValue(int row, int column);
+ public Number getMedianValue(@NonNegative int row, @NonNegative int column);
/**
* Returns the median value for an item.
@@ -103,7 +105,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return The q1median value.
*/
- public Number getQ1Value(int row, int column);
+ public Number getQ1Value(@NonNegative int row, @NonNegative int column);
/**
* Returns the q1median value for an item.
@@ -123,7 +125,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return The q3median value.
*/
- public Number getQ3Value(int row, int column);
+ public Number getQ3Value(@NonNegative int row, @NonNegative int column);
/**
* Returns the q3median value for an item.
@@ -143,7 +145,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return The minimum regular value.
*/
- public Number getMinRegularValue(int row, int column);
+ public Number getMinRegularValue(@NonNegative int row, @NonNegative int column);
/**
* Returns the minimum regular (non-outlier) value for an item.
@@ -163,7 +165,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return The maximum regular value.
*/
- public Number getMaxRegularValue(int row, int column);
+ public Number getMaxRegularValue(@NonNegative int row, @NonNegative int column);
/**
* Returns the maximum regular (non-outlier) value for an item.
@@ -183,7 +185,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return The minimum outlier.
*/
- public Number getMinOutlier(int row, int column);
+ public Number getMinOutlier(@NonNegative int row, @NonNegative int column);
/**
* Returns the minimum outlier (non-farout) for an item.
@@ -203,7 +205,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return The maximum outlier.
*/
- public Number getMaxOutlier(int row, int column);
+ public Number getMaxOutlier(@NonNegative int row, @NonNegative int column);
/**
* Returns the maximum outlier (non-farout) for an item.
@@ -224,7 +226,7 @@ public interface BoxAndWhiskerCategoryDataset extends CategoryDataset {
*
* @return A list of outliers for an item.
*/
- public List getOutliers(int row, int column);
+ public List getOutliers(@NonNegative int row, @NonNegative int column);
/**
* Returns a list of outlier values for an item. The list may be empty,
diff --git a/src/main/java/org/jfree/data/statistics/BoxAndWhiskerXYDataset.java b/src/main/java/org/jfree/data/statistics/BoxAndWhiskerXYDataset.java
index fa3dc3097..e61c818c6 100644
--- a/src/main/java/org/jfree/data/statistics/BoxAndWhiskerXYDataset.java
+++ b/src/main/java/org/jfree/data/statistics/BoxAndWhiskerXYDataset.java
@@ -52,6 +52,10 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.List;
import org.jfree.data.xy.XYDataset;
@@ -73,7 +77,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
*
* @return The mean for the specified series and item.
*/
- public Number getMeanValue(int series, int item);
+ public Number getMeanValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the median-value for the specified series and item.
@@ -83,7 +87,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
*
* @return The median-value for the specified series and item.
*/
- public Number getMedianValue(int series, int item);
+ public Number getMedianValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the Q1 median-value for the specified series and item.
@@ -93,7 +97,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
*
* @return The Q1 median-value for the specified series and item.
*/
- public Number getQ1Value(int series, int item);
+ public Number getQ1Value(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the Q3 median-value for the specified series and item.
@@ -103,7 +107,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
*
* @return The Q3 median-value for the specified series and item.
*/
- public Number getQ3Value(int series, int item);
+ public Number getQ3Value(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the min-value for the specified series and item.
@@ -113,7 +117,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
*
* @return The min-value for the specified series and item.
*/
- public Number getMinRegularValue(int series, int item);
+ public Number getMinRegularValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the max-value for the specified series and item.
@@ -123,7 +127,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
*
* @return The max-value for the specified series and item.
*/
- public Number getMaxRegularValue(int series, int item);
+ public Number getMaxRegularValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the minimum value which is not a farout.
@@ -132,7 +136,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
*
* @return A {@code Number} representing the maximum non-farout value.
*/
- public Number getMinOutlier(int series, int item);
+ public Number getMinOutlier(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the maximum value which is not a farout, ie Q3 + (interquartile
@@ -143,7 +147,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
*
* @return A {@code Number} representing the maximum non-farout value.
*/
- public Number getMaxOutlier(int series, int item);
+ public Number getMaxOutlier(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns a list of outliers for the specified series and item.
@@ -154,7 +158,7 @@ public interface BoxAndWhiskerXYDataset extends XYDataset {
* @return The list of outliers for the specified series and item
* (possibly {@code null}).
*/
- public List getOutliers(int series, int item);
+ public List getOutliers(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the value used as the outlier coefficient. The outlier
diff --git a/src/main/java/org/jfree/data/statistics/DefaultBoxAndWhiskerCategoryDataset.java b/src/main/java/org/jfree/data/statistics/DefaultBoxAndWhiskerCategoryDataset.java
index 086a37709..0dcd7864a 100644
--- a/src/main/java/org/jfree/data/statistics/DefaultBoxAndWhiskerCategoryDataset.java
+++ b/src/main/java/org/jfree/data/statistics/DefaultBoxAndWhiskerCategoryDataset.java
@@ -56,6 +56,9 @@
package org.jfree.data.statistics;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+
import java.util.List;
import org.jfree.chart.util.ObjectUtils;
import org.jfree.chart.util.PublicCloneable;
@@ -80,23 +83,23 @@ public class DefaultBoxAndWhiskerCategoryDataset extends AbstractDataset
private double minimumRangeValue;
/** The row index for the cell that the minimum range value comes from. */
- private int minimumRangeValueRow;
+ private @GTENegativeOne int minimumRangeValueRow;
/**
* The column index for the cell that the minimum range value comes from.
*/
- private int minimumRangeValueColumn;
+ private @GTENegativeOne int minimumRangeValueColumn;
/** The maximum range value. */
private double maximumRangeValue;
/** The row index for the cell that the maximum range value comes from. */
- private int maximumRangeValueRow;
+ private @GTENegativeOne int maximumRangeValueRow;
/**
* The column index for the cell that the maximum range value comes from.
*/
- private int maximumRangeValueColumn;
+ private @GTENegativeOne int maximumRangeValueColumn;
/**
* Creates a new dataset.
@@ -227,7 +230,7 @@ public void remove(Comparable rowKey, Comparable columnKey) {
*
* @since 1.0.7
*/
- public void removeRow(int rowIndex) {
+ public void removeRow(@NonNegative int rowIndex) {
this.data.removeRow(rowIndex);
updateBounds();
fireDatasetChanged();
@@ -259,7 +262,7 @@ public void removeRow(Comparable rowKey) {
*
* @since 1.0.7
*/
- public void removeColumn(int columnIndex) {
+ public void removeColumn(@NonNegative int columnIndex) {
this.data.removeColumn(columnIndex);
updateBounds();
fireDatasetChanged();
@@ -301,7 +304,7 @@ public void clear() {
*
* @return The item.
*/
- public BoxAndWhiskerItem getItem(int row, int column) {
+ public BoxAndWhiskerItem getItem(@NonNegative int row, @NonNegative int column) {
return (BoxAndWhiskerItem) this.data.getObject(row, column);
}
@@ -317,7 +320,8 @@ public BoxAndWhiskerItem getItem(int row, int column) {
* @see #getValue(Comparable, Comparable)
*/
@Override
- public Number getValue(int row, int column) {
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column) {
return getMedianValue(row, column);
}
@@ -348,7 +352,7 @@ public Number getValue(Comparable rowKey, Comparable columnKey) {
* @see #getItem(int, int)
*/
@Override
- public Number getMeanValue(int row, int column) {
+ public Number getMeanValue(@NonNegative int row, @NonNegative int column) {
Number result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row,
@@ -392,7 +396,7 @@ public Number getMeanValue(Comparable rowKey, Comparable columnKey) {
* @see #getItem(int, int)
*/
@Override
- public Number getMedianValue(int row, int column) {
+ public Number getMedianValue(@NonNegative int row, @NonNegative int column) {
Number result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row,
column);
@@ -434,7 +438,7 @@ public Number getMedianValue(Comparable rowKey, Comparable columnKey) {
* @see #getItem(int, int)
*/
@Override
- public Number getQ1Value(int row, int column) {
+ public Number getQ1Value(@NonNegative int row, @NonNegative int column) {
Number result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
row, column);
@@ -476,7 +480,7 @@ public Number getQ1Value(Comparable rowKey, Comparable columnKey) {
* @see #getItem(int, int)
*/
@Override
- public Number getQ3Value(int row, int column) {
+ public Number getQ3Value(@NonNegative int row, @NonNegative int column) {
Number result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
row, column);
@@ -517,7 +521,7 @@ public Number getQ3Value(Comparable rowKey, Comparable columnKey) {
* @see #getColumnKey(int)
*/
@Override
- public int getColumnIndex(Comparable key) {
+ public @GTENegativeOne int getColumnIndex(Comparable key) {
return this.data.getColumnIndex(key);
}
@@ -531,7 +535,7 @@ public int getColumnIndex(Comparable key) {
* @see #getColumnIndex(Comparable)
*/
@Override
- public Comparable getColumnKey(int column) {
+ public Comparable getColumnKey(@NonNegative int column) {
return this.data.getColumnKey(column);
}
@@ -557,7 +561,7 @@ public List getColumnKeys() {
* @see #getRowKey(int)
*/
@Override
- public int getRowIndex(Comparable key) {
+ public @GTENegativeOne int getRowIndex(Comparable key) {
// defer null argument check
return this.data.getRowIndex(key);
}
@@ -572,7 +576,7 @@ public int getRowIndex(Comparable key) {
* @see #getRowIndex(Comparable)
*/
@Override
- public Comparable getRowKey(int row) {
+ public Comparable getRowKey(@NonNegative int row) {
return this.data.getRowKey(row);
}
@@ -596,7 +600,7 @@ public List getRowKeys() {
* @see #getColumnCount()
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.data.getRowCount();
}
@@ -608,7 +612,8 @@ public int getRowCount() {
* @see #getRowCount()
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
return this.data.getColumnCount();
}
@@ -666,7 +671,7 @@ public Range getRangeBounds(boolean includeInterval) {
* @see #getItem(int, int)
*/
@Override
- public Number getMinRegularValue(int row, int column) {
+ public Number getMinRegularValue(@NonNegative int row, @NonNegative int column) {
Number result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
row, column);
@@ -708,7 +713,7 @@ public Number getMinRegularValue(Comparable rowKey, Comparable columnKey) {
* @see #getItem(int, int)
*/
@Override
- public Number getMaxRegularValue(int row, int column) {
+ public Number getMaxRegularValue(@NonNegative int row, @NonNegative int column) {
Number result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
row, column);
@@ -750,7 +755,7 @@ public Number getMaxRegularValue(Comparable rowKey, Comparable columnKey) {
* @see #getItem(int, int)
*/
@Override
- public Number getMinOutlier(int row, int column) {
+ public Number getMinOutlier(@NonNegative int row, @NonNegative int column) {
Number result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
row, column);
@@ -792,7 +797,7 @@ public Number getMinOutlier(Comparable rowKey, Comparable columnKey) {
* @see #getItem(int, int)
*/
@Override
- public Number getMaxOutlier(int row, int column) {
+ public Number getMaxOutlier(@NonNegative int row, @NonNegative int column) {
Number result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
row, column);
@@ -834,7 +839,7 @@ public Number getMaxOutlier(Comparable rowKey, Comparable columnKey) {
* @see #getItem(int, int)
*/
@Override
- public List getOutliers(int row, int column) {
+ public List getOutliers(@NonNegative int row, @NonNegative int column) {
List result = null;
BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
row, column);
diff --git a/src/main/java/org/jfree/data/statistics/DefaultBoxAndWhiskerXYDataset.java b/src/main/java/org/jfree/data/statistics/DefaultBoxAndWhiskerXYDataset.java
index a4fbbf6c3..51732f5a9 100644
--- a/src/main/java/org/jfree/data/statistics/DefaultBoxAndWhiskerXYDataset.java
+++ b/src/main/java/org/jfree/data/statistics/DefaultBoxAndWhiskerXYDataset.java
@@ -60,6 +60,10 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -200,7 +204,7 @@ public void setFaroutCoefficient(double faroutCoefficient) {
* @return The number of series.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return 1;
}
@@ -212,7 +216,7 @@ public int getSeriesCount() {
* @return The number of items in the specified series.
*/
@Override
- public int getItemCount(int series) {
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
return this.dates.size();
}
@@ -270,7 +274,7 @@ public Comparable getSeriesKey(int i) {
*
* @return The item.
*/
- public BoxAndWhiskerItem getItem(int series, int item) {
+ public BoxAndWhiskerItem getItem(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return (BoxAndWhiskerItem) this.items.get(item);
}
@@ -286,7 +290,7 @@ public BoxAndWhiskerItem getItem(int series, int item) {
* @return The x-value.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Long(((Date) this.dates.get(item)).getTime());
}
@@ -300,7 +304,7 @@ public Number getX(int series, int item) {
*
* @return The x-value as a Date.
*/
- public Date getXDate(int series, int item) {
+ public Date getXDate(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return (Date) this.dates.get(item);
}
@@ -316,7 +320,7 @@ public Date getXDate(int series, int item) {
* @return The y-value.
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getMeanValue(series, item);
}
@@ -329,7 +333,7 @@ public Number getY(int series, int item) {
* @return The mean for the specified series and item.
*/
@Override
- public Number getMeanValue(int series, int item) {
+ public Number getMeanValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
Number result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
@@ -347,7 +351,7 @@ public Number getMeanValue(int series, int item) {
* @return The median-value for the specified series and item.
*/
@Override
- public Number getMedianValue(int series, int item) {
+ public Number getMedianValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
Number result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
@@ -365,7 +369,7 @@ public Number getMedianValue(int series, int item) {
* @return The Q1 median-value for the specified series and item.
*/
@Override
- public Number getQ1Value(int series, int item) {
+ public Number getQ1Value(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
Number result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
@@ -383,7 +387,7 @@ public Number getQ1Value(int series, int item) {
* @return The Q3 median-value for the specified series and item.
*/
@Override
- public Number getQ3Value(int series, int item) {
+ public Number getQ3Value(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
Number result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
@@ -401,7 +405,7 @@ public Number getQ3Value(int series, int item) {
* @return The min-value for the specified series and item.
*/
@Override
- public Number getMinRegularValue(int series, int item) {
+ public Number getMinRegularValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
Number result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
@@ -419,7 +423,7 @@ public Number getMinRegularValue(int series, int item) {
* @return The max-value for the specified series and item.
*/
@Override
- public Number getMaxRegularValue(int series, int item) {
+ public Number getMaxRegularValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
Number result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
@@ -436,7 +440,7 @@ public Number getMaxRegularValue(int series, int item) {
* @return A {@code Number} representing the maximum non-farout value.
*/
@Override
- public Number getMinOutlier(int series, int item) {
+ public Number getMinOutlier(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
Number result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
@@ -455,7 +459,7 @@ public Number getMinOutlier(int series, int item) {
* @return A {@code Number} representing the maximum non-farout value.
*/
@Override
- public Number getMaxOutlier(int series, int item) {
+ public Number getMaxOutlier(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
Number result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
@@ -474,7 +478,7 @@ public Number getMaxOutlier(int series, int item) {
* (possibly {@code null}).
*/
@Override
- public List getOutliers(int series, int item) {
+ public List getOutliers(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
List result = null;
BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
if (stats != null) {
diff --git a/src/main/java/org/jfree/data/statistics/DefaultMultiValueCategoryDataset.java b/src/main/java/org/jfree/data/statistics/DefaultMultiValueCategoryDataset.java
index a1a85dcfe..799319008 100644
--- a/src/main/java/org/jfree/data/statistics/DefaultMultiValueCategoryDataset.java
+++ b/src/main/java/org/jfree/data/statistics/DefaultMultiValueCategoryDataset.java
@@ -42,6 +42,9 @@
package org.jfree.data.statistics;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -163,7 +166,7 @@ else if (minval < this.minimumRangeValue.doubleValue()) {
* @return The list of values.
*/
@Override
- public List getValues(int row, int column) {
+ public List getValues(@NonNegative int row, @NonNegative int column) {
List values = (List) this.data.getObject(row, column);
if (values != null) {
return Collections.unmodifiableList(values);
@@ -226,7 +229,8 @@ public Number getValue(Comparable row, Comparable column) {
* @return The average value.
*/
@Override
- public Number getValue(int row, int column) {
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column) {
List l = (List) this.data.getObject(row, column);
double average = 0.0d;
int count = 0;
@@ -254,7 +258,7 @@ public Number getValue(int row, int column) {
* @return The column index.
*/
@Override
- public int getColumnIndex(Comparable key) {
+ public @GTENegativeOne int getColumnIndex(Comparable key) {
return this.data.getColumnIndex(key);
}
@@ -266,7 +270,7 @@ public int getColumnIndex(Comparable key) {
* @return The column key.
*/
@Override
- public Comparable getColumnKey(int column) {
+ public Comparable getColumnKey(@NonNegative int column) {
return this.data.getColumnKey(column);
}
@@ -288,7 +292,7 @@ public List getColumnKeys() {
* @return The row index.
*/
@Override
- public int getRowIndex(Comparable key) {
+ public @GTENegativeOne int getRowIndex(Comparable key) {
return this.data.getRowIndex(key);
}
@@ -300,7 +304,7 @@ public int getRowIndex(Comparable key) {
* @return The row key.
*/
@Override
- public Comparable getRowKey(int row) {
+ public Comparable getRowKey(@NonNegative int row) {
return this.data.getRowKey(row);
}
@@ -320,7 +324,7 @@ public List getRowKeys() {
* @return The row count.
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.data.getRowCount();
}
@@ -330,7 +334,8 @@ public int getRowCount() {
* @return The column count.
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
return this.data.getColumnCount();
}
diff --git a/src/main/java/org/jfree/data/statistics/DefaultStatisticalCategoryDataset.java b/src/main/java/org/jfree/data/statistics/DefaultStatisticalCategoryDataset.java
index 4775338b1..966586871 100644
--- a/src/main/java/org/jfree/data/statistics/DefaultStatisticalCategoryDataset.java
+++ b/src/main/java/org/jfree/data/statistics/DefaultStatisticalCategoryDataset.java
@@ -57,6 +57,10 @@
package org.jfree.data.statistics;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.List;
import org.jfree.chart.util.PublicCloneable;
@@ -152,7 +156,7 @@ public DefaultStatisticalCategoryDataset() {
* @return The mean value (possibly {@code null}).
*/
@Override
- public Number getMeanValue(int row, int column) {
+ public Number getMeanValue(@NonNegative int row, @NonNegative int column) {
Number result = null;
MeanAndStandardDeviation masd = (MeanAndStandardDeviation)
this.data.getObject(row, column);
@@ -172,7 +176,8 @@ public Number getMeanValue(int row, int column) {
* @return The value (possibly {@code null}).
*/
@Override
- public Number getValue(int row, int column) {
+ @Pure
+ public Number getValue(@NonNegative int row, @NonNegative int column) {
return getMeanValue(row, column);
}
@@ -218,7 +223,7 @@ public Number getMeanValue(Comparable rowKey, Comparable columnKey) {
* @return The standard deviation (possibly {@code null}).
*/
@Override
- public Number getStdDevValue(int row, int column) {
+ public Number getStdDevValue(@NonNegative int row, @NonNegative int column) {
Number result = null;
MeanAndStandardDeviation masd = (MeanAndStandardDeviation)
this.data.getObject(row, column);
@@ -255,7 +260,7 @@ public Number getStdDevValue(Comparable rowKey, Comparable columnKey) {
* @return The column index.
*/
@Override
- public int getColumnIndex(Comparable key) {
+ public @GTENegativeOne int getColumnIndex(Comparable key) {
// defer null argument check
return this.data.getColumnIndex(key);
}
@@ -268,7 +273,7 @@ public int getColumnIndex(Comparable key) {
* @return The column key.
*/
@Override
- public Comparable getColumnKey(int column) {
+ public Comparable getColumnKey(@NonNegative int column) {
return this.data.getColumnKey(column);
}
@@ -290,7 +295,7 @@ public List getColumnKeys() {
* @return The row index.
*/
@Override
- public int getRowIndex(Comparable key) {
+ public @GTENegativeOne int getRowIndex(Comparable key) {
// defer null argument check
return this.data.getRowIndex(key);
}
@@ -303,7 +308,7 @@ public int getRowIndex(Comparable key) {
* @return The row key.
*/
@Override
- public Comparable getRowKey(int row) {
+ public Comparable getRowKey(@NonNegative int row) {
return this.data.getRowKey(row);
}
@@ -325,7 +330,7 @@ public List getRowKeys() {
* @see #getColumnCount()
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.data.getRowCount();
}
@@ -337,7 +342,8 @@ public int getRowCount() {
* @see #getRowCount()
*/
@Override
- public int getColumnCount() {
+ @Pure
+ public @NonNegative int getColumnCount() {
return this.data.getColumnCount();
}
@@ -478,7 +484,7 @@ public void remove(Comparable rowKey, Comparable columnKey) {
*
* @since 1.0.7
*/
- public void removeRow(int rowIndex) {
+ public void removeRow(@NonNegative int rowIndex) {
this.data.removeRow(rowIndex);
updateBounds();
fireDatasetChanged();
@@ -510,7 +516,7 @@ public void removeRow(Comparable rowKey) {
*
* @since 1.0.7
*/
- public void removeColumn(int columnIndex) {
+ public void removeColumn(@NonNegative int columnIndex) {
this.data.removeColumn(columnIndex);
updateBounds();
fireDatasetChanged();
diff --git a/src/main/java/org/jfree/data/statistics/HistogramBin.java b/src/main/java/org/jfree/data/statistics/HistogramBin.java
index 6b6ec7804..29f659ff1 100644
--- a/src/main/java/org/jfree/data/statistics/HistogramBin.java
+++ b/src/main/java/org/jfree/data/statistics/HistogramBin.java
@@ -44,6 +44,8 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.*;
+
import java.io.Serializable;
/**
@@ -55,7 +57,7 @@ public class HistogramBin implements Cloneable, Serializable {
private static final long serialVersionUID = 7614685080015589931L;
/** The number of items in the bin. */
- private int count;
+ private @NonNegative int count;
/** The start boundary. */
private double startBoundary;
@@ -84,7 +86,7 @@ public HistogramBin(double startBoundary, double endBoundary) {
*
* @return The item count.
*/
- public int getCount() {
+ public @NonNegative int getCount() {
return this.count;
}
diff --git a/src/main/java/org/jfree/data/statistics/HistogramDataset.java b/src/main/java/org/jfree/data/statistics/HistogramDataset.java
index 12d386421..47088a517 100644
--- a/src/main/java/org/jfree/data/statistics/HistogramDataset.java
+++ b/src/main/java/org/jfree/data/statistics/HistogramDataset.java
@@ -62,6 +62,12 @@
package org.jfree.data.statistics;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
@@ -131,7 +137,7 @@ public void setType(HistogramType type) {
* @param values the values ({@code null} not permitted).
* @param bins the number of bins (must be at least 1).
*/
- public void addSeries(Comparable key, double[] values, int bins) {
+ public void addSeries(Comparable key, double @MinLen(1) [] values, @Positive int bins) {
// defer argument checking...
double minimum = getMinimum(values);
double maximum = getMaximum(values);
@@ -150,7 +156,7 @@ public void addSeries(Comparable key, double[] values, int bins) {
* @param minimum the lower bound of the bin range.
* @param maximum the upper bound of the bin range.
*/
- public void addSeries(Comparable key, double[] values, int bins,
+ public void addSeries(Comparable key, double[] values, @Positive int bins,
double minimum, double maximum) {
Args.nullNotPermitted(key, "key");
@@ -195,6 +201,7 @@ public void addSeries(Comparable key, double[] values, int bins,
binIndex = bins - 1;
}
}
+ @SuppressWarnings("index") // see the comment about the known bug above
HistogramBin bin = (HistogramBin) binList.get(binIndex);
bin.incrementCount();
}
@@ -216,7 +223,7 @@ public void addSeries(Comparable key, double[] values, int bins,
*
* @return The minimum value.
*/
- private double getMinimum(double[] values) {
+ private double getMinimum(double @MinLen(1) [] values) {
if (values == null || values.length < 1) {
throw new IllegalArgumentException(
"Null or zero length 'values' argument.");
@@ -238,7 +245,7 @@ private double getMinimum(double[] values) {
*
* @return The maximum value.
*/
- private double getMaximum(double[] values) {
+ private double getMaximum(double @MinLen(1) [] values) {
if (values == null || values.length < 1) {
throw new IllegalArgumentException(
"Null or zero length 'values' argument.");
@@ -263,7 +270,7 @@ private double getMaximum(double[] values) {
* @throws IndexOutOfBoundsException if {@code series} is outside the
* specified range.
*/
- List getBins(int series) {
+ List getBins(@NonNegative int series) {
Map map = (Map) this.list.get(series);
return (List) map.get("bins");
}
@@ -275,7 +282,7 @@ List getBins(int series) {
*
* @return The total.
*/
- private int getTotal(int series) {
+ private int getTotal(@NonNegative int series) {
Map map = (Map) this.list.get(series);
return ((Integer) map.get("values.length")).intValue();
}
@@ -287,7 +294,7 @@ private int getTotal(int series) {
*
* @return The bin width.
*/
- private double getBinWidth(int series) {
+ private double getBinWidth(@NonNegative int series) {
Map map = (Map) this.list.get(series);
return ((Double) map.get("bin width")).doubleValue();
}
@@ -298,7 +305,7 @@ private double getBinWidth(int series) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.list.size();
}
@@ -314,7 +321,7 @@ public int getSeriesCount() {
* specified range.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
Map map = (Map) this.list.get(series);
return (Comparable) map.get("key");
}
@@ -331,7 +338,7 @@ public Comparable getSeriesKey(int series) {
* specified range.
*/
@Override
- public int getItemCount(int series) {
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
return getBins(series).size();
}
@@ -351,7 +358,7 @@ public int getItemCount(int series) {
* specified range.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
List bins = getBins(series);
HistogramBin bin = (HistogramBin) bins.get(item);
double x = (bin.getStartBoundary() + bin.getEndBoundary()) / 2.;
@@ -372,7 +379,7 @@ public Number getX(int series, int item) {
* specified range.
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
List bins = getBins(series);
HistogramBin bin = (HistogramBin) bins.get(item);
double total = getTotal(series);
@@ -405,7 +412,7 @@ else if (this.type == HistogramType.SCALE_AREA_TO_1) {
* specified range.
*/
@Override
- public Number getStartX(int series, int item) {
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
List bins = getBins(series);
HistogramBin bin = (HistogramBin) bins.get(item);
return new Double(bin.getStartBoundary());
@@ -424,7 +431,7 @@ public Number getStartX(int series, int item) {
* specified range.
*/
@Override
- public Number getEndX(int series, int item) {
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
List bins = getBins(series);
HistogramBin bin = (HistogramBin) bins.get(item);
return new Double(bin.getEndBoundary());
@@ -445,7 +452,7 @@ public Number getEndX(int series, int item) {
* specified range.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -464,7 +471,7 @@ public Number getStartY(int series, int item) {
* specified range.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
diff --git a/src/main/java/org/jfree/data/statistics/MultiValueCategoryDataset.java b/src/main/java/org/jfree/data/statistics/MultiValueCategoryDataset.java
index a5041baa1..5e82b0b1a 100644
--- a/src/main/java/org/jfree/data/statistics/MultiValueCategoryDataset.java
+++ b/src/main/java/org/jfree/data/statistics/MultiValueCategoryDataset.java
@@ -40,6 +40,8 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.List;
import org.jfree.data.category.CategoryDataset;
@@ -60,7 +62,7 @@ public interface MultiValueCategoryDataset extends CategoryDataset {
*
* @return The list of values.
*/
- public List getValues(int row, int column);
+ public List getValues(@NonNegative int row, @NonNegative int column);
/**
* Returns a list (possibly empty) of the values for the specified item.
diff --git a/src/main/java/org/jfree/data/statistics/Regression.java b/src/main/java/org/jfree/data/statistics/Regression.java
index 83b126b35..8ac936860 100644
--- a/src/main/java/org/jfree/data/statistics/Regression.java
+++ b/src/main/java/org/jfree/data/statistics/Regression.java
@@ -46,6 +46,12 @@
package org.jfree.data.statistics;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.chart.util.Args;
import org.jfree.data.xy.XYDataset;
@@ -63,7 +69,7 @@ public abstract class Regression {
*
* @return The parameters.
*/
- public static double[] getOLSRegression(double[][] data) {
+ public static double @ArrayLen(2) [] getOLSRegression(double @MinLen(2) [] @MinLen(2) [] data) {
int n = data.length;
if (n < 2) {
@@ -107,7 +113,7 @@ public static double[] getOLSRegression(double[][] data) {
*
* @return The parameters.
*/
- public static double[] getOLSRegression(XYDataset data, int series) {
+ public static double @ArrayLen(2) [] getOLSRegression(XYDataset data, @NonNegative int series) {
int n = data.getItemCount(series);
if (n < 2) {
@@ -150,7 +156,7 @@ public static double[] getOLSRegression(XYDataset data, int series) {
*
* @return The parameters.
*/
- public static double[] getPowerRegression(double[][] data) {
+ public static double @ArrayLen(2) [] getPowerRegression(double @MinLen(2) [] @MinLen(2) [] data) {
int n = data.length;
if (n < 2) {
@@ -194,7 +200,7 @@ public static double[] getPowerRegression(double[][] data) {
*
* @return The parameters.
*/
- public static double[] getPowerRegression(XYDataset data, int series) {
+ public static double @ArrayLen(2) [] getPowerRegression(XYDataset data, @NonNegative int series) {
int n = data.getItemCount(series);
if (n < 2) {
@@ -247,31 +253,34 @@ public static double[] getPowerRegression(XYDataset data, int series) {
*
* @since 1.0.14
*/
- public static double[] getPolynomialRegression(XYDataset dataset,
- int series, int order) {
+ public static double[] getPolynomialRegression(XYDataset dataset,
+ @NonNegative int series, @Positive int order) {
Args.nullNotPermitted(dataset, "dataset");
int itemCount = dataset.getItemCount(series);
if (itemCount < order + 1) {
throw new IllegalArgumentException("Not enough data.");
}
- int validItems = 0;
double[][] data = new double[2][itemCount];
+ @SuppressWarnings("index") // validItems will only be used as a index if there is at least one item
+ @LTLengthOf(value={"data[0]","data[1]"}, offset={"0","0"}) @NonNegative int validItems = 0;
for(int item = 0; item < itemCount; item++){
double x = dataset.getXValue(series, item);
double y = dataset.getYValue(series, item);
if (!Double.isNaN(x) && !Double.isNaN(y)){
data[0][validItems] = x;
data[1][validItems] = y;
- validItems++;
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/219: validItems is incremented at most as often as item, which is a valid index
+ @LTLengthOf(value={"data[0]","data[1]"}, offset={"0","0"}) @NonNegative int validItemsTmp = validItems + 1;
+ validItems = validItemsTmp;
}
}
if (validItems < order + 1) {
throw new IllegalArgumentException("Not enough data.");
}
- int equations = order + 1;
- int coefficients = order + 2;
+ @Positive int equations = order + 1;
+ @Positive int coefficients = order + 2;
double[] result = new double[equations + 1];
- double[][] matrix = new double[equations][coefficients];
+ double[] @MinLen(1) [] matrix = new double[equations][coefficients];
double sumX = 0.0;
double sumY = 0.0;
@@ -279,26 +288,34 @@ public static double[] getPolynomialRegression(XYDataset dataset,
sumX += data[0][item];
sumY += data[1][item];
for(int eq = 0; eq < equations; eq++){
- for(int coe = 0; coe < coefficients - 1; coe++){
+ for(int coe = 0; coe < matrix[eq].length - 1; coe++){
matrix[eq][coe] += Math.pow(data[0][item],eq + coe);
}
- matrix[eq][coefficients - 1] += data[1][item]
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/202: coefficients is positive, and matrix's subarrays are all exactly `coefficients` long
+ @IndexFor("matrix[eq]") int coe1 = coefficients - 1;
+ matrix[eq][coe1] += data[1][item]
* Math.pow(data[0][item],eq);
}
}
double[][] subMatrix = calculateSubMatrix(matrix);
for (int eq = 1; eq < equations; eq++) {
matrix[eq][0] = 0;
- for (int coe = 1; coe < coefficients; coe++) {
- matrix[eq][coe] = subMatrix[eq - 1][coe - 1];
+ for (int coe = 1; coe < matrix[eq].length; coe++) {
+ @SuppressWarnings("index") // subMatrix is a reduced version of matrix, with rows and columns shifted so that subtracting one is always safe
+ double subMatrixEntry = subMatrix[eq - 1][coe - 1];
+ matrix[eq][coe] = subMatrixEntry;
}
}
for (int eq = equations - 1; eq > -1; eq--) {
- double value = matrix[eq][coefficients - 1];
- for (int coe = eq; coe < coefficients -1; coe++) {
- value -= matrix[eq][coe] * result[coe];
+ double value = matrix[eq][matrix[eq].length - 1];
+ for (int coe = eq; coe < matrix[eq].length -1; coe++) {
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/202: coe is LTOM for matrix[eq], which means that it is LTL for result[eq], which is one smaller in each dimension
+ double resultCoefficient = result[coe];
+ value -= matrix[eq][coe] * resultCoefficient;
}
- result[eq] = value / matrix[eq][eq];
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/158 equations < coeffecients (equations = order + 1, coeffecients = order + 2)
+ double diag = matrix[eq][eq];
+ result[eq] = value / diag;
}
double meanY = sumY / validItems;
double yObsSquare = 0.0;
@@ -326,30 +343,41 @@ public static double[] getPolynomialRegression(XYDataset dataset,
*
* @return The new matrix.
*/
- private static double[][] calculateSubMatrix(double[][] matrix){
- int equations = matrix.length;
- int coefficients = matrix[0].length;
+ private static double[][] calculateSubMatrix(double @MinLen(1) [] @MinLen(1) [] matrix){
+ @Positive int equations = matrix.length;
+ @Positive int coefficients = matrix[0].length;
double[][] result = new double[equations - 1][coefficients - 1];
for (int eq = 1; eq < equations; eq++) {
double factor = matrix[0][0] / matrix[eq][0];
- for (int coe = 1; coe < coefficients; coe++) {
- result[eq - 1][coe -1] = matrix[0][coe] - matrix[eq][coe]
+ // I added the second condition here - matrix is rectangular, and this is the easiest way to guarantee this typechecks
+ for (int coe = 1; coe < matrix[eq].length && coe < matrix[0].length; coe++) {
+ int resultEq = eq - 1;
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/202: result is one smaller in both dimensions than matrix, and coe is an index for matrix. Also note the use of a temporary here: the Index Checker's java expression parser chokes on "result[eq - 1]"
+ @IndexFor("result[resultEq]") int resultCoe = coe -1;
+ result[resultEq][resultCoe] = matrix[0][coe] - matrix[eq][coe]
* factor;
}
}
if (equations == 1) {
return result;
}
+ @SuppressWarnings({"value", "index"}) // https://github.com/kelloggm/checker-framework/issues/158: equations != 1 -> equations >= 2 -> result is minlen(1)
+ double @MinLen(1) [] @MinLen(1) [] result1 = result;
+
// check for zero pivot element
- if (result[0][0] == 0) {
+ if (result1[0][0] == 0) {
boolean found = false;
- for (int i = 0; i < result.length; i ++) {
- if (result[i][0] != 0) {
+ for (int i = 0; i < result1.length; i ++) {
+ if (result1[i][0] != 0) {
found = true;
- double[] temp = result[0];
- System.arraycopy(result[i], 0, result[0], 0,
- result[i].length);
- System.arraycopy(temp, 0, result[i], 0, temp.length);
+ double[] temp = result1[0];
+ @SuppressWarnings("index") // result1 is a rectangular array
+ @IndexOrHigh({"result1[i]", "result1[0]"}) int result1ILength = result1[i].length;
+ System.arraycopy(result1[i], 0, result1[0], 0,
+ result1ILength);
+ @SuppressWarnings("index") // result1 is a rectangular array
+ @IndexOrHigh({"result1[i]", "temp", "result1[0]"}) int tempLen = temp.length;
+ System.arraycopy(temp, 0, result1[i], 0, tempLen);
break;
}
}
@@ -358,14 +386,16 @@ private static double[][] calculateSubMatrix(double[][] matrix){
return new double[equations - 1][coefficients - 1];
}
}
- double[][] subMatrix = calculateSubMatrix(result);
+ double[][] subMatrix = calculateSubMatrix(result1);
for (int eq = 1; eq < equations - 1; eq++) {
- result[eq][0] = 0;
- for (int coe = 1; coe < coefficients - 1; coe++) {
- result[eq][coe] = subMatrix[eq - 1][coe - 1];
+ result1[eq][0] = 0;
+ for (int coe = 1; coe < result1[eq].length; coe++) {
+ @SuppressWarnings("index") // subMatrix is always one smaller than result1
+ double submatrixresult1 = subMatrix[eq - 1][coe - 1];
+ result1[eq][coe] = submatrixresult1;
}
}
- return result;
+ return result1;
}
}
diff --git a/src/main/java/org/jfree/data/statistics/SimpleHistogramBin.java b/src/main/java/org/jfree/data/statistics/SimpleHistogramBin.java
index 3026b6d7a..ac347ff14 100644
--- a/src/main/java/org/jfree/data/statistics/SimpleHistogramBin.java
+++ b/src/main/java/org/jfree/data/statistics/SimpleHistogramBin.java
@@ -40,6 +40,8 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.*;
+
import java.io.Serializable;
import org.jfree.chart.util.PublicCloneable;
@@ -71,7 +73,7 @@ public class SimpleHistogramBin implements Comparable,
private boolean includeUpperBound;
/** The item count. */
- private int itemCount;
+ private @NonNegative int itemCount;
/**
* Creates a new bin.
@@ -127,7 +129,7 @@ public double getUpperBound() {
*
* @return The item count.
*/
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.itemCount;
}
@@ -136,7 +138,7 @@ public int getItemCount() {
*
* @param count the item count.
*/
- public void setItemCount(int count) {
+ public void setItemCount(@NonNegative int count) {
this.itemCount = count;
}
diff --git a/src/main/java/org/jfree/data/statistics/SimpleHistogramDataset.java b/src/main/java/org/jfree/data/statistics/SimpleHistogramDataset.java
index be6b95832..ccfed587b 100644
--- a/src/main/java/org/jfree/data/statistics/SimpleHistogramDataset.java
+++ b/src/main/java/org/jfree/data/statistics/SimpleHistogramDataset.java
@@ -43,6 +43,10 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
@@ -126,7 +130,7 @@ public void setAdjustForBinSize(boolean adjust) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return 1;
}
@@ -139,7 +143,7 @@ public int getSeriesCount() {
* @return The key for the series.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
return this.key;
}
@@ -162,7 +166,7 @@ public DomainOrder getDomainOrder() {
* @return The item count.
*/
@Override
- public int getItemCount(int series) {
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
return this.bins.size();
}
@@ -282,7 +286,7 @@ public void removeAllBins() {
* @return The x-value (never {@code null}).
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getXValue(series, item));
}
@@ -295,7 +299,7 @@ public Number getX(int series, int item) {
* @return The x-value.
*/
@Override
- public double getXValue(int series, int item) {
+ public double getXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
SimpleHistogramBin bin = (SimpleHistogramBin) this.bins.get(item);
return (bin.getLowerBound() + bin.getUpperBound()) / 2.0;
}
@@ -309,7 +313,7 @@ public double getXValue(int series, int item) {
* @return The y-value (possibly {@code null}).
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getYValue(series, item));
}
@@ -324,7 +328,7 @@ public Number getY(int series, int item) {
* @see #getAdjustForBinSize()
*/
@Override
- public double getYValue(int series, int item) {
+ public double getYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
SimpleHistogramBin bin = (SimpleHistogramBin) this.bins.get(item);
if (this.adjustForBinSize) {
return bin.getItemCount()
@@ -344,7 +348,7 @@ public double getYValue(int series, int item) {
* @return The value.
*/
@Override
- public Number getStartX(int series, int item) {
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getStartXValue(series, item));
}
@@ -358,7 +362,7 @@ public Number getStartX(int series, int item) {
* @return The start x-value.
*/
@Override
- public double getStartXValue(int series, int item) {
+ public double getStartXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
SimpleHistogramBin bin = (SimpleHistogramBin) this.bins.get(item);
return bin.getLowerBound();
}
@@ -372,7 +376,7 @@ public double getStartXValue(int series, int item) {
* @return The value.
*/
@Override
- public Number getEndX(int series, int item) {
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getEndXValue(series, item));
}
@@ -386,7 +390,7 @@ public Number getEndX(int series, int item) {
* @return The end x-value.
*/
@Override
- public double getEndXValue(int series, int item) {
+ public double getEndXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
SimpleHistogramBin bin = (SimpleHistogramBin) this.bins.get(item);
return bin.getUpperBound();
}
@@ -400,7 +404,7 @@ public double getEndXValue(int series, int item) {
* @return The value.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -414,7 +418,7 @@ public Number getStartY(int series, int item) {
* @return The start y-value.
*/
@Override
- public double getStartYValue(int series, int item) {
+ public double getStartYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getYValue(series, item);
}
@@ -427,7 +431,7 @@ public double getStartYValue(int series, int item) {
* @return The value.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -441,7 +445,7 @@ public Number getEndY(int series, int item) {
* @return The end y-value.
*/
@Override
- public double getEndYValue(int series, int item) {
+ public double getEndYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getYValue(series, item);
}
diff --git a/src/main/java/org/jfree/data/statistics/StatisticalCategoryDataset.java b/src/main/java/org/jfree/data/statistics/StatisticalCategoryDataset.java
index 7c9cb4921..c61fa4f5c 100644
--- a/src/main/java/org/jfree/data/statistics/StatisticalCategoryDataset.java
+++ b/src/main/java/org/jfree/data/statistics/StatisticalCategoryDataset.java
@@ -45,6 +45,8 @@
package org.jfree.data.statistics;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.data.category.CategoryDataset;
/**
@@ -61,7 +63,7 @@ public interface StatisticalCategoryDataset extends CategoryDataset {
*
* @return The mean value (possibly {@code null}).
*/
- public Number getMeanValue(int row, int column);
+ public Number getMeanValue(@NonNegative int row, @NonNegative int column);
/**
* Returns the mean value for an item.
@@ -81,7 +83,7 @@ public interface StatisticalCategoryDataset extends CategoryDataset {
*
* @return The standard deviation (possibly {@code null}).
*/
- public Number getStdDevValue(int row, int column);
+ public Number getStdDevValue(@NonNegative int row, @NonNegative int column);
/**
* Returns the standard deviation value for an item.
diff --git a/src/main/java/org/jfree/data/statistics/Statistics.java b/src/main/java/org/jfree/data/statistics/Statistics.java
index 8a4eb34b1..5a6fdf517 100644
--- a/src/main/java/org/jfree/data/statistics/Statistics.java
+++ b/src/main/java/org/jfree/data/statistics/Statistics.java
@@ -49,6 +49,10 @@
package org.jfree.data.statistics;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -220,6 +224,7 @@ public static double calculateMedian(List values, boolean copyAndSort) {
}
}
else {
+ @SuppressWarnings("index") // count is a positive even integer -> count >= 2 -> count / 2 - 1 is NN
Number value1 = (Number) values.get(count / 2 - 1);
Number value2 = (Number) values.get(count / 2);
result = (value1.doubleValue() + value2.doubleValue())
@@ -240,7 +245,7 @@ public static double calculateMedian(List values, boolean copyAndSort) {
*
* @return The median.
*/
- public static double calculateMedian(List values, int start, int end) {
+ public static double calculateMedian(List values, @NonNegative @LessThan("#3 + 1") int start, @NonNegative int end) {
return calculateMedian(values, start, end, true);
}
@@ -257,7 +262,7 @@ public static double calculateMedian(List values, int start, int end) {
*
* @return The median.
*/
- public static double calculateMedian(List values, int start, int end,
+ public static double calculateMedian(List values, @NonNegative @LessThan("#3 + 1") int start, @NonNegative int end,
boolean copyAndSort) {
double result = Double.NaN;
@@ -284,6 +289,7 @@ public static double calculateMedian(List values, int start, int end,
}
}
else {
+ @SuppressWarnings("index") // count is a positive even integer -> count >= 2 -> count / 2 - 1 is NN
Number value1 = (Number) values.get(start + count / 2 - 1);
Number value2 = (Number) values.get(start + count / 2);
result
@@ -303,7 +309,7 @@ public static double calculateMedian(List values, int start, int end,
*
* @return The standard deviation of a set of numbers.
*/
- public static double getStdDev(Number[] data) {
+ public static double getStdDev(Number @MinLen(1) [] data) {
Args.nullNotPermitted(data, "data");
if (data.length == 0) {
throw new IllegalArgumentException("Zero length 'data' array.");
@@ -327,7 +333,7 @@ public static double getStdDev(Number[] data) {
*
* @return A double array with the intercept in [0] and the slope in [1].
*/
- public static double[] getLinearFit(Number[] xData, Number[] yData) {
+ public static double @ArrayLen(2) [] getLinearFit(Number @SameLen("#2") [] xData, Number @SameLen("#1") [] yData) {
Args.nullNotPermitted(xData, "xData");
Args.nullNotPermitted(yData, "yData");
@@ -354,7 +360,7 @@ public static double[] getLinearFit(Number[] xData, Number[] yData) {
*
* @return The slope.
*/
- public static double getSlope(Number[] xData, Number[] yData) {
+ public static double getSlope(Number @SameLen("#2") [] xData, Number @SameLen("#1") [] yData) {
Args.nullNotPermitted(xData, "xData");
Args.nullNotPermitted(yData, "yData");
if (xData.length != yData.length) {
@@ -376,7 +382,7 @@ public static double getSlope(Number[] xData, Number[] yData) {
sx = sx + xData[counter].doubleValue();
sxx = sxx + Math.pow(xData[counter].doubleValue(), 2);
sxy = sxy + yData[counter].doubleValue()
- * xData[counter].doubleValue();
+ * xData[counter].doubleValue();
sy = sy + yData[counter].doubleValue();
}
return (sxy - (sx * sy) / counter) / (sxx - (sx * sx) / counter);
@@ -396,7 +402,7 @@ public static double getSlope(Number[] xData, Number[] yData) {
*
* @return The correlation.
*/
- public static double getCorrelation(Number[] data1, Number[] data2) {
+ public static double getCorrelation(Number @SameLen("#2") [] data1, Number @SameLen("#1") [] data2) {
Args.nullNotPermitted(data1, "data1");
Args.nullNotPermitted(data2, "data2");
if (data1.length != data2.length) {
@@ -439,8 +445,8 @@ public static double getCorrelation(Number[] data1, Number[] data2) {
* @return A double[][] the length of the data set in the first dimension,
* with two doubles for x and y in the second dimension
*/
- public static double[][] getMovingAverage(Number[] xData, Number[] yData,
- int period) {
+ public static double[] @ArrayLen(2) [] getMovingAverage(Number @SameLen("#2") [] xData, Number @SameLen("#1") [] yData,
+ @IndexFor("#1") int period) {
// check arguments...
if (xData.length != yData.length) {
@@ -452,13 +458,18 @@ public static double[][] getMovingAverage(Number[] xData, Number[] yData,
"Period can't be longer than dataset.");
}
- double[][] result = new double[xData.length - period][2];
+ @NonNegative int resultLen = xData.length - period;
+ double[] @ArrayLen(2) [] result = new double[resultLen][2];
for (int i = 0; i < result.length; i++) {
- result[i][0] = xData[i + period].doubleValue();
+ @SuppressWarnings("index") // result's length is exactly xData.length - period, so adding period to an index for result is always an index for xData
+ @IndexFor("xData") int iPeriod = i + period;
+ result[i][0] = xData[iPeriod].doubleValue();
// holds the moving average sum
double sum = 0.0;
for (int j = 0; j < period; j++) {
- sum += yData[i + j].doubleValue();
+ @SuppressWarnings("index") // result's length is exactly yData.length - period, so adding a nonnegative value less than period to an index for result is always an index for yData
+ @IndexFor("yData") int ij = i + j;
+ sum += yData[ij].doubleValue();
}
sum = sum / period;
result[i][1] = sum;
diff --git a/src/main/java/org/jfree/data/time/Day.java b/src/main/java/org/jfree/data/time/Day.java
index fd31a2361..77e1a5f42 100644
--- a/src/main/java/org/jfree/data/time/Day.java
+++ b/src/main/java/org/jfree/data/time/Day.java
@@ -65,6 +65,9 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
@@ -126,7 +129,7 @@ public Day() {
* @param month the month (1 to 12).
* @param year the year (1900 <= year <= 9999).
*/
- public Day(int day, int month, int year) {
+ public Day(@IntRange(from = 1, to = 31) int day, @IntRange(from = 1, to = 12) int month, @IntRange(from = 1900, to = 9999) int year) {
this.serialDate = SerialDate.createInstance(day, month, year);
peg(Calendar.getInstance());
}
@@ -162,6 +165,7 @@ public Day(Date time) {
* @param zone the time zone ({@code null} not permitted).
* @param locale the locale ({@code null} not permitted).
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Day(Date time, TimeZone zone, Locale locale) {
Args.nullNotPermitted(time, "time");
Args.nullNotPermitted(zone, "zone");
@@ -171,7 +175,8 @@ public Day(Date time, TimeZone zone, Locale locale) {
int d = calendar.get(Calendar.DAY_OF_MONTH);
int m = calendar.get(Calendar.MONTH) + 1;
int y = calendar.get(Calendar.YEAR);
- this.serialDate = SerialDate.createInstance(d, m, y);
+ SerialDate tmpDate = SerialDate.createInstance(d, m, y);
+ this.serialDate = tmpDate;
peg(calendar);
}
@@ -193,7 +198,7 @@ public SerialDate getSerialDate() {
*
* @return The year.
*/
- public int getYear() {
+ public @IntRange(from=1900, to=9999) int getYear() {
return this.serialDate.getYYYY();
}
@@ -202,7 +207,7 @@ public int getYear() {
*
* @return The month.
*/
- public int getMonth() {
+ public @IntRange(from = 1, to = 12) int getMonth() {
return this.serialDate.getMonth();
}
@@ -211,7 +216,7 @@ public int getMonth() {
*
* @return The day of the month.
*/
- public int getDayOfMonth() {
+ public @IntRange(from = 1, to = 31) int getDayOfMonth() {
return this.serialDate.getDayOfMonth();
}
diff --git a/src/main/java/org/jfree/data/time/DynamicTimeSeriesCollection.java b/src/main/java/org/jfree/data/time/DynamicTimeSeriesCollection.java
index 288c573f2..3d759cd05 100644
--- a/src/main/java/org/jfree/data/time/DynamicTimeSeriesCollection.java
+++ b/src/main/java/org/jfree/data/time/DynamicTimeSeriesCollection.java
@@ -62,6 +62,12 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.Calendar;
import java.util.TimeZone;
@@ -104,22 +110,22 @@ public class DynamicTimeSeriesCollection extends AbstractIntervalXYDataset
public static final int END = 2;
/** The maximum number of items for each series (can be overridden). */
- private int maximumItemCount = 2000; // an arbitrary safe default value
+ private @NonNegative int maximumItemCount = 2000; // an arbitrary safe default value
/** The history count. */
- protected int historyCount;
+ protected @LTEqLengthOf("this.pointsInTime") @Positive int historyCount;
/** Storage for the series keys. */
- private Comparable[] seriesKeys;
+ private Comparable @SameLen("this.valueHistory") [] seriesKeys;
/** The time period class - barely used, and could be removed (DG). */
private Class timePeriodClass = Minute.class; // default value;
/** Storage for the x-values. */
- protected RegularTimePeriod[] pointsInTime;
+ protected RegularTimePeriod @MinLen(1) [] pointsInTime;
/** The number of series. */
- private int seriesCount;
+ private @NonNegative int seriesCount;
/**
* A wrapper for a fixed array of float values.
@@ -127,7 +133,7 @@ public class DynamicTimeSeriesCollection extends AbstractIntervalXYDataset
protected class ValueSequence {
/** Storage for the float values. */
- float[] dataPoints;
+ float @SameLen("this") [] dataPoints;
/**
* Default constructor:
@@ -141,8 +147,10 @@ public ValueSequence() {
*
* @param length the length.
*/
- public ValueSequence(int length) {
- this.dataPoints = new float[length];
+ public ValueSequence(@NonNegative int length) {
+ @SuppressWarnings("index") // SameLen on custom collections requires a suppressed warning to establish representation invariant https://github.com/kelloggm/checker-framework/issues/213
+ float @SameLen("this") [] dataPointsTmp = new float[length];
+ this.dataPoints = dataPointsTmp;
for (int i = 0; i < length; i++) {
this.dataPoints[i] = 0.0f;
}
@@ -154,7 +162,7 @@ public ValueSequence(int length) {
* @param index the index.
* @param value the value.
*/
- public void enterData(int index, float value) {
+ public void enterData(@IndexFor("this") int index, float value) {
this.dataPoints[index] = value;
}
@@ -165,13 +173,13 @@ public void enterData(int index, float value) {
*
* @return The value.
*/
- public float getData(int index) {
+ public float getData(@IndexFor("this") int index) {
return this.dataPoints[index];
}
}
/** An array for storing the objects that represent each series. */
- protected ValueSequence[] valueHistory;
+ protected @SameLen("this.pointsInTime") ValueSequence @SameLen("this.seriesKeys") [] valueHistory;
/** A working calendar (to recycle) */
protected Calendar workingCalendar;
@@ -190,10 +198,10 @@ public float getData(int index) {
private boolean domainIsPointsInTime;
/** index for mapping: points to the oldest valid time and data. */
- private int oldestAt; // as a class variable, initializes == 0
+ private @IndexFor("this.pointsInTime") int oldestAt; // as a class variable, initializes == 0
/** Index of the newest data item. */
- private int newestAt;
+ private @IndexFor("this.pointsInTime") int newestAt;
// cached values used for interface DomainInfo:
@@ -228,9 +236,11 @@ public float getData(int index) {
* @param nSeries the number of series to be accommodated.
* @param nMoments the number of TimePeriods to be spanned.
*/
- public DynamicTimeSeriesCollection(int nSeries, int nMoments) {
+ public DynamicTimeSeriesCollection(@NonNegative int nSeries, @Positive int nMoments) {
this(nSeries, nMoments, new Millisecond(), TimeZone.getDefault());
- this.newestAt = nMoments - 1;
+ @SuppressWarnings("index") // nMoments is used later to populate the field this annotation refers to
+ @IndexFor("this.pointsInTime") int newestAtTmp = nMoments - 1;
+ this.newestAt = newestAtTmp;
}
/**
@@ -240,10 +250,12 @@ public DynamicTimeSeriesCollection(int nSeries, int nMoments) {
* @param nMoments the number of TimePeriods to be spanned
* @param zone the timezone.
*/
- public DynamicTimeSeriesCollection(int nSeries, int nMoments,
+ public DynamicTimeSeriesCollection(@NonNegative int nSeries, @Positive int nMoments,
TimeZone zone) {
this(nSeries, nMoments, new Millisecond(), zone);
- this.newestAt = nMoments - 1;
+ @SuppressWarnings("index") // nMoments is used later to populate the field this annotation refers to
+ @IndexFor("this.pointsInTime") int newestAtTmp = nMoments - 1;
+ this.newestAt = newestAtTmp;
}
/**
@@ -253,7 +265,7 @@ public DynamicTimeSeriesCollection(int nSeries, int nMoments,
* @param nMoments the number of items per series.
* @param timeSample a time period sample.
*/
- public DynamicTimeSeriesCollection(int nSeries, int nMoments,
+ public DynamicTimeSeriesCollection(@NonNegative int nSeries, @Positive int nMoments,
RegularTimePeriod timeSample) {
this(nSeries, nMoments, timeSample, TimeZone.getDefault());
}
@@ -266,7 +278,8 @@ public DynamicTimeSeriesCollection(int nSeries, int nMoments,
* @param timeSample a time period sample.
* @param zone the time zone.
*/
- public DynamicTimeSeriesCollection(int nSeries, int nMoments,
+ @SuppressWarnings("index") // this constructor establishes the repr. invariants
+ public DynamicTimeSeriesCollection(@NonNegative int nSeries, @Positive int nMoments,
RegularTimePeriod timeSample, TimeZone zone) {
// the first initialization must precede creation of the ValueSet array:
@@ -277,7 +290,6 @@ public DynamicTimeSeriesCollection(int nSeries, int nMoments,
for (int i = 0; i < nSeries; i++) {
this.seriesKeys[i] = "";
}
- this.newestAt = nMoments - 1;
this.valueHistory = new ValueSequence[nSeries];
this.timePeriodClass = timeSample.getClass();
@@ -291,6 +303,9 @@ public DynamicTimeSeriesCollection(int nSeries, int nMoments,
} else if (this.timePeriodClass == Hour.class) {
this.pointsInTime = new Hour[nMoments];
}
+
+ this.newestAt = nMoments - 1;
+
/// .. etc....
this.workingCalendar = Calendar.getInstance(zone);
this.position = START;
@@ -317,6 +332,7 @@ public synchronized long setTimeBase(RegularTimePeriod start) {
}
long oldestL = this.pointsInTime[0].getFirstMillisecond(
this.workingCalendar);
+ @SuppressWarnings("index") // This seems like a bug to me. There's nothing in the docs for this class that suggests that pointsInTime must have more than 1 element
long nextL = this.pointsInTime[1].getFirstMillisecond(
this.workingCalendar);
this.deltaTime = nextL - oldestL;
@@ -373,9 +389,8 @@ public void setPosition(int position) {
* Use this as-is during setup only, or add the synchronized keyword around
* the copy loop.
*/
- public void addSeries(float[] values, int seriesNumber,
+ public void addSeries(float @LengthOf("this.historyCount")[] values, @NonNegative int seriesNumber,
Comparable seriesKey) {
-
invalidateRangeInfo();
int i;
if (values == null) {
@@ -387,17 +402,20 @@ public void addSeries(float[] values, int seriesNumber,
+ "cannot add more series than specified in c'tor");
}
if (this.valueHistory[seriesNumber] == null) {
- this.valueHistory[seriesNumber]
- = new ValueSequence(this.historyCount);
+ @SuppressWarnings("index") // this.historyCount is the length of this.pointsInTime
+ @SameLen("this.pointsInTime") ValueSequence valueSequence = new ValueSequence(this.historyCount);
+ this.valueHistory[seriesNumber] = valueSequence;
this.seriesCount++;
}
// But if that series array already exists, just overwrite its contents
+ @SuppressWarnings("index") // https://github.com/kelloggm/checker-framework/issues/158: this.valueHistory[seriesNumber]'s length is <= this.historyCount
+ @IndexFor({"this.valueHistory[seriesNumber]","values"}) int historyCount = this.historyCount;
// Avoid IndexOutOfBoundsException:
int srcLength = values.length;
- int copyLength = this.historyCount;
+ int copyLength = historyCount;
boolean fillNeeded = false;
- if (srcLength < this.historyCount) {
+ if (srcLength < historyCount) {
fillNeeded = true;
copyLength = srcLength;
}
@@ -407,7 +425,7 @@ public void addSeries(float[] values, int seriesNumber,
this.valueHistory[seriesNumber].enterData(i, values[i]);
}
if (fillNeeded) {
- for (i = copyLength; i < this.historyCount; i++) {
+ for (i = copyLength; i < historyCount; i++) {
this.valueHistory[seriesNumber].enterData(i, 0.0f);
}
}
@@ -424,7 +442,7 @@ public void addSeries(float[] values, int seriesNumber,
* @param seriesNumber the series.
* @param key the new key.
*/
- public void setSeriesKey(int seriesNumber, Comparable key) {
+ public void setSeriesKey(@IndexFor("this.seriesKeys") int seriesNumber, Comparable key) {
this.seriesKeys[seriesNumber] = key;
}
@@ -435,7 +453,7 @@ public void setSeriesKey(int seriesNumber, Comparable key) {
* @param index ??.
* @param value the value.
*/
- public void addValue(int seriesNumber, int index, float value) {
+ public void addValue(@NonNegative int seriesNumber, @IndexFor("this.getSeries(#1)") int index, float value) {
invalidateRangeInfo();
if (seriesNumber >= this.valueHistory.length) {
throw new IllegalArgumentException(
@@ -444,14 +462,17 @@ public void addValue(int seriesNumber, int index, float value) {
);
}
if (this.valueHistory[seriesNumber] == null) {
- this.valueHistory[seriesNumber]
- = new ValueSequence(this.historyCount);
+ @SuppressWarnings("index") // this.historyCount is the length of this.pointsInTime
+ @SameLen("this.pointsInTime") ValueSequence valueSequence = new ValueSequence(this.historyCount);
+ this.valueHistory[seriesNumber] = valueSequence;
this.seriesCount++;
}
// But if that series array already exists, just overwrite its contents
//synchronized(this)
//{
- this.valueHistory[seriesNumber].enterData(index, value);
+ @SuppressWarnings("index") // String array bug https://github.com/kelloggm/checker-framework/issues/205
+ @LTLengthOf("this.valueHistory[seriesNumber]") int index0 = index;
+ this.valueHistory[seriesNumber].enterData(index0, value);
//}
fireSeriesChanged();
}
@@ -462,7 +483,8 @@ public void addValue(int seriesNumber, int index, float value) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ @SuppressWarnings("index")
+ public @NonNegative @LTEqLengthOf("this.valueHistory") int getSeriesCount() {
return this.seriesCount;
}
@@ -476,7 +498,8 @@ public int getSeriesCount() {
* @return The item count.
*/
@Override
- public int getItemCount(int series) { // all arrays equal length,
+ @SuppressWarnings("index") // SameLen to a method with any argument https://github.com/kelloggm/checker-framework/issues/209: I'd like to write SameLen on this.pointsInTime
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) { // all arrays equal length,
// so ignore argument:
return this.historyCount;
}
@@ -487,10 +510,12 @@ public int getItemCount(int series) { // all arrays equal length,
* Re-map an index, for use in retrieving data.
*
* @param toFetch the index.
+ * @param series a ghost variable necessary for the annotations
*
* @return The translated index.
*/
- protected int translateGet(int toFetch) {
+ @SuppressWarnings("index") // internal method that breaks abstraction boundaries
+ protected @IndexFor("this.pointsInTime") int translateGet(@IndexFor("this.getSeries(#2)") int toFetch, int series) {
if (this.oldestAt == 0) {
return toFetch; // no translation needed
}
@@ -509,7 +534,7 @@ protected int translateGet(int toFetch) {
*
* @return The offset.
*/
- public int offsetFromNewest(int delta) {
+ public @IndexFor("this.pointsInTime") int offsetFromNewest(int delta) {
return wrapOffset(this.newestAt + delta);
}
@@ -520,7 +545,7 @@ public int offsetFromNewest(int delta) {
*
* @return The offset.
*/
- public int offsetFromOldest(int delta) {
+ public @IndexFor("this.pointsInTime") int offsetFromOldest(int delta) {
return wrapOffset(this.oldestAt + delta);
}
@@ -531,7 +556,8 @@ public int offsetFromOldest(int delta) {
*
* @return The offset.
*/
- protected int wrapOffset(int protoIndex) {
+ @SuppressWarnings("index") // this method assumes that protoIndex will be within an absolute value of an actual index
+ protected @IndexFor("this.pointsInTime") int wrapOffset(int protoIndex) {
int tmp = protoIndex;
if (tmp >= this.historyCount) {
tmp -= this.historyCount;
@@ -564,7 +590,9 @@ public synchronized RegularTimePeriod advanceTime() {
oldMax = this.maxValue.floatValue();
}
for (int s = 0; s < getSeriesCount(); s++) {
- if (this.valueHistory[s].getData(this.oldestAt) == oldMax) {
+ @SuppressWarnings("index") // String array bug https://github.com/kelloggm/checker-framework/issues/205
+ @LTLengthOf("this.valueHistory[s]") int oldestAt = this.oldestAt;
+ if (this.valueHistory[s].getData(oldestAt) == oldMax) {
extremaChanged = true;
}
if (extremaChanged) {
@@ -577,15 +605,22 @@ public synchronized RegularTimePeriod advanceTime() {
// wipe the next (about to be used) set of data slots
float wiper = (float) 0.0;
for (int s = 0; s < getSeriesCount(); s++) {
- this.valueHistory[s].enterData(this.newestAt, wiper);
+ @SuppressWarnings("index") // String array bug https://github.com/kelloggm/checker-framework/issues/205
+ @LTLengthOf("this.valueHistory[s]") int newestAt = this.newestAt;
+ this.valueHistory[s].enterData(newestAt, wiper);
}
// Update the array of TimePeriods:
this.pointsInTime[this.newestAt] = nextInstant;
// Now advance "oldestAt", wrapping at end of the array
- this.oldestAt++;
+ int newOldestAt;
if (this.oldestAt >= this.historyCount) {
- this.oldestAt = 0;
+ newOldestAt = 0;
+ } else {
+ newOldestAt = this.oldestAt + 1;
}
+ @SuppressWarnings("index") // the check right above ensures this doesn't go out of bounds
+ @IndexFor("this.pointsInTime") int tmp = newOldestAt;
+ this.oldestAt = tmp;
// Update the domain limits:
long startL = this.domainStart.longValue(); //(time is kept in msec)
this.domainStart = new Long(startL + this.deltaTime);
@@ -615,7 +650,9 @@ protected double findMaxValue() {
double max = 0.0f;
for (int s = 0; s < getSeriesCount(); s++) {
for (int i = 0; i < this.historyCount; i++) {
- double tmp = getYValue(s, i);
+ @SuppressWarnings("index") // String array bug https://github.com/kelloggm/checker-framework/issues/205
+ @LTLengthOf("this.getSeries(s)") int i0 = i;
+ double tmp = getYValue(s, i0);
if (tmp > max) {
max = tmp;
}
@@ -631,7 +668,7 @@ protected double findMaxValue() {
*
* @return The index.
*/
- public int getOldestIndex() {
+ public @IndexFor("this.pointsInTime") int getOldestIndex() {
return this.oldestAt;
}
@@ -640,7 +677,7 @@ public int getOldestIndex() {
*
* @return The index.
*/
- public int getNewestIndex() {
+ public @IndexFor("this.pointsInTime") int getNewestIndex() {
return this.newestAt;
}
@@ -662,9 +699,13 @@ public void appendData(float[] newData) {
// check whether the "valueHistory" array member exists; if not,
// create them:
if (this.valueHistory[s] == null) {
- this.valueHistory[s] = new ValueSequence(this.historyCount);
+ @SuppressWarnings("index") // this.historyCount is the length of this.pointsInTime
+ @SameLen("this.pointsInTime") ValueSequence valueSequence = new ValueSequence(this.historyCount);
+ this.valueHistory[s] = valueSequence;
}
- this.valueHistory[s].enterData(this.newestAt, newData[s]);
+ @SuppressWarnings("index") // String array bug https://github.com/kelloggm/checker-framework/issues/205
+ @LTLengthOf("this.valueHistory[s]") int newestAt = this.newestAt;
+ this.valueHistory[s].enterData(newestAt, newData[s]);
}
fireSeriesChanged();
}
@@ -677,7 +718,7 @@ public void appendData(float[] newData) {
* @param refresh value of n in "refresh the display on every nth call"
* (ignored if <= 0 )
*/
- public void appendData(float[] newData, int insertionIndex, int refresh) {
+ public void appendData(float[] newData, final @IndexFor("this.pointsInTime") int insertionIndex, int refresh) {
int nDataPoints = newData.length;
if (nDataPoints > this.valueHistory.length) {
throw new IllegalArgumentException(
@@ -685,13 +726,17 @@ public void appendData(float[] newData, int insertionIndex, int refresh) {
}
for (int s = 0; s < nDataPoints; s++) {
if (this.valueHistory[s] == null) {
- this.valueHistory[s] = new ValueSequence(this.historyCount);
+ @SuppressWarnings("index") // this.historyCount is the length of this.pointsInTime
+ @SameLen("this.pointsInTime") ValueSequence valueSequence = new ValueSequence(this.historyCount);
+ this.valueHistory[s] = valueSequence;
}
- this.valueHistory[s].enterData(insertionIndex, newData[s]);
+ @SuppressWarnings("index") // String array bug https://github.com/kelloggm/checker-framework/issues/205
+ @LTLengthOf("this.valueHistory[s]") int insertionIndex0 = insertionIndex;
+ this.valueHistory[s].enterData(insertionIndex0, newData[s]);
}
if (refresh > 0) {
- insertionIndex++;
- if (insertionIndex % refresh == 0) {
+ int insertionIndexPlus = insertionIndex + 1;
+ if (insertionIndexPlus % refresh == 0) {
fireSeriesChanged();
}
}
@@ -726,8 +771,8 @@ public RegularTimePeriod getOldestTime() {
// getXxx() ftns can ignore the "series" argument:
// Don't synchronize this!! Instead, synchronize the loop that calls it.
@Override
- public Number getX(int series, int item) {
- RegularTimePeriod tp = this.pointsInTime[translateGet(item)];
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ RegularTimePeriod tp = this.pointsInTime[translateGet(item, series)];
return new Long(getX(tp));
}
@@ -740,11 +785,12 @@ public Number getX(int series, int item) {
* @return The value.
*/
@Override
- public double getYValue(int series, int item) {
+ public double getYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
// Don't synchronize this!!
// Instead, synchronize the loop that calls it.
+ @SuppressWarnings("index") // array-list interop: every other class that implements these interfaces uses a list to store series, so the annotation here is wrong
ValueSequence values = this.valueHistory[series];
- return values.getData(translateGet(item));
+ return values.getData(translateGet(item, series));
}
/**
@@ -756,7 +802,7 @@ public double getYValue(int series, int item) {
* @return The value.
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Float(getYValue(series, item));
}
@@ -769,8 +815,8 @@ public Number getY(int series, int item) {
* @return The value.
*/
@Override
- public Number getStartX(int series, int item) {
- RegularTimePeriod tp = this.pointsInTime[translateGet(item)];
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ RegularTimePeriod tp = this.pointsInTime[translateGet(item, series)];
return new Long(tp.getFirstMillisecond(this.workingCalendar));
}
@@ -783,8 +829,8 @@ public Number getStartX(int series, int item) {
* @return The value.
*/
@Override
- public Number getEndX(int series, int item) {
- RegularTimePeriod tp = this.pointsInTime[translateGet(item)];
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ RegularTimePeriod tp = this.pointsInTime[translateGet(item, series)];
return new Long(tp.getLastMillisecond(this.workingCalendar));
}
@@ -797,7 +843,7 @@ public Number getEndX(int series, int item) {
* @return The value.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -810,17 +856,17 @@ public Number getStartY(int series, int item) {
* @return The value.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
/* // "Extras" found useful when analyzing/verifying class behavior:
- public Number getUntranslatedXValue(int series, int item)
+ public Number getUntranslatedXValue(int series, @NonNegative int item)
{
return super.getXValue(series, item);
}
- public float getUntranslatedY(int series, int item)
+ public float getUntranslatedY(int series, @NonNegative int item)
{
return super.getY(series, item);
} */
@@ -833,7 +879,8 @@ public float getUntranslatedY(int series, int item)
* @return The key.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ @SuppressWarnings("index") // array-list interop: every other class that implements this interface backs the series with a list, so the annotation on this class don't correspond to the ones on the interface
+ public Comparable getSeriesKey(@IndexFor("this.seriesKeys") int series) {
return this.seriesKeys[series];
}
diff --git a/src/main/java/org/jfree/data/time/Hour.java b/src/main/java/org/jfree/data/time/Hour.java
index 9048ed7d9..53df9796f 100644
--- a/src/main/java/org/jfree/data/time/Hour.java
+++ b/src/main/java/org/jfree/data/time/Hour.java
@@ -66,6 +66,8 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
@@ -92,7 +94,7 @@ public class Hour extends RegularTimePeriod implements Serializable {
private Day day;
/** The hour. */
- private byte hour;
+ @IntRange(from = 0, to = 23) private byte hour;
/** The first millisecond. */
private long firstMillisecond;
@@ -113,7 +115,7 @@ public Hour() {
* @param hour the hour (in the range 0 to 23).
* @param day the day ({@code null} not permitted).
*/
- public Hour(int hour, Day day) {
+ public Hour(@IntRange(from = 0, to = 23) int hour, Day day) {
Args.nullNotPermitted(day, "day");
this.hour = (byte) hour;
this.day = day;
@@ -128,7 +130,7 @@ public Hour(int hour, Day day) {
* @param month the month (1-12).
* @param year the year (1900-9999).
*/
- public Hour(int hour, int day, int month, int year) {
+ public Hour(@IntRange(from = 0, to = 23) int hour, @IntRange(from = 1, to = 31) int day, @IntRange(from = 1, to = 12) int month, @IntRange(from = 1900, to = 9999) int year) {
this(hour, new Day(day, month, year));
}
@@ -155,6 +157,7 @@ public Hour(Date time) {
*
* @since 1.0.13
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Hour(Date time, TimeZone zone, Locale locale) {
Args.nullNotPermitted(time, "time");
Args.nullNotPermitted(zone, "zone");
@@ -171,7 +174,7 @@ public Hour(Date time, TimeZone zone, Locale locale) {
*
* @return The hour (0 <= hour <= 23).
*/
- public int getHour() {
+ public @IntRange(from = 0, to = 23) int getHour() {
return this.hour;
}
@@ -189,7 +192,7 @@ public Day getDay() {
*
* @return The year.
*/
- public int getYear() {
+ public @IntRange(from = 1900, to = 9999) int getYear() {
return this.day.getYear();
}
@@ -198,7 +201,7 @@ public int getYear() {
*
* @return The month.
*/
- public int getMonth() {
+ public @IntRange(from = 1, to = 12) int getMonth() {
return this.day.getMonth();
}
@@ -207,7 +210,7 @@ public int getMonth() {
*
* @return The day-of-the-month.
*/
- public int getDayOfMonth() {
+ public @IntRange(from = 1, to = 31) int getDayOfMonth() {
return this.day.getDayOfMonth();
}
diff --git a/src/main/java/org/jfree/data/time/Millisecond.java b/src/main/java/org/jfree/data/time/Millisecond.java
index 864f0d3ca..beeba0933 100644
--- a/src/main/java/org/jfree/data/time/Millisecond.java
+++ b/src/main/java/org/jfree/data/time/Millisecond.java
@@ -60,6 +60,8 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
@@ -85,16 +87,16 @@ public class Millisecond extends RegularTimePeriod implements Serializable {
private Day day;
/** The hour in the day. */
- private byte hour;
+ @IntRange(from = 0, to = 23) private byte hour;
/** The minute. */
- private byte minute;
+ @IntRange(from = 0, to = 59) private byte minute;
/** The second. */
- private byte second;
+ @IntRange(from = 0, to = 59) private byte second;
/** The millisecond. */
- private int millisecond;
+ @IntRange(from = 0, to = 999) private int millisecond;
/**
* The pegged millisecond.
@@ -114,7 +116,7 @@ public Millisecond() {
* @param millisecond the millisecond (0-999).
* @param second the second.
*/
- public Millisecond(int millisecond, Second second) {
+ public Millisecond(@IntRange(from = 0, to = 999) int millisecond, Second second) {
this.millisecond = millisecond;
this.second = (byte) second.getSecond();
this.minute = (byte) second.getMinute().getMinute();
@@ -134,8 +136,8 @@ public Millisecond(int millisecond, Second second) {
* @param month the month (1-12).
* @param year the year (1900-9999).
*/
- public Millisecond(int millisecond, int second, int minute, int hour,
- int day, int month, int year) {
+ public Millisecond(@IntRange(from = 0, to = 999) int millisecond, @IntRange(from = 0, to = 59) int second, @IntRange(from = 0, to = 59) int minute, @IntRange(from = 0, to = 23) int hour,
+ @IntRange(from = 1, to = 31) int day, @IntRange(from = 1, to = 12) int month, @IntRange(from = 1900, to = 9999) int year) {
this(millisecond, new Second(second, minute, hour, day, month, year));
@@ -161,6 +163,7 @@ public Millisecond(Date time) {
*
* @since 1.0.13
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Millisecond(Date time, TimeZone zone, Locale locale) {
Calendar calendar = Calendar.getInstance(zone, locale);
calendar.setTime(time);
diff --git a/src/main/java/org/jfree/data/time/Minute.java b/src/main/java/org/jfree/data/time/Minute.java
index 1e7d2316b..0801251e6 100644
--- a/src/main/java/org/jfree/data/time/Minute.java
+++ b/src/main/java/org/jfree/data/time/Minute.java
@@ -67,6 +67,8 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
@@ -93,10 +95,10 @@ public class Minute extends RegularTimePeriod implements Serializable {
private Day day;
/** The hour in which the minute falls. */
- private byte hour;
+ @IntRange(from = 0, to = 23) private byte hour;
/** The minute. */
- private byte minute;
+ @IntRange(from = 0, to = 59) private byte minute;
/** The first millisecond. */
private long firstMillisecond;
@@ -117,7 +119,7 @@ public Minute() {
* @param minute the minute (0 to 59).
* @param hour the hour ({@code null} not permitted).
*/
- public Minute(int minute, Hour hour) {
+ public Minute(@IntRange(from = 0, to = 59) int minute, Hour hour) {
Args.nullNotPermitted(hour, "hour");
this.minute = (byte) minute;
this.hour = (byte) hour.getHour();
@@ -147,6 +149,7 @@ public Minute(Date time) {
*
* @since 1.0.13
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Minute(Date time, TimeZone zone, Locale locale) {
Args.nullNotPermitted(time, "time");
Args.nullNotPermitted(zone, "zone");
@@ -169,7 +172,7 @@ public Minute(Date time, TimeZone zone, Locale locale) {
* @param month the month (1-12).
* @param year the year (1900-9999).
*/
- public Minute(int minute, int hour, int day, int month, int year) {
+ public Minute(@IntRange(from = 0, to = 59) int minute, @IntRange(from = 0, to = 23) int hour, @IntRange(from = 1, to = 31) int day, @IntRange(from = 1, to = 12) int month, @IntRange(from = 1900, to = 9999) int year) {
this(minute, new Hour(hour, new Day(day, month, year)));
}
@@ -200,7 +203,7 @@ public Hour getHour() {
*
* @since 1.0.3
*/
- public int getHourValue() {
+ public @IntRange(from = 0, to = 23) int getHourValue() {
return this.hour;
}
@@ -209,7 +212,7 @@ public int getHourValue() {
*
* @return The minute.
*/
- public int getMinute() {
+ public @IntRange(from = 0, to = 59) int getMinute() {
return this.minute;
}
diff --git a/src/main/java/org/jfree/data/time/Month.java b/src/main/java/org/jfree/data/time/Month.java
index cc0c30f6b..76e1ffeaa 100644
--- a/src/main/java/org/jfree/data/time/Month.java
+++ b/src/main/java/org/jfree/data/time/Month.java
@@ -66,6 +66,8 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
@@ -84,10 +86,10 @@ public class Month extends RegularTimePeriod implements Serializable {
private static final long serialVersionUID = -5090216912548722570L;
/** The month (1-12). */
- private int month;
+ private @IntRange(from = 1, to = 12) int month;
/** The year in which the month falls. */
- private int year;
+ private @IntRange(from = 0, to = 9999) int year;
/** The first millisecond. */
private long firstMillisecond;
@@ -108,7 +110,7 @@ public Month() {
* @param month the month (in the range 1 to 12).
* @param year the year.
*/
- public Month(int month, int year) {
+ public Month(@IntRange(from = 1, to = 12) int month, @IntRange(from = 0, to = 9999) int year) {
if ((month < 1) || (month > 12)) {
throw new IllegalArgumentException("Month outside valid range.");
}
@@ -123,7 +125,7 @@ public Month(int month, int year) {
* @param month the month (in the range 1 to 12).
* @param year the year.
*/
- public Month(int month, Year year) {
+ public Month(@IntRange(from = 1, to = 12) int month, Year year) {
if ((month < 1) || (month > 12)) {
throw new IllegalArgumentException("Month outside valid range.");
}
@@ -154,6 +156,7 @@ public Month(Date time) {
*
* @since 1.0.12
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Month(Date time, TimeZone zone, Locale locale) {
Calendar calendar = Calendar.getInstance(zone, locale);
calendar.setTime(time);
@@ -439,6 +442,7 @@ public long getLastMillisecond(Calendar calendar) {
* @return {@code null} if the string is not parseable, the month
* otherwise.
*/
+ @SuppressWarnings({"value", "index"}) // This method repeatedly assumes properties of the String s, especially that it is "wellformed" according to the documentation (i.e. either YYYY-MM or MM-YYYY)
public static Month parseMonth(String s) {
Month result = null;
if (s == null) {
diff --git a/src/main/java/org/jfree/data/time/MovingAverage.java b/src/main/java/org/jfree/data/time/MovingAverage.java
index c45ab2e49..075bb74c4 100644
--- a/src/main/java/org/jfree/data/time/MovingAverage.java
+++ b/src/main/java/org/jfree/data/time/MovingAverage.java
@@ -50,6 +50,11 @@
package org.jfree.data.time;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.chart.util.Args;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
@@ -74,7 +79,7 @@ public class MovingAverage {
* @return A collection of moving average time series.
*/
public static TimeSeriesCollection createMovingAverage(
- TimeSeriesCollection source, String suffix, int periodCount,
+ TimeSeriesCollection source, String suffix, @Positive int periodCount,
int skip) {
Args.nullNotPermitted(source, "source");
@@ -108,7 +113,7 @@ public static TimeSeriesCollection createMovingAverage(
* @return The moving average series.
*/
public static TimeSeries createMovingAverage(TimeSeries source,
- String name, int periodCount, int skip) {
+ String name, @Positive int periodCount, int skip) {
Args.nullNotPermitted(source, "source");
if (periodCount < 1) {
@@ -140,9 +145,10 @@ public static TimeSeries createMovingAverage(TimeSeries source,
boolean finished = false;
while ((offset < periodCount) && (!finished)) {
- if ((i - offset) >= 0) {
+ int itemIndex = i - offset;
+ if (itemIndex >= 0) {
TimeSeriesDataItem item = source.getRawDataItem(
- i - offset);
+ itemIndex);
RegularTimePeriod p = item.getPeriod();
Number v = item.getValue();
long currentIndex = p.getSerialIndex();
@@ -189,7 +195,7 @@ public static TimeSeries createMovingAverage(TimeSeries source,
* @return The moving average series.
*/
public static TimeSeries createPointMovingAverage(TimeSeries source,
- String name, int pointCount) {
+ String name, @Positive int pointCount) {
Args.nullNotPermitted(source, "source");
if (pointCount < 2) {
@@ -206,15 +212,16 @@ public static TimeSeries createPointMovingAverage(TimeSeries source,
// FIXME: what if value is null on next line?
rollingSumForPeriod += current.getValue().doubleValue();
- if (i > pointCount - 1) {
+ int startIndex = i - pointCount;
+ if (startIndex >= 0) {
// remove the point i-periodCount out of the rolling sum.
TimeSeriesDataItem startOfMovingAvg = source.getRawDataItem(
- i - pointCount);
+ startIndex);
rollingSumForPeriod -= startOfMovingAvg.getValue()
.doubleValue();
result.add(period, rollingSumForPeriod / pointCount);
}
- else if (i == pointCount - 1) {
+ else if (startIndex == - 1) {
result.add(period, rollingSumForPeriod / pointCount);
}
}
@@ -280,7 +287,7 @@ public static XYDataset createMovingAverage(XYDataset source,
* @return The dataset.
*/
public static XYSeries createMovingAverage(XYDataset source,
- int series, String name, double period, double skip) {
+ @NonNegative int series, String name, double period, double skip) {
Args.nullNotPermitted(source, "source");
if (period < Double.MIN_VALUE) {
@@ -296,6 +303,7 @@ public static XYSeries createMovingAverage(XYDataset source,
// if the initial averaging period is to be excluded, then
// calculate the lowest x-value to have an average calculated...
+ @SuppressWarnings("index") // item count was checked just above to be greater than zero, so zero is an index
double first = source.getXValue(series, 0) + skip;
for (int i = source.getItemCount(series) - 1; i >= 0; i--) {
@@ -312,9 +320,10 @@ public static XYSeries createMovingAverage(XYDataset source,
boolean finished = false;
while (!finished) {
- if ((i - offset) >= 0) {
- double xx = source.getXValue(series, i - offset);
- Number yy = source.getY(series, i - offset);
+ int ioff = i - offset;
+ if (ioff >= 0) {
+ double xx = source.getXValue(series, ioff);
+ Number yy = source.getY(series, ioff);
if (xx > limit) {
if (yy != null) {
sum = sum + yy.doubleValue();
diff --git a/src/main/java/org/jfree/data/time/Quarter.java b/src/main/java/org/jfree/data/time/Quarter.java
index 2097a0d4d..5f867d4b9 100644
--- a/src/main/java/org/jfree/data/time/Quarter.java
+++ b/src/main/java/org/jfree/data/time/Quarter.java
@@ -61,6 +61,9 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
@@ -86,22 +89,22 @@ public class Quarter extends RegularTimePeriod implements Serializable {
public static final int LAST_QUARTER = 4;
/** The first month in each quarter. */
- public static final int[] FIRST_MONTH_IN_QUARTER = {
+ public static final int @ArrayLen(5) [] FIRST_MONTH_IN_QUARTER = {
0, MonthConstants.JANUARY, MonthConstants.APRIL, MonthConstants.JULY,
MonthConstants.OCTOBER
};
/** The last month in each quarter. */
- public static final int[] LAST_MONTH_IN_QUARTER = {
+ public static final @IntRange(from = 0, to = 12) int @ArrayLen(5) [] LAST_MONTH_IN_QUARTER = {
0, MonthConstants.MARCH, MonthConstants.JUNE, MonthConstants.SEPTEMBER,
MonthConstants.DECEMBER
};
/** The year in which the quarter falls. */
- private short year;
+ @IntRange(from = 0, to = 9999) private short year;
/** The quarter (1-4). */
- private byte quarter;
+ private @IntVal({1,2,3,4}) byte quarter;
/** The first millisecond. */
private long firstMillisecond;
@@ -122,7 +125,7 @@ public Quarter() {
* @param year the year (1900 to 9999).
* @param quarter the quarter (1 to 4).
*/
- public Quarter(int quarter, int year) {
+ public Quarter(@IntVal({1,2,3,4}) int quarter, @IntRange(from=0, to = 9999)int year) {
if ((quarter < FIRST_QUARTER) || (quarter > LAST_QUARTER)) {
throw new IllegalArgumentException("Quarter outside valid range.");
}
@@ -137,7 +140,7 @@ public Quarter(int quarter, int year) {
* @param quarter the quarter (1 to 4).
* @param year the year (1900 to 9999).
*/
- public Quarter(int quarter, Year year) {
+ public Quarter(@IntVal({1,2,3,4}) int quarter, Year year) {
if ((quarter < FIRST_QUARTER) || (quarter > LAST_QUARTER)) {
throw new IllegalArgumentException("Quarter outside valid range.");
}
@@ -168,6 +171,7 @@ public Quarter(Date time) {
*
* @since 1.0.12
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Quarter(Date time, TimeZone zone, Locale locale) {
Calendar calendar = Calendar.getInstance(zone, locale);
calendar.setTime(time);
@@ -182,7 +186,7 @@ public Quarter(Date time, TimeZone zone, Locale locale) {
*
* @return The quarter.
*/
- public int getQuarter() {
+ public @IntVal({1,2,3,4}) int getQuarter() {
return this.quarter;
}
@@ -202,7 +206,7 @@ public Year getYear() {
*
* @since 1.0.3
*/
- public int getYearValue() {
+ public @IntRange(from = -9999, to = 9999) int getYearValue() {
return this.year;
}
@@ -418,7 +422,8 @@ public String toString() {
*/
@Override
public long getFirstMillisecond(Calendar calendar) {
- int month = Quarter.FIRST_MONTH_IN_QUARTER[this.quarter];
+ @SuppressWarnings("index") // month >= 1, since months are 1 to 12. this.quarter is 1 to 4, so it can't access the 0th value in FIRST_MONTH_IN_QUARTER, which is the only non positive value
+ @Positive int month = Quarter.FIRST_MONTH_IN_QUARTER[this.quarter];
calendar.set(this.year, month - 1, 1, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTimeInMillis();
@@ -437,7 +442,8 @@ public long getFirstMillisecond(Calendar calendar) {
*/
@Override
public long getLastMillisecond(Calendar calendar) {
- int month = Quarter.LAST_MONTH_IN_QUARTER[this.quarter];
+ @SuppressWarnings({"index", "value"}) // this.quarter is always 1, 2, 3, or 4 - and only the 0th element of this array is out of the range 1-12
+ @IntRange(from = 1, to = 12) int month = Quarter.LAST_MONTH_IN_QUARTER[this.quarter];
int eom = SerialDate.lastDayOfMonth(month, this.year);
calendar.set(this.year, month - 1, eom, 23, 59, 59);
calendar.set(Calendar.MILLISECOND, 999);
@@ -453,6 +459,7 @@ public long getLastMillisecond(Calendar calendar) {
*
* @return The quarter.
*/
+ @SuppressWarnings({"index", "value"}) // parse method relies on string being properly formatted
public static Quarter parseQuarter(String s) {
// find the Q and the integer following it (remove both from the
diff --git a/src/main/java/org/jfree/data/time/RegularTimePeriod.java b/src/main/java/org/jfree/data/time/RegularTimePeriod.java
index a396266bf..2f7f473ff 100644
--- a/src/main/java/org/jfree/data/time/RegularTimePeriod.java
+++ b/src/main/java/org/jfree/data/time/RegularTimePeriod.java
@@ -54,6 +54,8 @@
package org.jfree.data.time;
+import org.checkerframework.dataflow.qual.Pure;
+
import java.lang.reflect.Constructor;
import java.util.Calendar;
import java.util.Date;
@@ -177,6 +179,7 @@ else if (c.equals(Second.class)) {
* @see #getFirstMillisecond()
*/
@Override
+ @Pure
public Date getStart() {
return new Date(getFirstMillisecond());
}
diff --git a/src/main/java/org/jfree/data/time/Second.java b/src/main/java/org/jfree/data/time/Second.java
index 47beeb956..14f2e29b0 100644
--- a/src/main/java/org/jfree/data/time/Second.java
+++ b/src/main/java/org/jfree/data/time/Second.java
@@ -62,6 +62,8 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
@@ -88,13 +90,13 @@ public class Second extends RegularTimePeriod implements Serializable {
private Day day;
/** The hour of the day. */
- private byte hour;
+ @IntRange(from = 0, to = 23) private byte hour;
/** The minute. */
- private byte minute;
+ @IntRange(from = 0, to = 59) private byte minute;
/** The second. */
- private byte second;
+ @IntRange(from = 0, to = 59) private byte second;
/**
* The first millisecond. We don't store the last millisecond, because it
@@ -115,7 +117,7 @@ public Second() {
* @param second the second (0 to 59).
* @param minute the minute ({@code null} not permitted).
*/
- public Second(int second, Minute minute) {
+ public Second(@IntRange(from = 0, to = 59) int second, Minute minute) {
Args.requireInRange(second, "second",
Second.FIRST_SECOND_IN_MINUTE, Second.LAST_SECOND_IN_MINUTE);
Args.nullNotPermitted(minute, "minute");
@@ -136,8 +138,8 @@ public Second(int second, Minute minute) {
* @param month the month (1-12).
* @param year the year (1900-9999).
*/
- public Second(int second, int minute, int hour,
- int day, int month, int year) {
+ public Second(@IntRange(from = 0, to = 59) int second, @IntRange(from = 0, to = 59) int minute, @IntRange(from = 0, to = 23) int hour,
+ @IntRange(from = 1, to = 31) int day, @IntRange(from = 1, to = 12) int month, @IntRange(from = 1900, to = 9999) int year) {
this(second, new Minute(minute, hour, day, month, year));
}
@@ -162,6 +164,7 @@ public Second(Date time) {
*
* @since 1.0.13
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Second(Date time, TimeZone zone, Locale locale) {
Calendar calendar = Calendar.getInstance(zone, locale);
calendar.setTime(time);
@@ -177,7 +180,7 @@ public Second(Date time, TimeZone zone, Locale locale) {
*
* @return The second (0 - 59).
*/
- public int getSecond() {
+ public @IntRange(from = 0, to = 59) int getSecond() {
return this.second;
}
diff --git a/src/main/java/org/jfree/data/time/SimpleTimePeriod.java b/src/main/java/org/jfree/data/time/SimpleTimePeriod.java
index 9e081a1c5..d4e3769da 100644
--- a/src/main/java/org/jfree/data/time/SimpleTimePeriod.java
+++ b/src/main/java/org/jfree/data/time/SimpleTimePeriod.java
@@ -46,6 +46,8 @@
package org.jfree.data.time;
+import org.checkerframework.dataflow.qual.Pure;
+
import java.io.Serializable;
import java.util.Date;
@@ -97,6 +99,7 @@ public SimpleTimePeriod(Date start, Date end) {
* @return The start date/time (never {@code null}).
*/
@Override
+ @Pure
public Date getStart() {
return new Date(this.start);
}
diff --git a/src/main/java/org/jfree/data/time/TimePeriod.java b/src/main/java/org/jfree/data/time/TimePeriod.java
index f1b1a7ec7..3bbdc37e9 100644
--- a/src/main/java/org/jfree/data/time/TimePeriod.java
+++ b/src/main/java/org/jfree/data/time/TimePeriod.java
@@ -42,6 +42,8 @@
package org.jfree.data.time;
+import org.checkerframework.dataflow.qual.Pure;
+
import java.util.Date;
/**
@@ -56,6 +58,7 @@ public interface TimePeriod extends Comparable {
*
* @return The start date/time (never {@code null}).
*/
+ @Pure
public Date getStart();
/**
diff --git a/src/main/java/org/jfree/data/time/TimePeriodValue.java b/src/main/java/org/jfree/data/time/TimePeriodValue.java
index b403f9fb6..9615d9b2b 100644
--- a/src/main/java/org/jfree/data/time/TimePeriodValue.java
+++ b/src/main/java/org/jfree/data/time/TimePeriodValue.java
@@ -43,6 +43,8 @@
package org.jfree.data.time;
+import org.checkerframework.dataflow.qual.Pure;
+
import java.io.Serializable;
import org.jfree.chart.util.Args;
@@ -91,6 +93,7 @@ public TimePeriodValue(TimePeriod period, double value) {
*
* @return The time period (never {@code null}).
*/
+ @Pure
public TimePeriod getPeriod() {
return this.period;
}
diff --git a/src/main/java/org/jfree/data/time/TimePeriodValues.java b/src/main/java/org/jfree/data/time/TimePeriodValues.java
index a9119bebd..daa6d1fd5 100644
--- a/src/main/java/org/jfree/data/time/TimePeriodValues.java
+++ b/src/main/java/org/jfree/data/time/TimePeriodValues.java
@@ -48,6 +48,11 @@
package org.jfree.data.time;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.checker.index.qual.GTENegativeOne;
+import org.checkerframework.checker.index.qual.NonNegative;
+import org.checkerframework.checker.index.qual.LessThan;
+
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@@ -87,22 +92,22 @@ public class TimePeriodValues extends Series implements Serializable {
private List data;
/** Index of the time period with the minimum start milliseconds. */
- private int minStartIndex = -1;
+ private @GTENegativeOne int minStartIndex = -1;
/** Index of the time period with the maximum start milliseconds. */
- private int maxStartIndex = -1;
+ private @GTENegativeOne int maxStartIndex = -1;
/** Index of the time period with the minimum middle milliseconds. */
- private int minMiddleIndex = -1;
+ private @GTENegativeOne int minMiddleIndex = -1;
/** Index of the time period with the maximum middle milliseconds. */
- private int maxMiddleIndex = -1;
+ private @GTENegativeOne int maxMiddleIndex = -1;
/** Index of the time period with the minimum end milliseconds. */
- private int minEndIndex = -1;
+ private @GTENegativeOne int minEndIndex = -1;
/** Index of the time period with the maximum end milliseconds. */
- private int maxEndIndex = -1;
+ private @GTENegativeOne int maxEndIndex = -1;
/**
* Creates a new (empty) collection of time period values.
@@ -189,7 +194,7 @@ public void setRangeDescription(String description) {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.data.size();
}
@@ -201,7 +206,8 @@ public int getItemCount() {
*
* @return One data item for the series.
*/
- public TimePeriodValue getDataItem(int index) {
+ @Pure
+ public TimePeriodValue getDataItem(@NonNegative int index) {
return (TimePeriodValue) this.data.get(index);
}
@@ -215,7 +221,7 @@ public TimePeriodValue getDataItem(int index) {
*
* @see #getDataItem(int)
*/
- public TimePeriod getTimePeriod(int index) {
+ public TimePeriod getTimePeriod(@NonNegative int index) {
return getDataItem(index).getPeriod();
}
@@ -229,7 +235,7 @@ public TimePeriod getTimePeriod(int index) {
*
* @see #getDataItem(int)
*/
- public Number getValue(int index) {
+ public Number getValue(@NonNegative int index) {
return getDataItem(index).getValue();
}
@@ -242,7 +248,9 @@ public Number getValue(int index) {
public void add(TimePeriodValue item) {
Args.nullNotPermitted(item, "item");
this.data.add(item);
- updateBounds(item.getPeriod(), this.data.size() - 1);
+ @SuppressWarnings("index") // data.size is positive because we just added an item to data on the previous line
+ @NonNegative int lastIndex = this.data.size() - 1;
+ updateBounds(item.getPeriod(), lastIndex);
fireSeriesChanged();
}
@@ -252,7 +260,7 @@ public void add(TimePeriodValue item) {
* @param period the time period.
* @param index the index of the time period.
*/
- private void updateBounds(TimePeriod period, int index) {
+ private void updateBounds(TimePeriod period, @NonNegative int index) {
long start = period.getStart().getTime();
long end = period.getEnd().getTime();
@@ -279,11 +287,13 @@ private void updateBounds(TimePeriod period, int index) {
else {
this.maxStartIndex = index;
}
-
- if (this.minMiddleIndex >= 0) {
- long s = getDataItem(this.minMiddleIndex).getPeriod().getStart()
+
+ // don't use field directly to satisfy typechecker that field is not side-effected
+ int minMiddleIndex = this.minMiddleIndex;
+ if (minMiddleIndex >= 0) {
+ long s = getDataItem(minMiddleIndex).getPeriod().getStart()
.getTime();
- long e = getDataItem(this.minMiddleIndex).getPeriod().getEnd()
+ long e = getDataItem(minMiddleIndex).getPeriod().getEnd()
.getTime();
long minMiddle = s + (e - s) / 2;
if (middle < minMiddle) {
@@ -293,11 +303,13 @@ private void updateBounds(TimePeriod period, int index) {
else {
this.minMiddleIndex = index;
}
-
- if (this.maxMiddleIndex >= 0) {
- long s = getDataItem(this.maxMiddleIndex).getPeriod().getStart()
+
+ // don't use field directly to satisfy typechecker that field is not side-effected
+ int maxMiddleIndex = this.maxMiddleIndex;
+ if (maxMiddleIndex >= 0) {
+ long s = getDataItem(maxMiddleIndex).getPeriod().getStart()
.getTime();
- long e = getDataItem(this.maxMiddleIndex).getPeriod().getEnd()
+ long e = getDataItem(maxMiddleIndex).getPeriod().getEnd()
.getTime();
long maxMiddle = s + (e - s) / 2;
if (middle > maxMiddle) {
@@ -381,7 +393,7 @@ public void add(TimePeriod period, Number value) {
* @param index the index of the data item to update.
* @param value the new value ({@code null} not permitted).
*/
- public void update(int index, Number value) {
+ public void update(@NonNegative int index, Number value) {
TimePeriodValue item = getDataItem(index);
item.setValue(value);
fireSeriesChanged();
@@ -394,7 +406,7 @@ public void update(int index, Number value) {
* @param start the index of the first period to delete.
* @param end the index of the last period to delete.
*/
- public void delete(int start, int end) {
+ public void delete(@NonNegative @LessThan("#2 + 1") int start, @NonNegative int end) {
for (int i = 0; i <= (end - start); i++) {
this.data.remove(start);
}
@@ -493,7 +505,7 @@ public Object clone() throws CloneNotSupportedException {
*
* @throws CloneNotSupportedException if there is a cloning problem.
*/
- public TimePeriodValues createCopy(int start, int end)
+ public TimePeriodValues createCopy(@NonNegative int start, @GTENegativeOne int end)
throws CloneNotSupportedException {
TimePeriodValues copy = (TimePeriodValues) super.clone();
@@ -520,7 +532,7 @@ public TimePeriodValues createCopy(int start, int end)
*
* @return The index.
*/
- public int getMinStartIndex() {
+ public @GTENegativeOne int getMinStartIndex() {
return this.minStartIndex;
}
@@ -529,7 +541,7 @@ public int getMinStartIndex() {
*
* @return The index.
*/
- public int getMaxStartIndex() {
+ public @GTENegativeOne int getMaxStartIndex() {
return this.maxStartIndex;
}
@@ -539,7 +551,7 @@ public int getMaxStartIndex() {
*
* @return The index.
*/
- public int getMinMiddleIndex() {
+ public @GTENegativeOne int getMinMiddleIndex() {
return this.minMiddleIndex;
}
@@ -549,7 +561,7 @@ public int getMinMiddleIndex() {
*
* @return The index.
*/
- public int getMaxMiddleIndex() {
+ public @GTENegativeOne int getMaxMiddleIndex() {
return this.maxMiddleIndex;
}
@@ -558,7 +570,7 @@ public int getMaxMiddleIndex() {
*
* @return The index.
*/
- public int getMinEndIndex() {
+ public @GTENegativeOne int getMinEndIndex() {
return this.minEndIndex;
}
@@ -567,7 +579,7 @@ public int getMinEndIndex() {
*
* @return The index.
*/
- public int getMaxEndIndex() {
+ public @GTENegativeOne int getMaxEndIndex() {
return this.maxEndIndex;
}
diff --git a/src/main/java/org/jfree/data/time/TimePeriodValuesCollection.java b/src/main/java/org/jfree/data/time/TimePeriodValuesCollection.java
index aef830e63..8e0b5632a 100644
--- a/src/main/java/org/jfree/data/time/TimePeriodValuesCollection.java
+++ b/src/main/java/org/jfree/data/time/TimePeriodValuesCollection.java
@@ -50,6 +50,11 @@
package org.jfree.data.time;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
@@ -135,7 +140,7 @@ public void setXPosition(TimePeriodAnchor position) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.data.size();
}
@@ -146,7 +151,7 @@ public int getSeriesCount() {
*
* @return The series.
*/
- public TimePeriodValues getSeries(int series) {
+ public TimePeriodValues getSeries(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Index 'series' out of range.");
}
@@ -161,7 +166,7 @@ public TimePeriodValues getSeries(int series) {
* @return The key for a series.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
// defer argument checking
return getSeries(series).getKey();
}
@@ -198,7 +203,7 @@ public void removeSeries(TimePeriodValues series) {
*
* @param index the series index (zero-based).
*/
- public void removeSeries(int index) {
+ public void removeSeries(@NonNegative int index) {
TimePeriodValues series = getSeries(index);
if (series != null) {
removeSeries(series);
@@ -215,7 +220,8 @@ public void removeSeries(int index) {
* @return The number of items in the specified series.
*/
@Override
- public int getItemCount(int series) {
+ @SuppressWarnings("index") // array-list interop: getSeries(series).getItemCount is LengthOf(this.getSeries)
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
return getSeries(series).getItemCount();
}
@@ -228,7 +234,7 @@ public int getItemCount(int series) {
* @return The x-value for the specified series and item.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimePeriodValues ts = (TimePeriodValues) this.data.get(series);
TimePeriodValue dp = ts.getDataItem(item);
TimePeriod period = dp.getPeriod();
@@ -269,7 +275,7 @@ else if (this.xPosition == TimePeriodAnchor.END) {
* @return The starting X value for the specified series and item.
*/
@Override
- public Number getStartX(int series, int item) {
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimePeriodValues ts = (TimePeriodValues) this.data.get(series);
TimePeriodValue dp = ts.getDataItem(item);
return new Long(dp.getPeriod().getStart().getTime());
@@ -284,7 +290,7 @@ public Number getStartX(int series, int item) {
* @return The ending X value for the specified series and item.
*/
@Override
- public Number getEndX(int series, int item) {
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimePeriodValues ts = (TimePeriodValues) this.data.get(series);
TimePeriodValue dp = ts.getDataItem(item);
return new Long(dp.getPeriod().getEnd().getTime());
@@ -299,7 +305,7 @@ public Number getEndX(int series, int item) {
* @return The y-value for the specified series and item.
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimePeriodValues ts = (TimePeriodValues) this.data.get(series);
TimePeriodValue dp = ts.getDataItem(item);
return dp.getValue();
@@ -314,7 +320,7 @@ public Number getY(int series, int item) {
* @return The starting Y value for the specified series and item.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -327,7 +333,7 @@ public Number getStartY(int series, int item) {
* @return The ending Y value for the specified series and item.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -376,6 +382,7 @@ public double getDomainUpperBound(boolean includeInterval) {
* @return The range.
*/
@Override
+ @SuppressWarnings("index") // guaranteed index: every call to getXIndex in this method (there are a lot) is guarded by the if (count > 0) check, which ensures that those values can't be negative.
public Range getDomainBounds(boolean includeInterval) {
boolean interval = includeInterval;
Range result = null;
diff --git a/src/main/java/org/jfree/data/time/TimeSeries.java b/src/main/java/org/jfree/data/time/TimeSeries.java
index 3a2da9e13..216ac82f3 100644
--- a/src/main/java/org/jfree/data/time/TimeSeries.java
+++ b/src/main/java/org/jfree/data/time/TimeSeries.java
@@ -91,6 +91,10 @@
package org.jfree.data.time;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -141,7 +145,7 @@ public class TimeSeries extends Series implements Cloneable, Serializable {
protected List data;
/** The maximum number of items for the series. */
- private int maximumItemCount;
+ private @NonNegative int maximumItemCount;
/**
* The maximum age of items for the series, specified as a number of
@@ -256,7 +260,7 @@ public void setRangeDescription(String description) {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.data.size();
}
@@ -279,7 +283,7 @@ public List getItems() {
*
* @see #setMaximumItemCount(int)
*/
- public int getMaximumItemCount() {
+ public @NonNegative int getMaximumItemCount() {
return this.maximumItemCount;
}
@@ -294,14 +298,18 @@ public int getMaximumItemCount() {
*
* @see #getMaximumItemCount()
*/
- public void setMaximumItemCount(int maximum) {
+ public void setMaximumItemCount(@NonNegative int maximum) {
if (maximum < 0) {
throw new IllegalArgumentException("Negative 'maximum' argument.");
}
this.maximumItemCount = maximum;
int count = this.data.size();
if (count > maximum) {
- delete(0, count - maximum - 1);
+ @SuppressWarnings({"index","value"}) // https://github.com/kelloggm/checker-framework/issues/158
+ @IntRange(from=0) int deleteIndex = count - maximum - 1;
+ // Extra assignment to kill the dataflow refinement.
+ deleteIndex = deleteIndex;
+ delete(0, deleteIndex);
}
}
@@ -476,7 +484,7 @@ public Class getTimePeriodClass() {
*
* @return The data item.
*/
- public TimeSeriesDataItem getDataItem(int index) {
+ public TimeSeriesDataItem getDataItem(@NonNegative int index) {
TimeSeriesDataItem item = (TimeSeriesDataItem) this.data.get(index);
return (TimeSeriesDataItem) item.clone();
}
@@ -514,7 +522,7 @@ public TimeSeriesDataItem getDataItem(RegularTimePeriod period) {
*
* @since 1.0.14
*/
- TimeSeriesDataItem getRawDataItem(int index) {
+ TimeSeriesDataItem getRawDataItem(@NonNegative int index) {
return (TimeSeriesDataItem) this.data.get(index);
}
@@ -546,7 +554,7 @@ TimeSeriesDataItem getRawDataItem(RegularTimePeriod period) {
*
* @return The time period.
*/
- public RegularTimePeriod getTimePeriod(int index) {
+ public RegularTimePeriod getTimePeriod(@NonNegative int index) {
return getRawDataItem(index).getPeriod();
}
@@ -557,6 +565,7 @@ public RegularTimePeriod getTimePeriod(int index) {
* @return The next time period.
*/
public RegularTimePeriod getNextTimePeriod() {
+ @SuppressWarnings("index") // bug: requires there to be at least one time period, but documentation doesn't state it
RegularTimePeriod last = getTimePeriod(getItemCount() - 1);
return last.next();
}
@@ -616,7 +625,7 @@ public int getIndex(RegularTimePeriod period) {
*
* @return The value (possibly {@code null}).
*/
- public Number getValue(int index) {
+ public Number getValue(@NonNegative int index) {
return getRawDataItem(index).getValue();
}
@@ -679,7 +688,7 @@ else if (!this.timePeriodClass.equals(c)) {
added = true;
}
else {
- RegularTimePeriod last = getTimePeriod(getItemCount() - 1);
+ RegularTimePeriod last = getTimePeriod(count - 1);
if (item.getPeriod().compareTo(last) > 0) {
this.data.add(item);
added = true;
@@ -687,7 +696,9 @@ else if (!this.timePeriodClass.equals(c)) {
else {
int index = Collections.binarySearch(this.data, item);
if (index < 0) {
- this.data.add(-index - 1, item);
+ @SuppressWarnings("index") // binary search on list, which SearchIndex does not handle because lists are not fixed-size data structure
+ @NonNegative int index1 = -index - 1;
+ this.data.add(index1, item);
added = true;
}
else {
@@ -809,7 +820,7 @@ public void update(RegularTimePeriod period, Number value) {
* @param index the index of the data item.
* @param value the new value ({@code null} permitted).
*/
- public void update(int index, Number value) {
+ public void update(@NonNegative int index, Number value) {
TimeSeriesDataItem item = (TimeSeriesDataItem) this.data.get(index);
boolean iterate = false;
Number oldYN = item.getValue();
@@ -936,7 +947,9 @@ else if (item.getValue() != null) {
}
else {
item = (TimeSeriesDataItem) item.clone();
- this.data.add(-index - 1, item);
+ @SuppressWarnings("index") // binary search on list, which SearchIndex does not handle because lists are not fixed-size data structure
+ @NonNegative int index1 = -index - 1;
+ this.data.add(index1, item);
updateBoundsForAddedItem(item);
// check if this addition will exceed the maximum item count...
@@ -964,8 +977,9 @@ else if (item.getValue() != null) {
public void removeAgedItems(boolean notify) {
// check if there are any values earlier than specified by the history
// count...
- if (getItemCount() > 1) {
- long latest = getTimePeriod(getItemCount() - 1).getSerialIndex();
+ int count = getItemCount();
+ if (count > 1) {
+ long latest = getTimePeriod(count - 1).getSerialIndex();
boolean removed = false;
while ((latest - getTimePeriod(0).getSerialIndex())
> this.maximumItemAge) {
@@ -1073,7 +1087,7 @@ public void delete(RegularTimePeriod period) {
* @param start the index of the first period to delete.
* @param end the index of the last period to delete.
*/
- public void delete(int start, int end) {
+ public void delete(@NonNegative @LessThan("#2 + 1") int start, @NonNegative int end) {
delete(start, end, true);
}
@@ -1086,7 +1100,7 @@ public void delete(int start, int end) {
*
* @since 1.0.14
*/
- public void delete(int start, int end, boolean notify) {
+ public void delete(@NonNegative @LessThan("#2 + 1") int start, @NonNegative int end, boolean notify) {
if (end < start) {
throw new IllegalArgumentException("Requires start <= end.");
}
@@ -1136,7 +1150,7 @@ public Object clone() throws CloneNotSupportedException {
*
* @throws CloneNotSupportedException if there is a cloning problem.
*/
- public TimeSeries createCopy(int start, int end)
+ public TimeSeries createCopy(@NonNegative int start, @NonNegative int end)
throws CloneNotSupportedException {
if (start < 0) {
throw new IllegalArgumentException("Requires start >= 0.");
@@ -1207,6 +1221,10 @@ public TimeSeries createCopy(RegularTimePeriod start, RegularTimePeriod end)
copy.data = new java.util.ArrayList();
return copy;
}
+ @SuppressWarnings("index") // if endIndex < 0, emptyRange is true, so the function returns before we get here.
+ @NonNegative int endIndex1 = endIndex;
+ endIndex = endIndex1;
+
return createCopy(startIndex, endIndex);
}
diff --git a/src/main/java/org/jfree/data/time/TimeSeriesCollection.java b/src/main/java/org/jfree/data/time/TimeSeriesCollection.java
index 05e502888..dca8b64df 100644
--- a/src/main/java/org/jfree/data/time/TimeSeriesCollection.java
+++ b/src/main/java/org/jfree/data/time/TimeSeriesCollection.java
@@ -1,3 +1,4 @@
+
/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
@@ -88,6 +89,11 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
@@ -238,7 +244,7 @@ public List getSeries() {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.data.size();
}
@@ -252,7 +258,7 @@ public int getSeriesCount() {
*
* @since 1.0.6
*/
- public int indexOf(TimeSeries series) {
+ public @GTENegativeOne int indexOf(TimeSeries series) {
Args.nullNotPermitted(series, "series");
return this.data.indexOf(series);
}
@@ -264,7 +270,7 @@ public int indexOf(TimeSeries series) {
*
* @return The series.
*/
- public TimeSeries getSeries(int series) {
+ public TimeSeries getSeries(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException(
"The 'series' argument is out of bounds (" + series + ").");
@@ -301,7 +307,7 @@ public TimeSeries getSeries(Comparable key) {
* @return The key for a series.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
// check arguments...delegated
// fetch the series name...
return getSeries(series).getKey();
@@ -317,7 +323,7 @@ public Comparable getSeriesKey(int series) {
*
* @since 1.0.17
*/
- public int getSeriesIndex(Comparable key) {
+ public @GTENegativeOne int getSeriesIndex(Comparable key) {
Args.nullNotPermitted(key, "key");
int seriesCount = getSeriesCount();
for (int i = 0; i < seriesCount; i++) {
@@ -362,7 +368,7 @@ public void removeSeries(TimeSeries series) {
*
* @param index the series index (zero-based).
*/
- public void removeSeries(int index) {
+ public void removeSeries(@NonNegative int index) {
TimeSeries series = getSeries(index);
if (series != null) {
removeSeries(series);
@@ -398,7 +404,8 @@ public void removeAllSeries() {
* @return The item count.
*/
@Override
- public int getItemCount(int series) {
+ @SuppressWarnings("index") // array-list interop: getSeries(series).getItemCount is LengthOf(this.getSeries)
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
return getSeries(series).getItemCount();
}
@@ -411,7 +418,7 @@ public int getItemCount(int series) {
* @return The x-value.
*/
@Override
- public double getXValue(int series, int item) {
+ public double getXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimeSeries s = (TimeSeries) this.data.get(series);
RegularTimePeriod period = s.getTimePeriod(item);
return getX(period);
@@ -426,7 +433,7 @@ public double getXValue(int series, int item) {
* @return The value.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimeSeries ts = (TimeSeries) this.data.get(series);
RegularTimePeriod period = ts.getTimePeriod(item);
return new Long(getX(period));
@@ -462,7 +469,7 @@ else if (this.xPosition == TimePeriodAnchor.END) {
* @return The value.
*/
@Override
- public synchronized Number getStartX(int series, int item) {
+ public synchronized Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimeSeries ts = (TimeSeries) this.data.get(series);
return new Long(ts.getTimePeriod(item).getFirstMillisecond(
this.workingCalendar));
@@ -477,7 +484,7 @@ public synchronized Number getStartX(int series, int item) {
* @return The value.
*/
@Override
- public synchronized Number getEndX(int series, int item) {
+ public synchronized Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimeSeries ts = (TimeSeries) this.data.get(series);
return new Long(ts.getTimePeriod(item).getLastMillisecond(
this.workingCalendar));
@@ -492,7 +499,7 @@ public synchronized Number getEndX(int series, int item) {
* @return The value (possibly {@code null}).
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimeSeries ts = (TimeSeries) this.data.get(series);
return ts.getValue(item);
}
@@ -506,7 +513,7 @@ public Number getY(int series, int item) {
* @return The value (possibly {@code null}).
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -519,7 +526,7 @@ public Number getStartY(int series, int item) {
* @return The value (possibly {@code null}).
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -534,10 +541,9 @@ public Number getEndY(int series, int item) {
* @return An array containing the (two) indices of the items surrounding
* the time.
*/
- public int[] getSurroundingItems(int series, long milliseconds) {
+ public int @ArrayLen(2) [] getSurroundingItems(@NonNegative int series, long milliseconds) {
int[] result = new int[] {-1, -1};
- TimeSeries timeSeries = getSeries(series);
- for (int i = 0; i < timeSeries.getItemCount(); i++) {
+ for (int i = 0; i < this.getItemCount(series); i++) {
Number x = getX(series, i);
long m = x.longValue();
if (m <= milliseconds) {
diff --git a/src/main/java/org/jfree/data/time/TimeSeriesTableModel.java b/src/main/java/org/jfree/data/time/TimeSeriesTableModel.java
index b1e1ec33b..dd302a4b9 100644
--- a/src/main/java/org/jfree/data/time/TimeSeriesTableModel.java
+++ b/src/main/java/org/jfree/data/time/TimeSeriesTableModel.java
@@ -43,6 +43,8 @@
package org.jfree.data.time;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import javax.swing.table.AbstractTableModel;
import org.jfree.data.general.SeriesChangeEvent;
@@ -102,7 +104,7 @@ public TimeSeriesTableModel(TimeSeries series, boolean editable) {
* @return The column count.
*/
@Override
- public int getColumnCount() {
+ public @NonNegative int getColumnCount() {
return 2;
}
@@ -114,7 +116,7 @@ public int getColumnCount() {
* @return The column class in the table model.
*/
@Override
- public Class getColumnClass(int column) {
+ public Class getColumnClass(@NonNegative int column) {
if (column == 0) {
return String.class;
}
@@ -136,7 +138,7 @@ public Class getColumnClass(int column) {
* @return The name of a column.
*/
@Override
- public String getColumnName(int column) {
+ public String getColumnName(@NonNegative int column) {
if (column == 0) {
return "Period:";
@@ -158,7 +160,7 @@ public String getColumnName(int column) {
* @return The row count.
*/
@Override
- public int getRowCount() {
+ public @NonNegative int getRowCount() {
return this.series.getItemCount();
}
@@ -171,7 +173,7 @@ public int getRowCount() {
* @return The data value for a cell in the table model.
*/
@Override
- public Object getValueAt(int row, int column) {
+ public Object getValueAt(@NonNegative int row, @NonNegative int column) {
if (row < this.series.getItemCount()) {
if (column == 0) {
@@ -211,7 +213,7 @@ public Object getValueAt(int row, int column) {
* @return {@code true} if the specified cell is editable.
*/
@Override
- public boolean isCellEditable(int row, int column) {
+ public boolean isCellEditable(@NonNegative int row, @NonNegative int column) {
if (this.editable) {
if ((column == 0) || (column == 1)) {
return true;
@@ -233,7 +235,7 @@ public boolean isCellEditable(int row, int column) {
* @param column the column.
*/
@Override
- public void setValueAt(Object value, int row, int column) {
+ public void setValueAt(Object value, @NonNegative int row, @NonNegative int column) {
if (row < this.series.getItemCount()) {
diff --git a/src/main/java/org/jfree/data/time/TimeTableXYDataset.java b/src/main/java/org/jfree/data/time/TimeTableXYDataset.java
index 0cb32d047..4acf4d87a 100644
--- a/src/main/java/org/jfree/data/time/TimeTableXYDataset.java
+++ b/src/main/java/org/jfree/data/time/TimeTableXYDataset.java
@@ -57,6 +57,11 @@
package org.jfree.data.time;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
@@ -298,7 +303,7 @@ public void clear() {
*
* @return The time period.
*/
- public TimePeriod getTimePeriod(int item) {
+ public TimePeriod getTimePeriod(@NonNegative int item) {
return (TimePeriod) this.values.getRowKey(item);
}
@@ -308,7 +313,7 @@ public TimePeriod getTimePeriod(int item) {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.values.getRowCount();
}
@@ -322,7 +327,8 @@ public int getItemCount() {
* @return The number of items within the series.
*/
@Override
- public int getItemCount(int series) {
+ @SuppressWarnings("index") // array-list interop: series is ignored and the underlying rep here is a list
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
return getItemCount();
}
@@ -332,7 +338,7 @@ public int getItemCount(int series) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.values.getColumnCount();
}
@@ -344,7 +350,7 @@ public int getSeriesCount() {
* @return The key for the series.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
return this.values.getColumnKey(series);
}
@@ -359,7 +365,7 @@ public Comparable getSeriesKey(int series) {
* @return The x-value.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getXValue(series, item));
}
@@ -372,7 +378,7 @@ public Number getX(int series, int item) {
* @return The value.
*/
@Override
- public double getXValue(int series, int item) {
+ public double getXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimePeriod period = (TimePeriod) this.values.getRowKey(item);
return getXValue(period);
}
@@ -388,7 +394,7 @@ public double getXValue(int series, int item) {
* @see #getStartXValue(int, int)
*/
@Override
- public Number getStartX(int series, int item) {
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getStartXValue(series, item));
}
@@ -402,7 +408,7 @@ public Number getStartX(int series, int item) {
* @return The value.
*/
@Override
- public double getStartXValue(int series, int item) {
+ public double getStartXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimePeriod period = (TimePeriod) this.values.getRowKey(item);
return period.getStart().getTime();
}
@@ -418,7 +424,7 @@ public double getStartXValue(int series, int item) {
* @see #getEndXValue(int, int)
*/
@Override
- public Number getEndX(int series, int item) {
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getEndXValue(series, item));
}
@@ -432,7 +438,7 @@ public Number getEndX(int series, int item) {
* @return The value.
*/
@Override
- public double getEndXValue(int series, int item) {
+ public double getEndXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
TimePeriod period = (TimePeriod) this.values.getRowKey(item);
return period.getEnd().getTime();
}
@@ -446,7 +452,7 @@ public double getEndXValue(int series, int item) {
* @return The y-value (possibly {@code null}).
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return this.values.getValue(item, series);
}
@@ -459,7 +465,7 @@ public Number getY(int series, int item) {
* @return The starting Y value for the specified series and item.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -472,7 +478,7 @@ public Number getStartY(int series, int item) {
* @return The ending Y value for the specified series and item.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -551,7 +557,9 @@ public Range getDomainBounds(boolean includeInterval) {
}
TimePeriod first = (TimePeriod) keys.get(0);
- TimePeriod last = (TimePeriod) keys.get(keys.size() - 1);
+ @SuppressWarnings("index") // keys.isEmpty() call above establishes that this is safe
+ @NonNegative int lastIndex = keys.size() - 1;
+ TimePeriod last = (TimePeriod) keys.get(lastIndex);
if (!includeInterval || this.domainIsPointsInTime) {
return new Range(getXValue(first), getXValue(last));
diff --git a/src/main/java/org/jfree/data/time/Week.java b/src/main/java/org/jfree/data/time/Week.java
index 7504115f8..82536cd1a 100644
--- a/src/main/java/org/jfree/data/time/Week.java
+++ b/src/main/java/org/jfree/data/time/Week.java
@@ -74,6 +74,8 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
@@ -103,10 +105,10 @@ public class Week extends RegularTimePeriod implements Serializable {
public static final int LAST_WEEK_IN_YEAR = 53;
/** The year in which the week falls. */
- private short year;
+ private @IntRange(from = 0, to = 9999) short year;
/** The week (1-53). */
- private byte week;
+ private @IntRange(from = 1, to = 53) byte week;
/** The first millisecond. */
private long firstMillisecond;
@@ -128,7 +130,7 @@ public Week() {
* @param week the week (1 to 53).
* @param year the year (1900 to 9999).
*/
- public Week(int week, int year) {
+ public Week(@IntRange(from = 1, to = 53) int week, @IntRange(from = 0, to = 9999) int year) {
if ((week < FIRST_WEEK_IN_YEAR) && (week > LAST_WEEK_IN_YEAR)) {
throw new IllegalArgumentException(
"The 'week' argument must be in the range 1 - 53.");
@@ -144,7 +146,7 @@ public Week(int week, int year) {
* @param week the week (1 to 53).
* @param year the year (1900 to 9999).
*/
- public Week(int week, Year year) {
+ public Week(@IntRange(from = 1, to = 53) int week, Year year) {
if ((week < FIRST_WEEK_IN_YEAR) && (week > LAST_WEEK_IN_YEAR)) {
throw new IllegalArgumentException(
"The 'week' argument must be in the range 1 - 53.");
@@ -179,6 +181,7 @@ public Week(Date time) {
*
* @since 1.0.7
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Week(Date time, TimeZone zone, Locale locale) {
Args.nullNotPermitted(time, "time");
Args.nullNotPermitted(zone, "zone");
@@ -223,7 +226,7 @@ public Year getYear() {
*
* @return The year.
*/
- public int getYearValue() {
+ public @IntRange(from = -9999, to = 9999) int getYearValue() {
return this.year;
}
@@ -232,7 +235,7 @@ public int getYearValue() {
*
* @return The week.
*/
- public int getWeek() {
+ public @IntRange(from = 1, to = 53) int getWeek() {
return this.week;
}
@@ -301,8 +304,10 @@ public RegularTimePeriod previous() {
int yy = this.year - 1;
Calendar prevYearCalendar = Calendar.getInstance();
prevYearCalendar.set(yy, Calendar.DECEMBER, 31);
- result = new Week(prevYearCalendar.getActualMaximum(
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.getActualMaximum is a combined getter for various calendar fields, and therefore has no sensical annotation
+ Week resultTmp = new Week(prevYearCalendar.getActualMaximum(
Calendar.WEEK_OF_YEAR), yy);
+ result = resultTmp;
}
else {
result = null;
@@ -331,7 +336,8 @@ public RegularTimePeriod next() {
else {
Calendar calendar = Calendar.getInstance();
calendar.set(this.year, Calendar.DECEMBER, 31);
- int actualMaxWeek
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.getActualMaximum is a combined getter for various calendar fields, and therefore has no sensical annotation
+ @IntRange(from = 52, to = 53) int actualMaxWeek
= calendar.getActualMaximum(Calendar.WEEK_OF_YEAR);
if (this.week < actualMaxWeek) {
result = new Week(this.week + 1, this.year);
@@ -522,6 +528,7 @@ else if (o1 instanceof RegularTimePeriod) {
* @return {@code null} if the string is not parseable, the week
* otherwise.
*/
+ @SuppressWarnings({"index", "value"}) // parsing code relies on wellformedness of the String passed in
public static Week parseWeek(String s) {
Week result = null;
diff --git a/src/main/java/org/jfree/data/time/Year.java b/src/main/java/org/jfree/data/time/Year.java
index 67a941512..30ad3d573 100644
--- a/src/main/java/org/jfree/data/time/Year.java
+++ b/src/main/java/org/jfree/data/time/Year.java
@@ -62,6 +62,8 @@
package org.jfree.data.time;
+import org.checkerframework.common.value.qual.*;
+
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
@@ -92,7 +94,7 @@ public class Year extends RegularTimePeriod implements Serializable {
private static final long serialVersionUID = -7659990929736074836L;
/** The year. */
- private short year;
+ private @IntRange(from = -9999, to = 9999) short year;
/** The first millisecond. */
private long firstMillisecond;
@@ -112,7 +114,7 @@ public Year() {
*
* @param year the year.
*/
- public Year(int year) {
+ public Year(@IntRange(from = -9999, to = 9999) int year) {
if ((year < Year.MINIMUM_YEAR) || (year > Year.MAXIMUM_YEAR)) {
throw new IllegalArgumentException(
"Year constructor: year (" + year + ") outside valid range.");
@@ -143,6 +145,7 @@ public Year(Date time) {
*
* @since 1.0.12
*/
+ @SuppressWarnings({"index", "value"}) // calendar get: calendar.get is a combined getter for various calendar fields, and therefore has no sensical annotation
public Year(Date time, TimeZone zone, Locale locale) {
Calendar calendar = Calendar.getInstance(zone, locale);
calendar.setTime(time);
@@ -155,7 +158,8 @@ public Year(Date time, TimeZone zone, Locale locale) {
*
* @return The year.
*/
- public int getYear() {
+ @SuppressWarnings({"index", "value"}) // this is a bug. The calendar API which this interacts with expects years to be nonnegative (it uses an era field to represent AD/BC)
+ public @IntRange(from = 0, to = 9999) int getYear() {
return this.year;
}
@@ -259,6 +263,7 @@ public long getSerialIndex() {
* {@code null}.
*/
@Override
+ @SuppressWarnings({"index", "value"}) // this is a bug in this class. Years cannot be negative from a Calendar's perspective
public long getFirstMillisecond(Calendar calendar) {
calendar.set(this.year, Calendar.JANUARY, 1, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
@@ -277,6 +282,7 @@ public long getFirstMillisecond(Calendar calendar) {
* {@code null}.
*/
@Override
+ @SuppressWarnings({"index", "value"}) // this is a bug in this class. Years cannot be negative from a Calendar's perspective
public long getLastMillisecond(Calendar calendar) {
calendar.set(this.year, Calendar.DECEMBER, 31, 23, 59, 59);
calendar.set(Calendar.MILLISECOND, 999);
@@ -383,6 +389,7 @@ public String toString() {
* @return {@code null} if the string is not parseable, the year
* otherwise.
*/
+ @SuppressWarnings({"index", "value"}) // parsing method is intended to throw an exception if the year isn't valid
public static Year parseYear(String s) {
// parse the string...
diff --git a/src/main/java/org/jfree/data/time/ohlc/OHLCSeries.java b/src/main/java/org/jfree/data/time/ohlc/OHLCSeries.java
index 81c25be40..a8acd1906 100644
--- a/src/main/java/org/jfree/data/time/ohlc/OHLCSeries.java
+++ b/src/main/java/org/jfree/data/time/ohlc/OHLCSeries.java
@@ -42,6 +42,8 @@
package org.jfree.data.time.ohlc;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.chart.util.Args;
import org.jfree.data.ComparableObjectItem;
import org.jfree.data.ComparableObjectSeries;
@@ -74,7 +76,7 @@ public OHLCSeries(Comparable key) {
*
* @return The time period.
*/
- public RegularTimePeriod getPeriod(int index) {
+ public RegularTimePeriod getPeriod(@NonNegative int index) {
OHLCItem item = (OHLCItem) getDataItem(index);
return item.getPeriod();
}
@@ -87,7 +89,7 @@ public RegularTimePeriod getPeriod(int index) {
* @return The data item.
*/
@Override
- public ComparableObjectItem getDataItem(int index) {
+ public ComparableObjectItem getDataItem(@NonNegative int index) {
return super.getDataItem(index);
}
@@ -136,7 +138,7 @@ public void add(OHLCItem item) {
* @since 1.0.14
*/
@Override
- public ComparableObjectItem remove(int index) {
+ public ComparableObjectItem remove(@NonNegative int index) {
return super.remove(index);
}
diff --git a/src/main/java/org/jfree/data/time/ohlc/OHLCSeriesCollection.java b/src/main/java/org/jfree/data/time/ohlc/OHLCSeriesCollection.java
index f14315fcb..c28eab112 100644
--- a/src/main/java/org/jfree/data/time/ohlc/OHLCSeriesCollection.java
+++ b/src/main/java/org/jfree/data/time/ohlc/OHLCSeriesCollection.java
@@ -44,6 +44,10 @@
package org.jfree.data.time.ohlc;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.List;
@@ -125,7 +129,7 @@ public void addSeries(OHLCSeries series) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.data.size();
}
@@ -139,7 +143,7 @@ public int getSeriesCount() {
* @throws IllegalArgumentException if {@code series} is not in the
* range {@code 0} to {@code getSeriesCount() - 1}.
*/
- public OHLCSeries getSeries(int series) {
+ public OHLCSeries getSeries(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds");
}
@@ -158,7 +162,7 @@ public OHLCSeries getSeries(int series) {
* specified range.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
// defer argument checking
return getSeries(series).getKey();
}
@@ -174,7 +178,8 @@ public Comparable getSeriesKey(int series) {
* range {@code 0} to {@code getSeriesCount() - 1}.
*/
@Override
- public int getItemCount(int series) {
+ @SuppressWarnings("index") // array-list interop: the underlying data structure here is a list, but this method's annotation expects an array
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
// defer argument checking
return getSeries(series).getItemCount();
}
@@ -209,7 +214,7 @@ else if (this.xPosition == TimePeriodAnchor.END) {
* @return The x-value.
*/
@Override
- public double getXValue(int series, int item) {
+ public double getXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
OHLCSeries s = (OHLCSeries) this.data.get(series);
OHLCItem di = (OHLCItem) s.getDataItem(item);
RegularTimePeriod period = di.getPeriod();
@@ -225,7 +230,7 @@ public double getXValue(int series, int item) {
* @return The x-value.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getXValue(series, item));
}
@@ -238,7 +243,7 @@ public Number getX(int series, int item) {
* @return The y-value.
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
OHLCSeries s = (OHLCSeries) this.data.get(series);
OHLCItem di = (OHLCItem) s.getDataItem(item);
return new Double(di.getYValue());
@@ -253,7 +258,7 @@ public Number getY(int series, int item) {
* @return The open-value.
*/
@Override
- public double getOpenValue(int series, int item) {
+ public double getOpenValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
OHLCSeries s = (OHLCSeries) this.data.get(series);
OHLCItem di = (OHLCItem) s.getDataItem(item);
return di.getOpenValue();
@@ -268,7 +273,7 @@ public double getOpenValue(int series, int item) {
* @return The open-value.
*/
@Override
- public Number getOpen(int series, int item) {
+ public Number getOpen(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getOpenValue(series, item));
}
@@ -281,7 +286,7 @@ public Number getOpen(int series, int item) {
* @return The close-value.
*/
@Override
- public double getCloseValue(int series, int item) {
+ public double getCloseValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
OHLCSeries s = (OHLCSeries) this.data.get(series);
OHLCItem di = (OHLCItem) s.getDataItem(item);
return di.getCloseValue();
@@ -296,7 +301,7 @@ public double getCloseValue(int series, int item) {
* @return The close-value.
*/
@Override
- public Number getClose(int series, int item) {
+ public Number getClose(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getCloseValue(series, item));
}
@@ -309,7 +314,7 @@ public Number getClose(int series, int item) {
* @return The high-value.
*/
@Override
- public double getHighValue(int series, int item) {
+ public double getHighValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
OHLCSeries s = (OHLCSeries) this.data.get(series);
OHLCItem di = (OHLCItem) s.getDataItem(item);
return di.getHighValue();
@@ -324,7 +329,7 @@ public double getHighValue(int series, int item) {
* @return The high-value.
*/
@Override
- public Number getHigh(int series, int item) {
+ public Number getHigh(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getHighValue(series, item));
}
@@ -337,7 +342,7 @@ public Number getHigh(int series, int item) {
* @return The low-value.
*/
@Override
- public double getLowValue(int series, int item) {
+ public double getLowValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
OHLCSeries s = (OHLCSeries) this.data.get(series);
OHLCItem di = (OHLCItem) s.getDataItem(item);
return di.getLowValue();
@@ -352,7 +357,7 @@ public double getLowValue(int series, int item) {
* @return The low-value.
*/
@Override
- public Number getLow(int series, int item) {
+ public Number getLow(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return new Double(getLowValue(series, item));
}
@@ -366,7 +371,7 @@ public Number getLow(int series, int item) {
* @return {@code null}.
*/
@Override
- public Number getVolume(int series, int item) {
+ public Number getVolume(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return null;
}
@@ -380,7 +385,7 @@ public Number getVolume(int series, int item) {
* @return {@code Double.NaN}.
*/
@Override
- public double getVolumeValue(int series, int item) {
+ public double getVolumeValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return Double.NaN;
}
@@ -392,7 +397,7 @@ public double getVolumeValue(int series, int item) {
*
* @since 1.0.14
*/
- public void removeSeries(int index) {
+ public void removeSeries(@NonNegative int index) {
OHLCSeries series = getSeries(index);
if (series != null) {
removeSeries(series);
diff --git a/src/main/java/org/jfree/data/xml/KeyHandler.java b/src/main/java/org/jfree/data/xml/KeyHandler.java
index 4c480b998..ca79d04c3 100644
--- a/src/main/java/org/jfree/data/xml/KeyHandler.java
+++ b/src/main/java/org/jfree/data/xml/KeyHandler.java
@@ -40,6 +40,9 @@
package org.jfree.data.xml;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
@@ -134,7 +137,8 @@ public void endElement(String namespaceURI,
* @param length the length of the valid character data.
*/
@Override
- public void characters(char[] ch, int start, int length) {
+ @SuppressWarnings("index") // need xml annotations
+ public void characters(char[] ch, @IndexOrHigh("#1") int start, @IndexOrHigh("#1") int length) {
if (this.currentText != null) {
this.currentText.append(String.copyValueOf(ch, start, length));
}
diff --git a/src/main/java/org/jfree/data/xml/RootHandler.java b/src/main/java/org/jfree/data/xml/RootHandler.java
index de6fe59cb..1350a42e5 100644
--- a/src/main/java/org/jfree/data/xml/RootHandler.java
+++ b/src/main/java/org/jfree/data/xml/RootHandler.java
@@ -40,6 +40,9 @@
package org.jfree.data.xml;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
import java.util.Stack;
import org.xml.sax.SAXException;
@@ -79,7 +82,8 @@ public Stack getSubHandlers() {
* @throws SAXException for errors.
*/
@Override
- public void characters(char[] ch, int start, int length)
+ @SuppressWarnings("index") // need xml annotations
+ public void characters(char[] ch, @IndexOrHigh("#1") int start, @IndexOrHigh("#1") int length)
throws SAXException {
DefaultHandler handler = getCurrentHandler();
if (handler != this) {
diff --git a/src/main/java/org/jfree/data/xml/ValueHandler.java b/src/main/java/org/jfree/data/xml/ValueHandler.java
index f387e1c8f..b228b6ad0 100644
--- a/src/main/java/org/jfree/data/xml/ValueHandler.java
+++ b/src/main/java/org/jfree/data/xml/ValueHandler.java
@@ -41,6 +41,9 @@
package org.jfree.data.xml;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
@@ -139,7 +142,8 @@ public void endElement(String namespaceURI,
* @param length the length of the valid character data.
*/
@Override
- public void characters(char[] ch, int start, int length) {
+ @SuppressWarnings("index") // need xml annotations
+ public void characters(char[] ch, @IndexOrHigh("#1") int start, @IndexOrHigh("#1") int length) {
if (this.currentText != null) {
this.currentText.append(String.copyValueOf(ch, start, length));
}
diff --git a/src/main/java/org/jfree/data/xy/AbstractIntervalXYDataset.java b/src/main/java/org/jfree/data/xy/AbstractIntervalXYDataset.java
index c8e97a9cb..18667261e 100644
--- a/src/main/java/org/jfree/data/xy/AbstractIntervalXYDataset.java
+++ b/src/main/java/org/jfree/data/xy/AbstractIntervalXYDataset.java
@@ -43,6 +43,9 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
/**
* An base class that you can use to create new implementations of the
@@ -61,7 +64,7 @@ public abstract class AbstractIntervalXYDataset extends AbstractXYDataset
* @return The value.
*/
@Override
- public double getStartXValue(int series, int item) {
+ public double getStartXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number x = getStartX(series, item);
if (x != null) {
@@ -80,7 +83,7 @@ public double getStartXValue(int series, int item) {
* @return The value.
*/
@Override
- public double getEndXValue(int series, int item) {
+ public double getEndXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number x = getEndX(series, item);
if (x != null) {
@@ -99,7 +102,7 @@ public double getEndXValue(int series, int item) {
* @return The value.
*/
@Override
- public double getStartYValue(int series, int item) {
+ public double getStartYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number y = getStartY(series, item);
if (y != null) {
@@ -118,7 +121,7 @@ public double getStartYValue(int series, int item) {
* @return The value.
*/
@Override
- public double getEndYValue(int series, int item) {
+ public double getEndYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number y = getEndY(series, item);
if (y != null) {
@@ -126,5 +129,4 @@ public double getEndYValue(int series, int item) {
}
return result;
}
-
}
diff --git a/src/main/java/org/jfree/data/xy/AbstractXYDataset.java b/src/main/java/org/jfree/data/xy/AbstractXYDataset.java
index 45bca666c..4c4325743 100644
--- a/src/main/java/org/jfree/data/xy/AbstractXYDataset.java
+++ b/src/main/java/org/jfree/data/xy/AbstractXYDataset.java
@@ -43,6 +43,10 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.data.DomainOrder;
import org.jfree.data.general.AbstractSeriesDataset;
@@ -72,7 +76,7 @@ public DomainOrder getDomainOrder() {
* @return The value.
*/
@Override
- public double getXValue(int series, int item) {
+ public double getXValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number x = getX(series, item);
if (x != null) {
@@ -90,7 +94,7 @@ public double getXValue(int series, int item) {
* @return The value.
*/
@Override
- public double getYValue(int series, int item) {
+ public double getYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number y = getY(series, item);
if (y != null) {
@@ -98,5 +102,4 @@ public double getYValue(int series, int item) {
}
return result;
}
-
}
diff --git a/src/main/java/org/jfree/data/xy/AbstractXYZDataset.java b/src/main/java/org/jfree/data/xy/AbstractXYZDataset.java
index 859a60e58..a72ab04d4 100644
--- a/src/main/java/org/jfree/data/xy/AbstractXYZDataset.java
+++ b/src/main/java/org/jfree/data/xy/AbstractXYZDataset.java
@@ -41,6 +41,10 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
/**
* An base class that you can use to create new implementations of the
* {@link XYZDataset} interface.
@@ -57,7 +61,7 @@ public abstract class AbstractXYZDataset extends AbstractXYDataset
* @return The z-value.
*/
@Override
- public double getZValue(int series, int item) {
+ public double getZValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number z = getZ(series, item);
if (z != null) {
diff --git a/src/main/java/org/jfree/data/xy/CategoryTableXYDataset.java b/src/main/java/org/jfree/data/xy/CategoryTableXYDataset.java
index 0c2431513..69dc5d955 100644
--- a/src/main/java/org/jfree/data/xy/CategoryTableXYDataset.java
+++ b/src/main/java/org/jfree/data/xy/CategoryTableXYDataset.java
@@ -49,6 +49,10 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.chart.util.PublicCloneable;
import org.jfree.data.DefaultKeyedValues2D;
import org.jfree.data.DomainInfo;
@@ -159,7 +163,7 @@ public void clear() {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.values.getColumnCount();
}
@@ -171,7 +175,7 @@ public int getSeriesCount() {
* @return The key for a series.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
return this.values.getColumnKey(series);
}
@@ -181,7 +185,7 @@ public Comparable getSeriesKey(int series) {
* @return The item count.
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.values.getRowCount();
}
@@ -194,9 +198,11 @@ public int getItemCount() {
* @return The item count.
*/
@Override
- public int getItemCount(int series) {
- return getItemCount(); // all series have the same number of items in
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
+ @SuppressWarnings("index") // The annotation on this method's return type isn't quite sensical, because there's no way to express the correct invariant here. Warnings are suppressed throughout these classes, but callers have a good interface.
+ @LengthOf("this.getSeries(#1)") int result = getItemCount(); // all series have the same number of items in
// this dataset
+ return result;
}
/**
@@ -208,7 +214,7 @@ public int getItemCount(int series) {
* @return The value.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return (Number) this.values.getRowKey(item);
}
@@ -221,7 +227,8 @@ public Number getX(int series, int item) {
* @return The starting X value.
*/
@Override
- public Number getStartX(int series, int item) {
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212: interval delegate and this.getSeries have the same conceptual length
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return this.intervalDelegate.getStartX(series, item);
}
@@ -234,7 +241,8 @@ public Number getStartX(int series, int item) {
* @return The ending X value.
*/
@Override
- public Number getEndX(int series, int item) {
+ @SuppressWarnings("index") // retain information when casting https://github.com/kelloggm/checker-framework/issues/212: interval delegate and this.getSeries have the same conceptual length
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return this.intervalDelegate.getEndX(series, item);
}
@@ -247,7 +255,7 @@ public Number getEndX(int series, int item) {
* @return The y value (possibly {@code null}).
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return this.values.getValue(item, series);
}
@@ -260,7 +268,7 @@ public Number getY(int series, int item) {
* @return The starting Y value.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -273,7 +281,7 @@ public Number getStartY(int series, int item) {
* @return The ending Y value.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
diff --git a/src/main/java/org/jfree/data/xy/DefaultHighLowDataset.java b/src/main/java/org/jfree/data/xy/DefaultHighLowDataset.java
index 1b3ed72c8..16d4d14fd 100644
--- a/src/main/java/org/jfree/data/xy/DefaultHighLowDataset.java
+++ b/src/main/java/org/jfree/data/xy/DefaultHighLowDataset.java
@@ -49,6 +49,8 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
import java.util.Arrays;
import java.util.Date;
import org.jfree.chart.util.Args;
@@ -66,22 +68,22 @@ public class DefaultHighLowDataset extends AbstractXYDataset
private Comparable seriesKey;
/** Storage for the dates. */
- private Date[] date;
+ private Date @SameLen({"this.high", "this.date", "this.low", "this.open", "this.close", "this.volume"}) [] date;
/** Storage for the high values. */
- private Number[] high;
+ private Number @SameLen({"this.high", "this.date", "this.low", "this.open", "this.close", "this.volume"}) [] high;
/** Storage for the low values. */
- private Number[] low;
+ private Number @SameLen({"this.high", "this.date", "this.low", "this.open", "this.close", "this.volume"}) [] low;
/** Storage for the open values. */
- private Number[] open;
+ private Number @SameLen({"this.high", "this.date", "this.low", "this.open", "this.close", "this.volume"}) [] open;
/** Storage for the close values. */
- private Number[] close;
+ private Number @SameLen({"this.high", "this.date", "this.low", "this.open", "this.close", "this.volume"}) [] close;
/** Storage for the volume values. */
- private Number[] volume;
+ private Number @SameLen({"this.high", "this.date", "this.low", "this.open", "this.close", "this.volume"}) [] volume;
/**
* Constructs a new high/low/open/close dataset.
@@ -98,9 +100,11 @@ public class DefaultHighLowDataset extends AbstractXYDataset
* @param close the close values ({@code null} not permitted).
* @param volume the volume values ({@code null} not permitted).
*/
- public DefaultHighLowDataset(Comparable seriesKey, Date[] date,
- double[] high, double[] low, double[] open, double[] close,
- double[] volume) {
+ @SuppressWarnings("samelen") // While initializing object, SameLen invariants between the fields will be broken (because one field must be initialized before the others). The annotations on the parameters guarantee the invariant holds after the constructor finishes executing.
+ public DefaultHighLowDataset(Comparable seriesKey, Date @SameLen({"#2", "#3", "#4", "#5", "#6", "#7"}) [] date,
+ double @SameLen({"#2", "#3", "#4", "#5", "#6", "#7"}) [] high, double @SameLen({"#2", "#3", "#4", "#5", "#6", "#7"}) [] low,
+ double @SameLen({"#2", "#3", "#4", "#5", "#6", "#7"}) [] open, double @SameLen({"#2", "#3", "#4", "#5", "#6", "#7"}) [] close,
+ double @SameLen({"#2", "#3", "#4", "#5", "#6", "#7"}) [] volume) {
Args.nullNotPermitted(seriesKey, "seriesKey");
Args.nullNotPermitted(date, "date");
@@ -123,7 +127,7 @@ public DefaultHighLowDataset(Comparable seriesKey, Date[] date,
* @return The series key (never {@code null}).
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
return this.seriesKey;
}
@@ -142,8 +146,10 @@ public Comparable getSeriesKey(int series) {
* @see #getXDate(int, int)
*/
@Override
- public Number getX(int series, int item) {
- return new Long(this.date[item].getTime());
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ @SuppressWarnings("index") // array-list interop: the annotation on this method cannot expose the implementation detail of this class being backed by an array
+ Number result = new Long(this.date[item].getTime());
+ return result;
}
/**
@@ -158,8 +164,10 @@ public Number getX(int series, int item) {
*
* @see #getX(int, int)
*/
- public Date getXDate(int series, int item) {
- return this.date[item];
+ public Date getXDate(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ @SuppressWarnings("index") // array-list interop: the annotation on this method cannot expose the implementation detail of this class being backed by an array
+ Date result = this.date[item];
+ return result;
}
/**
@@ -176,7 +184,7 @@ public Date getXDate(int series, int item) {
* @see #getYValue(int, int)
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getClose(series, item);
}
@@ -191,8 +199,10 @@ public Number getY(int series, int item) {
* @see #getHighValue(int, int)
*/
@Override
- public Number getHigh(int series, int item) {
- return this.high[item];
+ public Number getHigh(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ @SuppressWarnings("index") // array-list interop: the annotation on this method cannot expose the implementation detail of this class being backed by an array
+ Number result = this.high[item];
+ return result;
}
/**
@@ -207,7 +217,7 @@ public Number getHigh(int series, int item) {
* @see #getHigh(int, int)
*/
@Override
- public double getHighValue(int series, int item) {
+ public double getHighValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number h = getHigh(series, item);
if (h != null) {
@@ -227,8 +237,10 @@ public double getHighValue(int series, int item) {
* @see #getLowValue(int, int)
*/
@Override
- public Number getLow(int series, int item) {
- return this.low[item];
+ public Number getLow(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ @SuppressWarnings("index") // array-list interop: the annotation on this method cannot expose the implementation detail of this class being backed by an array
+ Number result = this.low[item];
+ return result;
}
/**
@@ -243,7 +255,7 @@ public Number getLow(int series, int item) {
* @see #getLow(int, int)
*/
@Override
- public double getLowValue(int series, int item) {
+ public double getLowValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number l = getLow(series, item);
if (l != null) {
@@ -263,8 +275,10 @@ public double getLowValue(int series, int item) {
* @see #getOpenValue(int, int)
*/
@Override
- public Number getOpen(int series, int item) {
- return this.open[item];
+ public Number getOpen(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ @SuppressWarnings("index") // array-list interop: the annotation on this method cannot expose the implementation detail of this class being backed by an array
+ Number result = this.open[item];
+ return result;
}
/**
@@ -279,7 +293,7 @@ public Number getOpen(int series, int item) {
* @see #getOpen(int, int)
*/
@Override
- public double getOpenValue(int series, int item) {
+ public double getOpenValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number open = getOpen(series, item);
if (open != null) {
@@ -299,8 +313,10 @@ public double getOpenValue(int series, int item) {
* @see #getCloseValue(int, int)
*/
@Override
- public Number getClose(int series, int item) {
- return this.close[item];
+ public Number getClose(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ @SuppressWarnings("index") // array-list interop: the annotation on this method cannot expose the implementation detail of this class being backed by an array
+ Number result = this.close[item];
+ return result;
}
/**
@@ -315,7 +331,7 @@ public Number getClose(int series, int item) {
* @see #getClose(int, int)
*/
@Override
- public double getCloseValue(int series, int item) {
+ public double getCloseValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number c = getClose(series, item);
if (c != null) {
@@ -335,8 +351,10 @@ public double getCloseValue(int series, int item) {
* @see #getVolumeValue(int, int)
*/
@Override
- public Number getVolume(int series, int item) {
- return this.volume[item];
+ public Number getVolume(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
+ @SuppressWarnings("index") // array-list interop: the annotation on this method cannot expose the implementation detail of this class being backed by an array
+ Number result = this.volume[item];
+ return result;
}
/**
@@ -351,7 +369,7 @@ public Number getVolume(int series, int item) {
* @see #getVolume(int, int)
*/
@Override
- public double getVolumeValue(int series, int item) {
+ public double getVolumeValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
double result = Double.NaN;
Number v = getVolume(series, item);
if (v != null) {
@@ -368,7 +386,7 @@ public double getVolumeValue(int series, int item) {
* @return The number of series.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return 1;
}
@@ -380,8 +398,10 @@ public int getSeriesCount() {
* @return The number of items in the specified series.
*/
@Override
- public int getItemCount(int series) {
- return this.date.length;
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
+ @SuppressWarnings("index") // the annotation on this method isn't quite sensical, but it's the closest we can get, and is safe.
+ @LengthOf("this.getSeries(#1)") int result = this.date.length;
+ return result;
}
/**
@@ -432,7 +452,7 @@ public boolean equals(Object obj) {
*
* @return The data as an array of Number objects.
*/
- public static Number[] createNumberArray(double[] data) {
+ public static Number @SameLen("#1") [] createNumberArray(double[] data) {
Number[] result = new Number[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = new Double(data[i]);
diff --git a/src/main/java/org/jfree/data/xy/DefaultIntervalXYDataset.java b/src/main/java/org/jfree/data/xy/DefaultIntervalXYDataset.java
index 9003e532e..6abcc0c56 100644
--- a/src/main/java/org/jfree/data/xy/DefaultIntervalXYDataset.java
+++ b/src/main/java/org/jfree/data/xy/DefaultIntervalXYDataset.java
@@ -45,6 +45,9 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.common.value.qual.*;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -76,7 +79,7 @@ public class DefaultIntervalXYDataset extends AbstractIntervalXYDataset
* order of the series is significant. This list must be kept in sync
* with the seriesKeys list.
*/
- private List seriesList;
+ private List> implements ItemKey,
* @param seriesKey the series key.
* @param itemIndex the item index.
*/
- public XYItemKey(S seriesKey, int itemIndex) {
+ public XYItemKey(S seriesKey, @NonNegative int itemIndex) {
Args.nullNotPermitted(seriesKey, "seriesKey");
this.seriesKey = seriesKey;
this.itemIndex = itemIndex;
diff --git a/src/main/java/org/jfree/data/xy/XYSeries.java b/src/main/java/org/jfree/data/xy/XYSeries.java
index 040112b57..044a61f8e 100644
--- a/src/main/java/org/jfree/data/xy/XYSeries.java
+++ b/src/main/java/org/jfree/data/xy/XYSeries.java
@@ -80,6 +80,9 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
@@ -111,7 +114,7 @@ public class XYSeries extends Series implements Cloneable, Serializable {
protected List data;
/** The maximum number of items for the series. */
- private int maximumItemCount = Integer.MAX_VALUE;
+ private @NonNegative int maximumItemCount = Integer.MAX_VALUE;
/**
* A flag that controls whether the items are automatically sorted
@@ -265,6 +268,7 @@ private void updateBoundsForAddedItem(XYDataItem item) {
*
* @since 1.0.13
*/
+ @SuppressWarnings("index") // documentation bug: this method cannot be called unless there is at least one more item beyond the parameter in this dataset: I believe this is a bug
private void updateBoundsForRemovedItem(XYDataItem item) {
boolean itemContributesToXBounds = false;
boolean itemContributesToYBounds = false;
@@ -343,7 +347,7 @@ public boolean getAllowDuplicateXValues() {
* @see #getItems()
*/
@Override
- public int getItemCount() {
+ public @NonNegative int getItemCount() {
return this.data.size();
}
@@ -365,7 +369,7 @@ public List getItems() {
*
* @see #setMaximumItemCount(int)
*/
- public int getMaximumItemCount() {
+ public @NonNegative int getMaximumItemCount() {
return this.maximumItemCount;
}
@@ -383,7 +387,7 @@ public int getMaximumItemCount() {
*
* @param maximum the maximum number of items for the series.
*/
- public void setMaximumItemCount(int maximum) {
+ public void setMaximumItemCount(@NonNegative int maximum) {
this.maximumItemCount = maximum;
int remove = this.data.size() - maximum;
if (remove > 0) {
@@ -509,7 +513,9 @@ public void add(XYDataItem item, boolean notify) {
if (this.autoSort) {
int index = Collections.binarySearch(this.data, item);
if (index < 0) {
- this.data.add(-index - 1, item);
+ @SuppressWarnings("index") // binary search on list, which SearchIndex does not handle because lists are not fixed-size data structure
+ @NonNegative int newIndex = -index - 1;
+ this.data.add(newIndex, item);
}
else {
if (this.allowDuplicateXValues) {
@@ -559,7 +565,7 @@ public void add(XYDataItem item, boolean notify) {
* @param start the start index (zero-based).
* @param end the end index (zero-based).
*/
- public void delete(int start, int end) {
+ public void delete(@NonNegative int start, @NonNegative int end) {
this.data.subList(start, end + 1).clear();
findBoundsByIteration();
fireSeriesChanged();
@@ -573,7 +579,7 @@ public void delete(int start, int end) {
*
* @return The item removed.
*/
- public XYDataItem remove(int index) {
+ public XYDataItem remove(@NonNegative int index) {
XYDataItem removed = (XYDataItem) this.data.remove(index);
updateBoundsForRemovedItem(removed);
fireSeriesChanged();
@@ -590,6 +596,7 @@ public XYDataItem remove(int index) {
* @return The item removed.
*/
+ @SuppressWarnings("index") // this is a bug? The documentation doesn't say it, but a precondition of this method must be that x is in this XYSeries
public XYDataItem remove(Number x) {
return remove(indexOf(x));
}
@@ -616,7 +623,7 @@ public void clear() {
*
* @return The data item with the specified index.
*/
- public XYDataItem getDataItem(int index) {
+ public XYDataItem getDataItem(@NonNegative int index) {
XYDataItem item = (XYDataItem) this.data.get(index);
return (XYDataItem) item.clone();
}
@@ -630,7 +637,7 @@ public XYDataItem getDataItem(int index) {
*
* @since 1.0.14
*/
- XYDataItem getRawDataItem(int index) {
+ XYDataItem getRawDataItem(@NonNegative int index) {
return (XYDataItem) this.data.get(index);
}
@@ -641,7 +648,7 @@ XYDataItem getRawDataItem(int index) {
*
* @return The x-value (never {@code null}).
*/
- public Number getX(int index) {
+ public Number getX(@NonNegative int index) {
return getRawDataItem(index).getX();
}
@@ -652,7 +659,7 @@ public Number getX(int index) {
*
* @return The y-value (possibly {@code null}).
*/
- public Number getY(int index) {
+ public Number getY(@NonNegative int index) {
return getRawDataItem(index).getY();
}
@@ -703,7 +710,7 @@ private double maxIgnoreNaN(double a, double b) {
*
* @since 1.0.1
*/
- public void updateByIndex(int index, Number y) {
+ public void updateByIndex(@NonNegative int index, Number y) {
XYDataItem item = getRawDataItem(index);
// figure out if we need to iterate through all the y-values
@@ -820,7 +827,9 @@ else if (item.getY() != null) {
// append the value to the list...
item = (XYDataItem) item.clone();
if (this.autoSort) {
- this.data.add(-index - 1, item);
+ @SuppressWarnings("index") // binary search on list, which SearchIndex does not handle because lists are not fixed-size data structure
+ @NonNegative int addIndex = -index - 1;
+ this.data.add(addIndex, item);
}
else {
this.data.add(item);
@@ -869,6 +878,8 @@ public int indexOf(Number x) {
*
* @since 1.0.4
*/
+ @SuppressWarnings("index") // every access of the form result[0][i] or result[1][i] in this method issues an error despite
+ // being safe, since both result[0] and result[1] have length of itemCount.
public double[][] toArray() {
int itemCount = getItemCount();
double[][] result = new double[2][itemCount];
@@ -909,7 +920,7 @@ public Object clone() throws CloneNotSupportedException {
*
* @throws CloneNotSupportedException if there is a cloning problem.
*/
- public XYSeries createCopy(int start, int end)
+ public XYSeries createCopy(@NonNegative int start, @NonNegative int end)
throws CloneNotSupportedException {
XYSeries copy = (XYSeries) super.clone();
diff --git a/src/main/java/org/jfree/data/xy/XYSeriesCollection.java b/src/main/java/org/jfree/data/xy/XYSeriesCollection.java
index a55625036..01f9ac5f2 100644
--- a/src/main/java/org/jfree/data/xy/XYSeriesCollection.java
+++ b/src/main/java/org/jfree/data/xy/XYSeriesCollection.java
@@ -65,6 +65,10 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
@@ -170,7 +174,7 @@ public void addSeries(XYSeries series) {
*
* @param series the series index (zero-based).
*/
- public void removeSeries(int series) {
+ public void removeSeries(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds.");
}
@@ -220,7 +224,7 @@ public void removeAllSeries() {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.data.size();
}
@@ -243,7 +247,7 @@ public List getSeries() {
*
* @since 1.0.6
*/
- public int indexOf(XYSeries series) {
+ public @GTENegativeOne int indexOf(XYSeries series) {
Args.nullNotPermitted(series, "series");
return this.data.indexOf(series);
}
@@ -258,7 +262,7 @@ public int indexOf(XYSeries series) {
* @throws IllegalArgumentException if {@code series} is not in the
* range {@code 0} to {@code getSeriesCount() - 1}.
*/
- public XYSeries getSeries(int series) {
+ public XYSeries getSeries(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds");
}
@@ -301,7 +305,7 @@ public XYSeries getSeries(Comparable key) {
* specified range.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
// defer argument checking
return getSeries(series).getKey();
}
@@ -316,7 +320,7 @@ public Comparable getSeriesKey(int series) {
*
* @since 1.0.14
*/
- public int getSeriesIndex(Comparable key) {
+ public @GTENegativeOne int getSeriesIndex(Comparable key) {
Args.nullNotPermitted(key, "key");
int seriesCount = getSeriesCount();
for (int i = 0; i < seriesCount; i++) {
@@ -339,7 +343,8 @@ public int getSeriesIndex(Comparable key) {
* range {@code 0} to {@code getSeriesCount() - 1}.
*/
@Override
- public int getItemCount(int series) {
+ @SuppressWarnings("index") // array-list interop: getSeries.getItemCount cannot be annotated because some series are mutable
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
// defer argument checking
return getSeries(series).getItemCount();
}
@@ -353,7 +358,7 @@ public int getItemCount(int series) {
* @return The value.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
XYSeries s = (XYSeries) this.data.get(series);
return s.getX(item);
}
@@ -367,7 +372,8 @@ public Number getX(int series, int item) {
* @return The starting X value.
*/
@Override
- public Number getStartX(int series, int item) {
+ @SuppressWarnings("index") // array-list interop: getSeries.getItemCount cannot be annotated because some series are mutable
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return this.intervalDelegate.getStartX(series, item);
}
@@ -380,7 +386,8 @@ public Number getStartX(int series, int item) {
* @return The ending X value.
*/
@Override
- public Number getEndX(int series, int item) {
+ @SuppressWarnings("index") // array-list interop: getSeries.getItemCount cannot be annotated because some series are mutable
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return this.intervalDelegate.getEndX(series, item);
}
@@ -393,7 +400,7 @@ public Number getEndX(int series, int item) {
* @return The value (possibly {@code null}).
*/
@Override
- public Number getY(int series, int index) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int index) {
XYSeries s = (XYSeries) this.data.get(series);
return s.getY(index);
}
@@ -407,7 +414,7 @@ public Number getY(int series, int index) {
* @return The starting Y value.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
@@ -420,7 +427,7 @@ public Number getStartY(int series, int item) {
* @return The ending Y value.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getY(series, item);
}
diff --git a/src/main/java/org/jfree/data/xy/XYZDataset.java b/src/main/java/org/jfree/data/xy/XYZDataset.java
index 15adba35f..ef6bdf2bd 100644
--- a/src/main/java/org/jfree/data/xy/XYZDataset.java
+++ b/src/main/java/org/jfree/data/xy/XYZDataset.java
@@ -43,6 +43,10 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
/**
* The interface through which JFreeChart obtains data in the form of (x, y, z)
* items - used for XY and XYZ plots.
@@ -57,7 +61,7 @@ public interface XYZDataset extends XYDataset {
*
* @return The z-value (possibly {@code null}).
*/
- public Number getZ(int series, int item);
+ public Number getZ(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
/**
* Returns the z-value (as a double primitive) for an item within a series.
@@ -67,6 +71,6 @@ public interface XYZDataset extends XYDataset {
*
* @return The z-value.
*/
- public double getZValue(int series, int item);
+ public double getZValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item);
}
diff --git a/src/main/java/org/jfree/data/xy/XisSymbolic.java b/src/main/java/org/jfree/data/xy/XisSymbolic.java
index 5ae72153e..3c3a2aad8 100644
--- a/src/main/java/org/jfree/data/xy/XisSymbolic.java
+++ b/src/main/java/org/jfree/data/xy/XisSymbolic.java
@@ -42,6 +42,10 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
/**
* Represent a data set where X is a symbolic values. Each symbolic value is
* linked with an Integer.
@@ -64,7 +68,7 @@ public interface XisSymbolic {
*
* @return The symbolic value.
*/
- public String getXSymbolicValue(int series, int item);
+ public String getXSymbolicValue(@NonNegative int series, @NonNegative int item);
/**
* Returns the symbolic value linked with the specified {@code Integer}.
diff --git a/src/main/java/org/jfree/data/xy/YIntervalSeries.java b/src/main/java/org/jfree/data/xy/YIntervalSeries.java
index d991c170f..8ee9fefc2 100644
--- a/src/main/java/org/jfree/data/xy/YIntervalSeries.java
+++ b/src/main/java/org/jfree/data/xy/YIntervalSeries.java
@@ -42,6 +42,8 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.NonNegative;
+
import org.jfree.data.ComparableObjectItem;
import org.jfree.data.ComparableObjectSeries;
import org.jfree.data.general.SeriesChangeEvent;
@@ -114,7 +116,7 @@ public void add(YIntervalDataItem item, boolean notify) {
*
* @return The x-value (never {@code null}).
*/
- public Number getX(int index) {
+ public Number getX(@NonNegative int index) {
YIntervalDataItem item = (YIntervalDataItem) getDataItem(index);
return item.getX();
}
@@ -126,7 +128,7 @@ public Number getX(int index) {
*
* @return The y-value.
*/
- public double getYValue(int index) {
+ public double getYValue(@NonNegative int index) {
YIntervalDataItem item = (YIntervalDataItem) getDataItem(index);
return item.getYValue();
}
@@ -141,7 +143,7 @@ public double getYValue(int index) {
*
* @since 1.0.5
*/
- public double getYLowValue(int index) {
+ public double getYLowValue(@NonNegative int index) {
YIntervalDataItem item = (YIntervalDataItem) getDataItem(index);
return item.getYLowValue();
}
@@ -156,7 +158,7 @@ public double getYLowValue(int index) {
*
* @since 1.0.5
*/
- public double getYHighValue(int index) {
+ public double getYHighValue(@NonNegative int index) {
YIntervalDataItem item = (YIntervalDataItem) getDataItem(index);
return item.getYHighValue();
}
@@ -169,7 +171,7 @@ public double getYHighValue(int index) {
* @return The data item.
*/
@Override
- public ComparableObjectItem getDataItem(int index) {
+ public ComparableObjectItem getDataItem(@NonNegative int index) {
return super.getDataItem(index);
}
diff --git a/src/main/java/org/jfree/data/xy/YIntervalSeriesCollection.java b/src/main/java/org/jfree/data/xy/YIntervalSeriesCollection.java
index c136cf57b..1d9591985 100644
--- a/src/main/java/org/jfree/data/xy/YIntervalSeriesCollection.java
+++ b/src/main/java/org/jfree/data/xy/YIntervalSeriesCollection.java
@@ -46,6 +46,10 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
+import org.checkerframework.checker.index.qual.NonNegative;
+
import java.io.Serializable;
import java.util.List;
import org.jfree.chart.util.ObjectUtils;
@@ -93,7 +97,7 @@ public void addSeries(YIntervalSeries series) {
* @return The series count.
*/
@Override
- public int getSeriesCount() {
+ public @NonNegative int getSeriesCount() {
return this.data.size();
}
@@ -107,7 +111,7 @@ public int getSeriesCount() {
* @throws IllegalArgumentException if {@code series} is not in the
* range {@code 0} to {@code getSeriesCount() - 1}.
*/
- public YIntervalSeries getSeries(int series) {
+ public YIntervalSeries getSeries(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds");
}
@@ -126,7 +130,7 @@ public YIntervalSeries getSeries(int series) {
* specified range.
*/
@Override
- public Comparable getSeriesKey(int series) {
+ public Comparable getSeriesKey(@NonNegative int series) {
// defer argument checking
return getSeries(series).getKey();
}
@@ -142,7 +146,8 @@ public Comparable getSeriesKey(int series) {
* range {@code 0} to {@code getSeriesCount() - 1}.
*/
@Override
- public int getItemCount(int series) {
+ @SuppressWarnings("index") // array-list interop: getSeries.getItemCount cannot be annotated because some series are mutable
+ public @LengthOf("this.getSeries(#1)") int getItemCount(@NonNegative int series) {
// defer argument checking
return getSeries(series).getItemCount();
}
@@ -156,7 +161,7 @@ public int getItemCount(int series) {
* @return The x-value.
*/
@Override
- public Number getX(int series, int item) {
+ public Number getX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
YIntervalSeries s = (YIntervalSeries) this.data.get(series);
return s.getX(item);
}
@@ -171,7 +176,7 @@ public Number getX(int series, int item) {
* @return The value.
*/
@Override
- public double getYValue(int series, int item) {
+ public double getYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
YIntervalSeries s = (YIntervalSeries) this.data.get(series);
return s.getYValue(item);
}
@@ -186,7 +191,7 @@ public double getYValue(int series, int item) {
* @return The value.
*/
@Override
- public double getStartYValue(int series, int item) {
+ public double getStartYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
YIntervalSeries s = (YIntervalSeries) this.data.get(series);
return s.getYLowValue(item);
}
@@ -201,7 +206,7 @@ public double getStartYValue(int series, int item) {
* @return The value.
*/
@Override
- public double getEndYValue(int series, int item) {
+ public double getEndYValue(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
YIntervalSeries s = (YIntervalSeries) this.data.get(series);
return s.getYHighValue(item);
}
@@ -215,7 +220,7 @@ public double getEndYValue(int series, int item) {
* @return The y-value.
*/
@Override
- public Number getY(int series, int item) {
+ public Number getY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
YIntervalSeries s = (YIntervalSeries) this.data.get(series);
return new Double(s.getYValue(item));
}
@@ -230,7 +235,7 @@ public Number getY(int series, int item) {
* @return The x-value.
*/
@Override
- public Number getStartX(int series, int item) {
+ public Number getStartX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getX(series, item);
}
@@ -244,7 +249,7 @@ public Number getStartX(int series, int item) {
* @return The x-value.
*/
@Override
- public Number getEndX(int series, int item) {
+ public Number getEndX(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
return getX(series, item);
}
@@ -257,7 +262,7 @@ public Number getEndX(int series, int item) {
* @return The start y-value.
*/
@Override
- public Number getStartY(int series, int item) {
+ public Number getStartY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
YIntervalSeries s = (YIntervalSeries) this.data.get(series);
return new Double(s.getYLowValue(item));
}
@@ -271,7 +276,7 @@ public Number getStartY(int series, int item) {
* @return The end y-value.
*/
@Override
- public Number getEndY(int series, int item) {
+ public Number getEndY(@NonNegative int series, @IndexFor("this.getSeries(#1)") int item) {
YIntervalSeries s = (YIntervalSeries) this.data.get(series);
return new Double(s.getYHighValue(item));
}
@@ -284,7 +289,7 @@ public Number getEndY(int series, int item) {
*
* @since 1.0.10
*/
- public void removeSeries(int series) {
+ public void removeSeries(@NonNegative int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds.");
}
diff --git a/src/main/java/org/jfree/data/xy/YisSymbolic.java b/src/main/java/org/jfree/data/xy/YisSymbolic.java
index bd5763e39..99c7796de 100644
--- a/src/main/java/org/jfree/data/xy/YisSymbolic.java
+++ b/src/main/java/org/jfree/data/xy/YisSymbolic.java
@@ -43,6 +43,8 @@
package org.jfree.data.xy;
+import org.checkerframework.checker.index.qual.*;
+
/**
* Represent a data set where Y is a symbolic values. Each symbolic value is
* linked with an Integer.
@@ -65,7 +67,7 @@ public interface YisSymbolic {
*
* @return The symbolic value.
*/
- public String getYSymbolicValue(int series, int item);
+ public String getYSymbolicValue(@NonNegative int series, @NonNegative int item);
/**
* Returns the symbolic value linked with the specified {@code Integer}.
diff --git a/src/test/java/org/jfree/data/statistics/DefaultStatisticalCategoryDatasetTest.java b/src/test/java/org/jfree/data/statistics/DefaultStatisticalCategoryDatasetTest.java
index 6d6553972..221f92c93 100644
--- a/src/test/java/org/jfree/data/statistics/DefaultStatisticalCategoryDatasetTest.java
+++ b/src/test/java/org/jfree/data/statistics/DefaultStatisticalCategoryDatasetTest.java
@@ -43,6 +43,7 @@
*/
package org.jfree.data.statistics;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
diff --git a/src/test/java/org/jfree/data/time/TimeSeriesCollectionTest.java b/src/test/java/org/jfree/data/time/TimeSeriesCollectionTest.java
index cee454dcd..1e8ba2615 100644
--- a/src/test/java/org/jfree/data/time/TimeSeriesCollectionTest.java
+++ b/src/test/java/org/jfree/data/time/TimeSeriesCollectionTest.java
@@ -2,7 +2,7 @@
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
- * (C) Copyright 2000-2016, by Object Refinery Limited and Contributors.
+ * (C) Copyright 2000-2018, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jfreechart/index.html
*
@@ -27,19 +27,11 @@
* -----------------------------
* TimeSeriesCollectionTest.java
* -----------------------------
- * (C) Copyright 2003-2016, by Object Refinery Limited.
+ * (C) Copyright 2003-2018, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
- * Changes
- * -------
- * 01-May-2003 : Version 1 (DG);
- * 04-Dec-2003 : Added a test for the getSurroundingItems() method (DG);
- * 08-May-2007 : Added testIndexOf() method (DG);
- * 18-May-2009 : Added testFindDomainBounds() (DG);
- * 08-Jan-2012 : Added testBug3445507() (DG);
- *
*/
package org.jfree.data.time;
@@ -58,7 +50,6 @@
import java.util.Locale;
import java.util.TimeZone;
import org.jfree.chart.TestUtils;
-
import org.jfree.data.Range;
import org.jfree.data.general.DatasetUtils;
import org.junit.Test;
@@ -309,6 +300,10 @@ public void testIndexOf() {
*/
@Test
public void testFindDomainBounds() {
+ // store the current time zone
+ TimeZone saved = TimeZone.getDefault();
+ TimeZone.setDefault(TimeZone.getTimeZone("Europe/Paris"));
+
TimeSeriesCollection dataset = new TimeSeriesCollection();
List visibleSeriesKeys = new java.util.ArrayList();
Range r = DatasetUtils.findDomainBounds(dataset, visibleSeriesKeys,
@@ -321,10 +316,6 @@ public void testFindDomainBounds() {
r = DatasetUtils.findDomainBounds(dataset, visibleSeriesKeys, true);
assertNull(r);
- // store the current time zone
- TimeZone saved = TimeZone.getDefault();
- TimeZone.setDefault(TimeZone.getTimeZone("Europe/Paris"));
-
s1.add(new Year(2008), 8.0);
r = DatasetUtils.findDomainBounds(dataset, visibleSeriesKeys, true);
assertEquals(1199142000000.0, r.getLowerBound(), EPSILON);