From: Chris Jaekl Date: Sat, 16 Jan 2016 13:25:00 +0000 (+0900) Subject: Display LocalVariables along with Locations in the html report. X-Git-Url: https://jaekl.net/gitweb/?a=commitdiff_plain;h=e9a80ba4b35ce25d00d259038c7d2cb0a954dcc4;p=cfb.git Display LocalVariables along with Locations in the html report. --- diff --git a/prod/net/jaekl/cfb/analyze/HtmlReport.java b/prod/net/jaekl/cfb/analyze/HtmlReport.java index 166a140..7ff6962 100644 --- a/prod/net/jaekl/cfb/analyze/HtmlReport.java +++ b/prod/net/jaekl/cfb/analyze/HtmlReport.java @@ -7,11 +7,15 @@ import java.io.PrintWriter; import net.jaekl.cfb.CfbBundle; import net.jaekl.cfb.store.Location; import net.jaekl.cfb.util.Command; +import net.jaekl.cfb.util.XmlEscape; import net.jaekl.cfb.xml.BugInstance; +import net.jaekl.cfb.xml.LocalVariable; import net.jaekl.cfb.xml.messages.BugPattern; import net.jaekl.cfb.xml.messages.MessageCollection; public class HtmlReport { + private static final String NBSP = " "; // " " isn't valid XML, but " " is. + CfbBundle m_bundle; Delta m_delta; MessageCollection m_msgColl; @@ -86,7 +90,9 @@ public class HtmlReport { } } - pw.println(" " + sb.toString() + ""); + String displayText = XmlEscape.toEscaped(sb.toString()); + + pw.println(" " + displayText + ""); } } @@ -108,6 +114,7 @@ public class HtmlReport { pw.println(" " + bug.getType() + ""); pw.println(" "); writeBugLocations(pw, bug); + writeBugVariables(pw, bug); pw.println(" " + pattern.getShort() + ""); pw.println(" "); pw.println(" " + pattern.getDetails() + ""); @@ -118,6 +125,24 @@ public class HtmlReport { } } + void writeBugVariables(PrintWriter pw, BugInstance bug) + { + for (LocalVariable var : bug.getVariables()) { + StringBuffer sb = new StringBuffer(); + + if (null != var) { + String name = var.getName(); + String role = var.getRole(); + sb.append(name); + if (null != role) { + sb.append(" (").append(role).append(")"); + } + } + + pw.println(" " + sb.toString() + ""); + } + } + void writeHeader(PrintWriter pw) { String title = trans(CfbBundle.CFB_REPORT); @@ -139,7 +164,7 @@ public class HtmlReport { void writeSummary(PrintWriter pw) { - final String SEP = ":  "; + final String SEP = ":" + NBSP + NBSP; String earlierVersion = ""; if (null != m_delta.getEarlier()) { @@ -157,7 +182,7 @@ public class HtmlReport { pw.println(" " + trans(CfbBundle.OLD_VERSION) + SEP + ""); pw.println(" " + earlierVersion + ""); pw.println(" "); - pw.println("  "); + pw.println(" " + NBSP + ""); pw.println(" "); pw.println(" " + trans(CfbBundle.NEW_BUGS) + SEP + ""); pw.println(" " + trans(CfbBundle.NUM_BUGS, m_delta.getNumNew()) + ""); @@ -182,6 +207,7 @@ public class HtmlReport { pw.println(" .CategoryValue { text-align: left; }"); pw.println(" .Loc { font-family: monospace; }"); pw.println(" .SectionHead td { background-color: #0000FF; color: #FFFFFF; font-size: 1.25em; font-weight: bold; }"); + pw.println(" .Var { font-family: monospace; }"); pw.println(" "); } } diff --git a/prod/net/jaekl/cfb/util/XmlEscape.java b/prod/net/jaekl/cfb/util/XmlEscape.java new file mode 100644 index 0000000..9e177bb --- /dev/null +++ b/prod/net/jaekl/cfb/util/XmlEscape.java @@ -0,0 +1,39 @@ +package net.jaekl.cfb.util; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class XmlEscape { + // The following code adapted from: + // http://stackoverflow.com/questions/439298/best-way-to-encode-text-data-for-xml-in-java#439311 + private final static String ESCAPE_CHARS = "<>&\"\'"; + private final static List ESCAPE_STRINGS = + Collections.unmodifiableList(Arrays.asList(new String[] {"<", ">", "&", """, "'" })); + + //should only use for the content of an attribute or tag + public static String toEscaped(String content) { + String result = content; + + if ((content != null) && (content.length() > 0)) { + boolean modified = false; + StringBuilder stringBuilder = new StringBuilder(content.length()); + for (int i = 0, count = content.length(); i < count; ++i) { + String character = content.substring(i, i + 1); + int pos = ESCAPE_CHARS.indexOf(character); + if (pos > -1) { + stringBuilder.append(ESCAPE_STRINGS.get(pos)); + modified = true; + } + else { + stringBuilder.append(character); + } + } + if (modified) { + result = stringBuilder.toString(); + } + } + + return result; + } +} diff --git a/test/net/jaekl/cfb/analyze/BugReportData.java b/test/net/jaekl/cfb/analyze/BugReportData.java new file mode 100644 index 0000000..7a6d222 --- /dev/null +++ b/test/net/jaekl/cfb/analyze/BugReportData.java @@ -0,0 +1,100 @@ +package net.jaekl.cfb.analyze; + +public class BugReportData { + private static final String DM_DEFAULT_ENCODING = "" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n"; + + private static final String RCN_REDUNDANT_NULL_CHECK = "" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n"; + + private static String VO_VOLATILE_INCREMENT = "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + + private static final String DM_NUMBER_CTOR_156 = "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + + private static final String DM_NUMBER_CTOR_169 = "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + + private static final String PROLOGUE = "" + + "\n" + + "\n" + + "\n" + + "/home/chris/prog/././cfb/bin\n" + + "/home/chris/prog/././cfb/src\n" + + "\n"; + + private static final String EPILOGUE = "" + + "\n"; + + public static String getDmDefaultEncoding() { return DM_DEFAULT_ENCODING; } + public static String getRcnRedundantNullCheck() { return RCN_REDUNDANT_NULL_CHECK; } + public static String getVoVolatileIncrement() { return VO_VOLATILE_INCREMENT; } + public static String getDmNumberCtor156() { return DM_NUMBER_CTOR_156; } + public static String getDmNumberCtor169() { return DM_NUMBER_CTOR_169; } + + public static String getPrologue() { return PROLOGUE; } + public static String getEpilogue() { return EPILOGUE; } +} diff --git a/test/net/jaekl/cfb/analyze/DeltaTest.java b/test/net/jaekl/cfb/analyze/DeltaTest.java index cb2222c..bc974ee 100644 --- a/test/net/jaekl/cfb/analyze/DeltaTest.java +++ b/test/net/jaekl/cfb/analyze/DeltaTest.java @@ -15,94 +15,6 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class DeltaTest { - private static final String DM_DEFAULT_ENCODING = "" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n"; - - private static final String RCN_REDUNDANT_NULL_CHECK = "" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n"; - - private static String VO_VOLATILE_INCREMENT = "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + ""; - - private static final String DM_NUMBER_CTOR_156 = "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + ""; - - private static final String DM_NUMBER_CTOR_169 = "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + ""; - - private static final String PROLOGUE = "" - + "\n" - + "\n" - + "\n" - + "/home/chris/prog/././cfb/bin\n" - + "/home/chris/prog/././cfb/src\n" - + "\n"; - - private static final String EPILOGUE = "" - + "\n"; - private Analysis analysisFromXml(String xml, String projectName, String version) throws FileNotFoundException, IOException, SAXException { @@ -126,11 +38,11 @@ public class DeltaTest { private String buildXml(String[][] bugSpecs, int from, int to) { - StringBuilder sb = new StringBuilder(PROLOGUE); + StringBuilder sb = new StringBuilder(BugReportData.getPrologue()); for (int i = from; i <= to; ++i) { sb.append(bugSpecs[i][0]); } - sb.append(EPILOGUE); + sb.append(BugReportData.getEpilogue()); return sb.toString(); } @@ -190,10 +102,9 @@ public class DeltaTest { public void test_computeDeltas() throws FileNotFoundException, IOException, SAXException { String[][] bugSpecs = { - { DM_DEFAULT_ENCODING, "DM_DEFAULT_ENCODING" }, - { RCN_REDUNDANT_NULL_CHECK, "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" }, - { DM_NUMBER_CTOR_156, "DM_NUMBER_CTOR" }, - { DM_NUMBER_CTOR_169, "DM_NUMBER_CTOR" } + { BugReportData.getDmDefaultEncoding(), "DM_DEFAULT_ENCODING" }, + { BugReportData.getRcnRedundantNullCheck(), "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" }, + { BugReportData.getDmNumberCtor169(), "DM_NUMBER_CTOR" } }; for (int w = 0; w < bugSpecs.length; ++w) { @@ -211,11 +122,11 @@ public class DeltaTest { public void test_deltaWithNoPrior() throws FileNotFoundException, IOException, SAXException { String[][] bugSpecs = { - { DM_DEFAULT_ENCODING, "DM_DEFAULT_ENCODING" }, - { RCN_REDUNDANT_NULL_CHECK, "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" }, - { VO_VOLATILE_INCREMENT, "VO_VOLATILE_INCREMENT" }, - { DM_NUMBER_CTOR_156, "DM_NUMBER_CTOR" }, - { DM_NUMBER_CTOR_169, "DM_NUMBER_CTOR" } + { BugReportData.getDmDefaultEncoding(), "DM_DEFAULT_ENCODING" }, + { BugReportData.getRcnRedundantNullCheck(), "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" }, + { BugReportData.getVoVolatileIncrement(), "VO_VOLATILE_INCREMENT" }, + { BugReportData.getDmNumberCtor156(), "DM_NUMBER_CTOR" }, + { BugReportData.getDmNumberCtor169(), "DM_NUMBER_CTOR" } }; final String PROJECT_NAME = "AlphaOne"; diff --git a/test/net/jaekl/cfb/analyze/HtmlReportTest.java b/test/net/jaekl/cfb/analyze/HtmlReportTest.java new file mode 100644 index 0000000..26f9f8e --- /dev/null +++ b/test/net/jaekl/cfb/analyze/HtmlReportTest.java @@ -0,0 +1,199 @@ +package net.jaekl.cfb.analyze; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import net.jaekl.cfb.CfbBundle; +import net.jaekl.cfb.CfbBundleMock; +import net.jaekl.cfb.util.Command; +import net.jaekl.cfb.xml.messages.MessageCollection; +import net.jaekl.cfb.xml.messages.MessagesData; + +import org.junit.Before; +import org.junit.Test; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +public class HtmlReportTest { + private static class CheckWellFormedHandler extends DefaultHandler + { + @Override + public void warning(SAXParseException spe) throws SAXException + { + throw new SAXException(spe); + } + + @Override + public void error(SAXParseException spe) throws SAXException + { + throw new SAXException(spe); + } + + @Override + public void fatalError(SAXParseException spe) throws SAXException + { + throw new SAXException(spe); + } + } + + String[] BUG_XMLS = { + BugReportData.getDmDefaultEncoding(), + BugReportData.getDmNumberCtor156(), + BugReportData.getRcnRedundantNullCheck(), + BugReportData.getVoVolatileIncrement() + }; + + private static final String PROJECT_NAME = "Project Name"; + private static final String FIRST_VERSION = "1.0.1.3145"; + private static final String SECOND_VERSION = "1.0.1.3146"; + + private CfbBundleMock m_bundle; + private MessageMapMock m_msgMap; + + private Analysis analysisFromXml(String xml, String projectName, String version) + throws FileNotFoundException, IOException, SAXException + { + Analysis analysis = new Analysis(projectName, version); + ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes(Command.UTF_8)); + InputSource inputSource = new InputSource(bais); + analysis.parse(inputSource); + + return analysis; + } + + private void assertContainsTagExactlyOnce(String html, String tag) + { + int pos = html.indexOf("<" + tag + ">"); + assertTrue(pos >= 0); + String substr = html.substring(pos + 1); + assertFalse(substr.contains("<" + tag + ">")); + assertTrue(substr.contains("")); + } + + private void checkForWellFormedXml(String xml) throws IOException, ParserConfigurationException, SAXException + { + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setValidating(false); + SAXParser parser = spf.newSAXParser(); + + try ( ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes(Command.UTF_8)) ) + { + InputSource source = new InputSource(bais); + CheckWellFormedHandler handler = new CheckWellFormedHandler(); + + parser.parse(source, handler); + } + } + + private String createReport(String firstXml, String secondXml) throws IOException, SAXException + { + Analysis first = null; + if (null != firstXml) { + first = analysisFromXml(firstXml, PROJECT_NAME, FIRST_VERSION); + } + + Analysis second = analysisFromXml(secondXml, PROJECT_NAME, SECOND_VERSION); + Delta delta = new Delta(first, second); + MessageCollection msgColl = m_msgMap.getColl(); + assertNotNull(msgColl); + + HtmlReport htmlReport = new HtmlReport(m_bundle, msgColl, delta); + + try ( + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + ) + { + htmlReport.write(pw); + pw.close(); + sw.close(); + return sw.toString(); + } + } + + private void doTestDelta(String firstXml, String secondXml) throws FileNotFoundException, IOException, SAXException, ParserConfigurationException + { + String html = createReport(firstXml, secondXml); + validateReport(html); + } + + private void validateReport(String html) throws IOException, ParserConfigurationException, SAXException + { + assertNotNull(html); + + // Report should be well-formed XHTML + checkForWellFormedXml(html); + + // Certain tags should be present exactly once + for (String tag : new String[]{"HTML", "HEAD", "BODY", "STYLE"}) + { + assertContainsTagExactlyOnce(html, tag); + } + + // Title should be the result of translating CFB_REPORT + String title = m_bundle.get(CfbBundle.CFB_REPORT); + assertTrue(html.contains("" + title + "")); + + // The character set UTF-8 should be specified + assertTrue(html.contains("")); + } + + @Before + public void setUp() throws FileNotFoundException, IOException, SAXException + { + m_bundle = new CfbBundleMock(); + m_msgMap = new MessageMapMock(); + + try (ByteArrayInputStream bais = new ByteArrayInputStream(MessagesData.getData().getBytes(Command.UTF_8))) { + m_msgMap.parse(new InputSource(bais)); + } + } + + @Test + public void testVariousDeltas() throws FileNotFoundException, IOException, SAXException, ParserConfigurationException + { + StringBuilder sbFirst = new StringBuilder(BugReportData.getPrologue()); + StringBuilder sbSecond = new StringBuilder(BugReportData.getPrologue()); + for (int i = 0; i < BUG_XMLS.length; ++i) { + sbFirst.append(BUG_XMLS[i]); + for (int j = 0; j < BUG_XMLS.length; ++j) { + sbSecond.append(BUG_XMLS[j]); + + String firstXml = sbFirst.toString() + BugReportData.getEpilogue(); + String secondXml = sbSecond.toString() + BugReportData.getEpilogue(); + + doTestDelta(firstXml, secondXml); + } + } + } + + @Test + public void testLocalVariable() throws FileNotFoundException, IOException, SAXException, ParserConfigurationException + { + String xml = BugReportData.getPrologue() + + BugReportData.getRcnRedundantNullCheck() + + BugReportData.getEpilogue(); + + String html = createReport(null, xml); + validateReport(html); + + String expected = "con (LOCAL_VARIABLE_VALUE_OF)"; + // expected string should be present exactly once + int pos = html.indexOf(expected); + assertTrue(pos > 0); + assertFalse(html.substring(pos + expected.length()).contains(expected)); + } +} diff --git a/test/net/jaekl/cfb/analyze/MessageMapTest.java b/test/net/jaekl/cfb/analyze/MessageMapTest.java new file mode 100644 index 0000000..45ada91 --- /dev/null +++ b/test/net/jaekl/cfb/analyze/MessageMapTest.java @@ -0,0 +1,63 @@ +package net.jaekl.cfb.analyze; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +import net.jaekl.cfb.util.Command; +import net.jaekl.cfb.xml.messages.BugCategory; +import net.jaekl.cfb.xml.messages.BugPattern; +import net.jaekl.cfb.xml.messages.MessageCollection; +import net.jaekl.cfb.xml.messages.MessagesData; + +import org.junit.Test; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class MessageMapTest { + + private boolean containsCategory(MessageCollection msgColl, String catName) { + for (BugCategory cat : msgColl.getCategories()) { + if (catName.equals(cat.getCategory())) { + return true; + } + } + return false; + } + + private boolean containsPattern(MessageCollection msgColl, String patName) { + BugPattern pat = msgColl.getPattern(patName); + return(null != pat); + } + + @Test + public void testParseMessagesData() throws FileNotFoundException, IOException, SAXException + { + MessageMap msgMap = new MessageMap(); + + ByteArrayInputStream bais = new ByteArrayInputStream(MessagesData.getData().getBytes(Command.UTF_8)); + InputSource source = new InputSource(bais); + msgMap.parse(source); + + MessageCollection msgColl = msgMap.getColl(); + assertNotNull(msgColl); + + // Non-exhaustive list of category names that should have been picked up by the parse + String[] expectedCategories = { "BAD_PRACTICE", "CORRECTNESS", "PERFORMANCE", "STYLE" }; + + for (String catName : expectedCategories) { + assertTrue(containsCategory(msgMap.getColl(), catName)); + } + + // Non-exhaustive list of pattern names that sohuld have been picked up by the parse + String[] expectedPatterns = { "DM_DEFAULT_ENCODING", "VO_VOLATILE_INCREMENT" }; + + for (String patName : expectedPatterns) { + assertTrue(containsPattern(msgMap.getColl(), patName)); + } + } + +} diff --git a/test/net/jaekl/cfb/util/XmlEscapeTest.java b/test/net/jaekl/cfb/util/XmlEscapeTest.java new file mode 100644 index 0000000..f514e95 --- /dev/null +++ b/test/net/jaekl/cfb/util/XmlEscapeTest.java @@ -0,0 +1,53 @@ +package net.jaekl.cfb.util; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class XmlEscapeTest { + + @Test + public void test() { + String[][] data = { + { null, null }, + { "", "" }, + { "fred", "fred" }, + { "org.example.Foo.()", "org.example.Foo.<init>()" }, + { + "ἄνδρα μοι ἔννεπε, μοῦσα, πολύτροπον, ὃς μάλα πολλὰ", + "ἄνδρα μοι ἔννεπε, μοῦσα, πολύτροπον, ὃς μάλα πολλὰ" + }, + { + "L'amour est enfant de Bohême\n" + + "Il n'a jamais, jamais connu de loi\n" + + "Si tu ne m'aimes pas, je t'aime\n" + + "Si je t'aime, prends garde à toi!\n" + + "Si tu ne m’aimes pas\n" + + "Si tu ne m’aimes pas, je t’aime!\n" + + "Mais, si je t’aime\n" + + "Si je t’aime, prends garde à toi!", + + "L'amour est enfant de Bohême\n" + + "Il n'a jamais, jamais connu de loi\n" + + "Si tu ne m'aimes pas, je t'aime\n" + + "Si je t'aime, prends garde à toi!\n" + + "Si tu ne m’aimes pas\n" + + "Si tu ne m’aimes pas, je t’aime!\n" + + "Mais, si je t’aime\n" + + "Si je t’aime, prends garde à toi!", + }, + { + "\"I'm sorry Dave,\" said Hal, \"but I can't do that.\"", + ""I'm sorry Dave," said Hal, "but I can't do that."" + } + }; + + for (String[] datum : data) { + String input = datum[0]; + String expected = datum[1]; + String actual = XmlEscape.toEscaped(input); + assertEquals(expected, actual); + } + } + +} diff --git a/test/net/jaekl/cfb/xml/messages/MessagesData.java b/test/net/jaekl/cfb/xml/messages/MessagesData.java new file mode 100644 index 0000000..28360b2 --- /dev/null +++ b/test/net/jaekl/cfb/xml/messages/MessagesData.java @@ -0,0 +1,450 @@ +package net.jaekl.cfb.xml.messages; + +public class MessagesData +{ + private static final String DATA = "\n" + + "\n" + + "\n" + + " \n" + + " \n" + + " Core FindBugs plugin\n" + + "
\n" + + "\n" + + "This plugin contains all of the standard FindBugs detectors.\n" + + "

