<?xml version="1.0"?>

<ruleset name="String and StringBuffer"
    xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
  <description>
These rules deal with different issues that can arise with manipulation of the String, StringBuffer, or StringBuilder instances.
  </description>

    <rule name="AvoidDuplicateLiterals"
    	  since="1.0"
        message="The String literal {0} appears {1} times in this file; the first occurrence is on line {2}"
        class="net.sourceforge.pmd.lang.java.rule.strings.AvoidDuplicateLiteralsRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#AvoidDuplicateLiterals">
    <description>
Code containing duplicate String literals can usually be improved by declaring the String as a constant field.
    </description>
        <priority>3</priority>
    <example>
<![CDATA[
private void bar() {
     buz("Howdy");
     buz("Howdy");
     buz("Howdy");
     buz("Howdy");
 }
 private void buz(String x) {}
]]>
    </example>
  </rule>

    <rule name="StringInstantiation"
    	  since="1.0"
        message="Avoid instantiating String objects; this is usually unnecessary."
        class="net.sourceforge.pmd.lang.java.rule.strings.StringInstantiationRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#StringInstantiation">
    <description>
Avoid instantiating String objects; this is usually unnecessary since they are immutable and can be safely shared.
    </description>
       <priority>2</priority>
    <example>
<![CDATA[
private String bar = new String("bar"); // just do a String bar = "bar";
]]>
    </example>
    </rule>

   <rule name="StringToString"
   	  since="1.0"
        message="Avoid calling toString() on String objects; this is unnecessary."
        class="net.sourceforge.pmd.lang.java.rule.strings.StringToStringRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#StringToString">
    <description>
Avoid calling toString() on objects already known to be string instances; this is unnecessary.
    </description>
       <priority>3</priority>
    <example>
<![CDATA[
private String baz() {
    String bar = "howdy";
    return bar.toString();
}
]]>
    </example>
    </rule>

    <rule name="InefficientStringBuffering"
   	  since="3.4"
        message="Avoid concatenating nonliterals in a StringBuffer/StringBuilder constructor or append()."
        class="net.sourceforge.pmd.lang.java.rule.strings.InefficientStringBufferingRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#InefficientStringBuffering">
    <description>
Avoid concatenating non-literals in a StringBuffer constructor or append() since intermediate buffers will
need to be be created and destroyed by the JVM.
    </description>
       <priority>3</priority>
    <example>
<![CDATA[
    // Avoid this, two buffers are actually being created here
StringBuffer sb = new StringBuffer("tmp = "+System.getProperty("java.io.tmpdir"));
    
    // do this instead
StringBuffer sb = new StringBuffer("tmp = ");
sb.append(System.getProperty("java.io.tmpdir"));
]]>
    </example>
    </rule>

    <rule name="UnnecessaryCaseChange"
          since="3.3"
          message="Using equalsIgnoreCase() is cleaner than using toUpperCase/toLowerCase().equals()."
           class="net.sourceforge.pmd.lang.java.rule.strings.UnnecessaryCaseChangeRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#UnnecessaryCaseChange">
       <description>
Using equalsIgnoreCase() is faster than using toUpperCase/toLowerCase().equals()
       </description>
       <priority>3</priority>
       <example>
       <![CDATA[
boolean answer1 = buz.toUpperCase().equals("baz");	 		// should be buz.equalsIgnoreCase("baz")
    
boolean answer2 = buz.toUpperCase().equalsIgnoreCase("baz");	 // another unnecessary toUpperCase()
 ]]>
       </example>
     </rule>

    <rule name="UseStringBufferLength"
          since="3.4"
          message="This is an inefficient use of StringBuffer.toString; call StringBuffer.length instead."
          class="net.sourceforge.pmd.lang.java.rule.strings.UseStringBufferLengthRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#UseStringBufferLength">
      <description>
Use StringBuffer.length() to determine StringBuffer length rather than using StringBuffer.toString().equals("")
or StringBuffer.toString().length() == ...
      </description>
      <priority>3</priority>
      <example>
  <![CDATA[
StringBuffer sb = new StringBuffer();
    
if (sb.toString().equals("")) {}	    // inefficient 
    
if (sb.length() == 0) {}	    		// preferred
  ]]>
      </example>
    </rule>


    <rule name="AppendCharacterWithChar"
        since="3.5"
        message="Avoid appending characters as strings in StringBuffer.append."
        class="net.sourceforge.pmd.lang.java.rule.strings.AppendCharacterWithCharRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#AppendCharacterWithChar">
    <description>