\n" + + "]]>\n" + + "
\n" + + " http://findbugs.sourceforge.net/bugDescriptions.html\n" + + " http://findbugs.sourceforge.net/allBugDescriptions.html\n" + + "
\n" + + " \n" + + " Add msgs (e.g., textual descriptions of bugs) to analysis results\n" + + " \n" + + " \n" + + " Perform FindBugs Analysis\n" + + " \n" + + " \n" + + " Launch FindBugs GUI\n" + + " \n" + + " \n" + + " Convert analysis results to textual form\n" + + " \n" + + " \n" + + " Provide help for commands\n" + + " \n" + + " \n" + + " List FindBugs version\n" + + " \n" + + " \n" + + " Filter analysis results\n" + + " \n" + + " \n" + + " Set project configuration/options\n" + + " \n" + + " \n" + + " List details from multi-version analysis results\n" + + " \n" + + " \n" + + " Merge analysis results from disjoint components\n" + + " \n" + + " \n" + + " Combine analysis results from different versions of software to produce multi-version analysis results\n" + + " \n" + + "\n" + + " \n" + + " Disassemble a class file\n" + + " \n" + + " \n" + + " List analysis errors stored in results file\n" + + " \n" + + "\n" + + " \n" + + " \n" + + " (cloud disabled)\n" + + "
Bug reviews are disabled when using this plugin.
\n" + + "
\n" + + " \n" + + " Suppress multithreaded correctness issues\n" + + "
Suppress all multithreaded correctness issues
\n" + + "
\n" + + " \n" + + " Suppress internationalization issues\n" + + "
Suppress all internationalization issues
\n" + + "
\n" + + " \n" + + " Suppress internationalization issues in all but selected packages\n" + + "
Suppress all internationalization issues except those specified in the i18n.properties resource
\n" + + "
\n" + + " \n" + + " Suppress all issues with rank higher than 14\n" + + "
Suppress all issues with rank higher than 14
\n" + + "
\n" + + " \n" + + " Suppress warnings about vulnerabilities to malicious code\n" + + "
Suppress warnings about vulnerabilities to malicious code
\n" + + "
\n" + + " \n" + + " \n" + + " Correctness\n" + + " C\n" + + "
Probable bug - an apparent coding mistake\n" + + " resulting in code that was probably not what the\n" + + " developer intended. We strive for a low false positive rate.
\n" + + "
\n" + + " \n" + + " Bogus random noise\n" + + " N\n" + + "
Bogus random noise: intended to be useful\n" + + " as a control in data mining experiments, not in finding actual bugs in software\n" + + "
\n" + + "
\n" + + " \n" + + " Security\n" + + " S\n" + + "
A use of untrusted input in a way that could create a remotely exploitable security vulnerability.\n" + + "
\n" + + "
\n" + + " \n" + + " Bad practice\n" + + " B\n" + + "
Violations of recommended and essential\n" + + " coding practice. Examples include hash code and equals\n" + + " problems, cloneable idiom, dropped exceptions,\n" + + " Serializable problems, and misuse of finalize.\n" + + " We strive to make this analysis accurate,\n" + + " although some groups may\n" + + " not care about some of the bad practices.
\n" + + "
\n" + + " \n" + + " Dodgy code\n" + + " D\n" + + "
code that is confusing, anomalous, or\n" + + " written in a way that leads itself to errors.\n" + + " Examples include dead local stores, switch fall through,\n" + + " unconfirmed casts, and redundant null check of value\n" + + " known to be null.\n" + + " More false positives accepted.\n" + + " In previous versions of FindBugs, this category was known as Style.\n" + + "
\n" + + "
\n" + + " \n" + + " Performance\n" + + " P\n" + + "
code that is not necessarily incorrect but may be inefficient
\n" + + "
\n" + + " \n" + + " Malicious code vulnerability\n" + + " V\n" + + "
code that is vulnerable to attacks from untrusted code
\n" + + "
\n" + + " \n" + + " Multithreaded correctness\n" + + " M\n" + + "
code flaws having to do with threads, locks, and volatiles
\n" + + "
\n" + + " \n" + + " Internationalization\n" + + " I\n" + + "
code flaws having to do with internationalization and locale
\n" + + " \n" + + "
\n" + + " \n" + + " Experimental\n" + + " X\n" + + "
Experimental and not fully vetted bug patterns
\n" + + " \n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " Finds constants which roughly (but not precisely) equal to known values like Math.PI.\n" + + "

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + " Reliance on default encoding\n" + + " Found reliance on default encoding in {1}: {2}\n" + + "
\n" + + " Found a call to a method which will perform a byte to String (or String to byte) conversion, and will assume that the default platform encoding is suitable. This will cause the application behaviour to vary between platforms. Use an alternative API and specify a charset name or Charset object explicitly.

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " Nullcheck of value previously dereferenced\n" + + " Nullcheck of {2.givenClass} at {4.lineNumber} of value previously dereferenced in {1}\n" + + "
\n" + + " A value is checked here to see whether it is null, but this value can't\n" + + "be null because it was previously dereferenced and if it were null a null pointer\n" + + "exception would have occurred at the earlier dereference.\n" + + "Essentially, this code and the previous dereference\n" + + "disagree as to whether this value is allowed to be null. Either the check is redundant\n" + + "or the previous dereference is erroneous.

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " Redundant nullcheck of value known to be null\n" + + " Redundant nullcheck of {2} which is known to be null in {1}\n" + + "
\n" + + " This method contains a redundant check of a known null value against\n" + + "the constant null.

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " Redundant nullcheck of value known to be non-null\n" + + " Redundant nullcheck of {2}, which is known to be non-null in {1}\n" + + "
\n" + + " This method contains a redundant check of a known non-null value against\n" + + "the constant null.

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " Redundant comparison of two null values\n" + + " Redundant comparison of two null values in {1}\n" + + "
\n" + + " This method contains a redundant comparison of two references known to\n" + + "both be definitely null.

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " Redundant comparison of non-null value to null\n" + + " Redundant comparison of non-null value to null in {1}\n" + + "
\n" + + " This method contains a reference known to be non-null with another reference\n" + + "known to be null.

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + " Redundant comparison to null of previously checked value\n" + + " Redundant comparison to null of previously checked {2} in {1}\n" + + "
\n" + + " This method contains a redundant comparison of a reference value\n" + + "to null. Two types of redundant comparison are reported:\n" + + "

\n" + + "
    \n" + + "
  • Both values compared are definitely null
  • \n" + + "
  • One value is definitely null and the other is definitely not null
  • \n" + + "
\n" + + "\n" + + "

This particular warning generally indicates that a\n" + + "value known not to be null was checked against null.\n" + + "While the check is not necessary, it may simply be a case\n" + + "of defensive programming.

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " An increment to a volatile field isn't atomic\n" + + " Increment of volatile field {2} in {1}\n" + + "
\n" + + "This code increments a volatile field. Increments of volatile fields aren't\n" + + "atomic. If more than one thread is incrementing the field at the same time,\n" + + "increments could be lost.\n" + + "

\n" + + "]]>\n" + + "
\n" + + "
\n" + + " \n" + + " Method invokes inefficient Number constructor; use static valueOf instead\n" + + " {1} invokes inefficient {2} constructor; use {3} instead\n" + + "
\n" + + " \n" + + " Using new Integer(int) is guaranteed to always result in a new object whereas\n" + + " Integer.valueOf(int) allows caching of values to be done by the compiler, class library, or JVM.\n" + + " Using of cached values avoids object allocation and the code will be faster.\n" + + "

\n" + + "

\n" + + " Values between -128 and 127 are guaranteed to have corresponding cached instances\n" + + " and using valueOf is approximately 3.5 times faster than using constructor.\n" + + " For values outside the constant range the performance of both styles is the same.\n" + + "