Avoid concatenating characters as strings in StringBuffer/StringBuilder.append methods.
    </description>
       <priority>3</priority>
    <example>
<![CDATA[
StringBuffer sb = new StringBuffer();
sb.append("a");		 // avoid this

StringBuffer sb = new StringBuffer();
sb.append('a');		// use this instead
]]>
    </example>
    </rule>

<rule name="ConsecutiveAppendsShouldReuse"
        language="java"
        since="5.1"
        message="StringBuffer (or StringBuilder).append is called consecutively without reusing the target variable."
        class="net.sourceforge.pmd.lang.java.rule.strings.ConsecutiveAppendsShouldReuseRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#ConsecutiveAppendsShouldReuse">
    <description>
Consecutively calls to StringBuffer/StringBuilder .append should reuse the target object. This can improve the performance.
    </description>
    <priority>3</priority>
    <example>
<![CDATA[
String foo = " ";

StringBuffer buf = new StringBuffer();
buf.append("Hello"); // poor
buf.append(foo);
buf.append("World");

StringBuffer buf = new StringBuffer();
buf.append("Hello").append(foo).append("World"); // good
]]>
    </example>
  </rule>

        <rule name="ConsecutiveLiteralAppends"
        since="3.5"
        message="StringBuffer (or StringBuilder).append is called {0} consecutive times with literal Strings. Use a single append with a single combined String."
        class="net.sourceforge.pmd.lang.java.rule.strings.ConsecutiveLiteralAppendsRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#ConsecutiveLiteralAppends">
    <description>
Consecutively calling StringBuffer/StringBuilder.append with String literals
    </description>
        <priority>3</priority>
    <example>
<![CDATA[
StringBuffer buf = new StringBuffer();
buf.append("Hello").append(" ").append("World"); // poor
buf.append("Hello World");        				 // good
]]>
    </example>
  </rule>


    <rule name="UseIndexOfChar"
        since="3.5"
        message="String.indexOf(char) is faster than String.indexOf(String)."
        class="net.sourceforge.pmd.lang.java.rule.strings.UseIndexOfCharRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#UseIndexOfChar">
    <description>
Use String.indexOf(char) when checking for the index of a single character; it executes faster.
    </description>
       <priority>3</priority>
    <example>
<![CDATA[
String s = "hello world";
  // avoid this
if (s.indexOf("d") {}
  // instead do this
if (s.indexOf('d') {}
]]>
    </example>
    </rule>

    <rule name="InefficientEmptyStringCheck"
        since="3.6"
        message="String.trim().length()==0 is an inefficient way to validate an empty String."
        class="net.sourceforge.pmd.lang.java.rule.strings.InefficientEmptyStringCheckRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#InefficientEmptyStringCheck">
    <description>
String.trim().length() is an inefficient way to check if a String is really empty, as it
creates a new String object just to check its size. Consider creating a static function that
loops through a string, checking Character.isWhitespace() on each character and returning
false if a non-whitespace character is found.
    </description>
       <priority>3</priority>
    <example>
<![CDATA[
public void bar(String string) {
	if (string != null && string.trim().size() > 0) {
		doSomething();
	}
}
]]>
    </example>
    </rule>

    <rule name="InsufficientStringBufferDeclaration"
        since="3.6"
        message="StringBuffer constructor is initialized with size {0}, but has at least {1} characters appended."
        class="net.sourceforge.pmd.lang.java.rule.strings.InsufficientStringBufferDeclarationRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#InsufficientStringBufferDeclaration">
    <description>
Failing to pre-size a StringBuffer or StringBuilder properly could cause it to re-size many times
during runtime. This rule attempts to determine the total number the characters that are actually 
passed into StringBuffer.append(), but represents a best guess "worst case" scenario. An empty
StringBuffer/StringBuilder constructor initializes the object to 16 characters. This default
is assumed if the length of the constructor can not be determined.
    </description>
       <priority>3</priority>
    <example>
<![CDATA[
StringBuffer bad = new StringBuffer();
bad.append("This is a long string that will exceed the default 16 characters");
        
StringBuffer good = new StringBuffer(41);
good.append("This is a long string, which is pre-sized");
]]>
    </example>
    </rule>

    <rule name="UselessStringValueOf"
          since="3.8"
          message="No need to call String.valueOf to append to a string."
          class="net.sourceforge.pmd.lang.java.rule.strings.UselessStringValueOfRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#UselessStringValueOf">
      <description>
No need to call String.valueOf to append to a string; just use the valueOf() argument directly.
      </description>
        <priority>3</priority>
      <example>
<![CDATA[
public String convert(int i) {
	String s;
	s = "a" + String.valueOf(i);	// not required
	s = "a" + i; 					// preferred approach
	return s;
}
]]>
          </example>
    </rule>


<rule   name="StringBufferInstantiationWithChar"
   		language="java"
        since="3.9"
        message="Do not instantiate a StringBuffer or StringBuilder with a char"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#StringBufferInstantiationWithChar">
    <description>
Individual character values provided as initialization arguments will be converted into integers.
This can lead to internal buffer sizes that are larger than expected. Some examples:

new StringBuffer() 		//  16
new StringBuffer(6)		//  6
new StringBuffer("hello world")  // 11 + 16 = 27
new StringBuffer('A')	//  chr(A) = 65
new StringBuffer("A")   //  1 + 16 = 17 

new StringBuilder() 		//  16
new StringBuilder(6)		//  6
new StringBuilder("hello world")  // 11 + 16 = 27
new StringBuilder('C')	 //  chr(C) = 67
new StringBuilder("A")   //  1 + 16 = 17
    </description>
    <priority>4</priority>
    <properties>
        <property name="xpath">
            <value>
<![CDATA[
//AllocationExpression/ClassOrInterfaceType
[@Image='StringBuffer' or @Image='StringBuilder']
/../Arguments/ArgumentList/Expression/PrimaryExpression
/PrimaryPrefix/
Literal
  [starts-with(@Image, "'")]
  [ends-with(@Image, "'")]
]]>
            </value>
        </property>
    </properties>
    <example>
<![CDATA[
	// misleading instantiation, these buffers
	// are actually sized to 99 characters long
StringBuffer  sb1 = new StringBuffer('c');   
StringBuilder sb2 = new StringBuilder('c');
  
// in these forms, just single characters are allocated
StringBuffer  sb3 = new StringBuffer("c");
StringBuilder sb4 = new StringBuilder("c");
]]>
    </example>
    </rule>

<rule   name="UseEqualsToCompareStrings"
   		language="java"
        since="4.1"
        message="Use equals() to compare strings instead of ''=='' or ''!=''"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#UseEqualsToCompareStrings">
    <description>
Using '==' or '!=' to compare strings only works if intern version is used on both sides.
Use the equals() method instead.
    </description>
    <priority>3</priority>
    <properties>
        <property name="xpath">
            <value>
<![CDATA[
//EqualityExpression/PrimaryExpression
[(PrimaryPrefix/Literal
   [starts-with(@Image, '"')]
   [ends-with(@Image, '"')]
and count(PrimarySuffix) = 0)]
]]>
            </value>
        </property>
    </properties>
    <example>
<![CDATA[
public boolean test(String s) {
    if (s == "one") return true; 		// unreliable
    if ("two".equals(s)) return true; 	// better
    return false;
}
]]>
    </example>
    </rule>

	<rule   name="AvoidStringBufferField"
   		language="java"
	      since="4.2"
        	message="StringBuffers can grow quite a lot, and so may become a source of memory leak (if the owning class has a long life time)."
        	class="net.sourceforge.pmd.lang.rule.XPathRule"
        	externalInfoUrl="${pmd.website.baseurl}/rules/java/strings.html#AvoidStringBufferField">
    <description>
		<![CDATA[
StringBuffers/StringBuilders can grow considerably, and so may become a source of memory leaks
if held within objects with long lifetimes.
		]]>
    </description>
    <priority>3</priority>
    <properties>
        <property name="xpath">
            <value>
<![CDATA[
//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[@Image = 'StringBuffer' or @Image = 'StringBuilder']
]]>
			</value>
		</property>
		</properties>
    	<example>
<![CDATA[
public class Foo {
	private StringBuffer buffer;	// potential memory leak as an instance variable;
}
]]>
		</example>
	</rule>

</ruleset>