\n" + + "

\n" + + " Unless the class must be compatible with JVMs predating Java 1.5,\n" + + " use either autoboxing or the valueOf() method when creating instances of\n" + + " Long, Integer, Short, Character, and Byte.\n" + + "

\n" + + " ]]>\n" + + "
\n" + + "
\n" + + " \n" + + " Format string problem\n" + + " Analysis skipped\n" + + " Infinite Loop\n" + + " Use of volatile\n" + + " Unsafe inheritance\n" + + " Use of floating point precision\n" + + " Testing prototype and incomplete bug pattern\n" + + " Dubious catching of IllegalMonitorStateException\n" + + " Bad implementation of cloneable idiom\n" + + " Covariant array assignment\n" + + " Possible atomicity violation\n" + + " Incorrect use of finalizers\n" + + " Checking String equality using == or !=\n" + + " Synchronization on updated field (Mutable Lock)\n" + + " Unsynchronized get method, synchronized set method\n" + + " Input/Output problem\n" + + " Initialization circularity\n" + + " Suspicious static initializer\n" + + " Mutable servlet field\n" + + " Inconsistent synchronization\n" + + " Problems with implementation of equals()\n" + + " Problems with implementation of compareTo()\n" + + " Equal objects must have equal hashcodes\n" + + " API misuse\n" + + " Dubious method used\n" + + " Questionable Boxing of primitive value\n" + + " Uninitialized read of field in constructor\n" + + " Method ignores results of InputStream.read()\n" + + " Naked notify\n" + + " Unconditional wait\n" + + " Method spins on field\n" + + " Double check pattern\n" + + " Wait not in loop\n" + + " Using notify() rather than notifyAll()\n" + + " Dropped or ignored exception\n" + + " Method invokes run()\n" + + " Incorrect definition of Iterator\n" + + " Serializable class with no Version ID\n" + + " Incorrect definition of Serializable class\n" + + " Class's writeObject() method is synchronized but nothing else is\n" + + " Class's readObject() method is synchronized\n" + + " Constructor invokes Thread.start()\n" + + " Mutable static field\n" + + " Mutable enum field\n" + + " Method returning array may expose internal representation\n" + + " Confusing method name\n" + + " Unread field should be static\n" + + " Unused field\n" + + " Unread field\n" + + " Unwritten field\n" + + " Inner class could be made static\n" + + " Wait with two locks held\n" + + " Range checks\n" + + " Bad use of return value from method\n" + + " Logger problem\n" + + " Ambiguous invocation\n" + + " Huge String constants\n" + + " HTTP Response splitting vulnerability\n" + + " Path traversal\n" + + " Cross site scripting vulnerability\n" + + " Null pointer dereference\n" + + " Bogus random warning\n" + + " Repeated conditional test\n" + + " Stream not closed on all paths\n" + + " Prefer zero length arrays to null to indicate no results\n" + + " Useless control flow\n" + + " Redundant comparison to null\n" + + " Lock not released on all paths\n" + + " Questionable use of reference equality rather than calling equals\n" + + " Comparing incompatible types for equality\n" + + " Mismatched wait() or notify()\n" + + " Useless self-operation\n" + + " Suspicious integer expression\n" + + " Suspicious bitwise logical expression\n" + + " Unsynchronized Lazy Initialization\n" + + " Synchronization on java.util.concurrent objects\n" + + " Private method is never called\n" + + " Uncallable method of anonymous class\n" + + " Storing reference to mutable object\n" + + " Suspicious use of non-short-circuit boolean operator\n" + + " Database resource not closed on all paths\n" + + " String concatenation in loop using + operator\n" + + " Inefficient code which can be moved outside of the loop\n" + + " Inefficient use of String.indexOf(String) or String.lastIndexOf(String)\n" + + " Inefficient use of collection.toArray(new Foo[0])\n" + + " Swing coding rules\n" + + " Improperly implemented JUnit TestCase\n" + + " Badly Overridden Adapter\n" + + " Switch case falls through\n" + + " Superfluous instanceof\n" + + " Bad Applet Constructor\n" + + " Use Object Equals\n" + + " Suspicious Thread Interrupted\n" + + " Dead local store\n" + + " Ignored parameter\n" + + " Masked Field\n" + + " Inefficient Map Iterator\n" + + " Instantiated Static Class\n" + + " RuntimeException capture\n" + + " Test for floating point equality\n" + + " Unnecessary Math on constants\n" + + " Useless code\n" + + " Rough value of known constant\n" + + " Circular Dependencies\n" + + " Redundant Interfaces\n" + + " Multithreaded Instance Access\n" + + " Public Semaphores\n" + + " Bad shift\n" + + " Casting from integer values\n" + + " Regular expressions\n" + + " Potential SQL Problem\n" + + " Possible locking on wrong object\n" + + " Empty Synchronized blocks\n" + + " Questionable for loops\n" + + " Var arg problems\n" + + " Bad casts of object references\n" + + " Questionable integer math\n" + + " Misuse of static fields\n" + + " Violation of net.jcip annotations\n" + + " Useless/non-informative string generated\n" + + " Dubious method invocation\n" + + " Warning inspired by Josh Bloch's and Neal Gafter's Programming Puzzlers\n" + + " Sleep with lock held\n" + + " J2EE error\n" + + " Duplicate Branches\n" + + " Inefficient Member Access\n" + + " XML Factory Bypass\n" + + " Useless Subclass Method\n" + + " Confused Inheritance\n" + + " Questionable Boolean Assignment\n" + + " Version compatibility issue\n" + + " Use doPrivileged\n" + + " Suspicious calls to generic collection methods\n" + + " Static use of type Calendar or DateFormat\n" + + " Inconsistent use of type qualifier annotations\n" + + " Unsatisfied obligation to clean up stream or resource\n" + + " FindBugs did not produce the expected warnings on a method\n" + + " Unintended contention or possible deadlock due to locking on shared objects\n" + + "
\n"; + + public static String getData() { return DATA; } +}