View | Details | Raw Unified | Return to bug 185682 | Differences between
and this patch

Collapse All | Expand All

(-)compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java (-5 / +58 lines)
Lines 7-13 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 292478 - Report potentially null across variable assignment
10
 *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 292478 - Report potentially null across variable assignment,
11
 *     											    Contribution for bug 185682 - Increment/decrement operators mark local variables as read
11
 *******************************************************************************/
12
 *******************************************************************************/
12
package org.eclipse.jdt.internal.compiler.ast;
13
package org.eclipse.jdt.internal.compiler.ast;
13
14
Lines 78-87 Link Here
78
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
79
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
79
					// we could improve error msg here telling "cannot use compound assignment on final local variable"
80
					// we could improve error msg here telling "cannot use compound assignment on final local variable"
80
				}
81
				}
81
				if (isReachable) {
82
				if (localBinding.useFlag != LocalVariableBinding.USED) {
82
					localBinding.useFlag = LocalVariableBinding.USED;
83
					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
83
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
84
					// access from compound assignment does not prevent "unused" warning, unless unboxing is involved:
84
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
85
					if (isReachable && (this.implicitConversion & TypeIds.UNBOXING) != 0) {
86
						localBinding.useFlag = LocalVariableBinding.USED;
87
					} else {
88
						localBinding.useFlag = LocalVariableBinding.FAKE_USED;
89
					}
85
				}
90
				}
86
		}
91
		}
87
	}
92
	}
Lines 462-467 Link Here
462
 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
467
 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
463
 */
468
 */
464
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
469
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
470
	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
471
	if (!valueRequired && ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL)) {
472
		LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
473
		if (localBinding.useFlag == LocalVariableBinding.FAKE_USED
474
				&& (localBinding.declaration != null) // unused (and non secret) local
475
				&& ((localBinding.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0)) {  // declaration is reachable
476
			if (localBinding.declaration instanceof Argument) {
477
				// check compiler options to report against unused arguments
478
				if (currentScope instanceof MethodScope) {
479
					MethodBinding method = ((MethodDeclaration)currentScope.referenceContext()).binding;
480
					if (!(method.isImplementing() && !currentScope.compilerOptions().reportUnusedParameterWhenImplementingAbstract)
481
							&& !(method.isOverriding() && !method.isImplementing() && !currentScope.compilerOptions().reportUnusedParameterWhenOverridingConcrete)
482
							&& !method.isMain()) {
483
						// report the case of an argument that is unread except for postIncrement expressions
484
						currentScope.problemReporter().unusedArgument(localBinding.declaration);
485
					}
486
				}
487
			} else {
488
				// report the case of a local variable that is unread except for this compound assignment
489
				currentScope.problemReporter().unusedLocalVariable(localBinding.declaration);
490
			}
491
			localBinding.useFlag = LocalVariableBinding.USED; // don't report again
492
		}
493
	}
465
	this.generateCompoundAssignment(
494
	this.generateCompoundAssignment(
466
		currentScope,
495
		currentScope,
467
		codeStream,
496
		codeStream,
Lines 662-667 Link Here
662
			return;
691
			return;
663
		case Binding.LOCAL : // assigning to a local variable
692
		case Binding.LOCAL : // assigning to a local variable
664
			LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
693
			LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
694
			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
695
			if (!valueRequired) {
696
				if (localBinding.useFlag == LocalVariableBinding.FAKE_USED
697
						&& (localBinding.declaration != null) // unused (and non secret) local
698
						&& ((localBinding.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0)) {  // declaration is reachable
699
					if (localBinding.declaration instanceof Argument) {
700
						// check compiler options to report against unused arguments
701
						if (currentScope instanceof MethodScope) {
702
							MethodBinding method = ((MethodDeclaration)currentScope.referenceContext()).binding;
703
							if (!(method.isImplementing() && !currentScope.compilerOptions().reportUnusedParameterWhenImplementingAbstract)
704
									&& !(method.isOverriding() && !method.isImplementing() && !currentScope.compilerOptions().reportUnusedParameterWhenOverridingConcrete)
705
									&& !method.isMain()) {
706
								// report the case of an argument that is unread except for postIncrement expressions
707
								currentScope.problemReporter().unusedArgument(localBinding.declaration);
708
							}
709
						}
710
					} else {
711
						// report the case of a local variable that is unread except for postIncrement expressions
712
						currentScope.problemReporter().unusedLocalVariable(localBinding.declaration);
713
					}
714
					localBinding.useFlag = LocalVariableBinding.USED; // don't report again
715
				}
716
			}
717
665
			// using incr bytecode if possible
718
			// using incr bytecode if possible
666
			if (localBinding.type == TypeBinding.INT) {
719
			if (localBinding.type == TypeBinding.INT) {
667
				if (valueRequired) {
720
				if (valueRequired) {
(-)src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java (-1 / +249 lines)
Lines 7-25 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 185682 - Increment/decrement operators mark local variables as read
10
 *******************************************************************************/
11
 *******************************************************************************/
11
package org.eclipse.jdt.core.tests.compiler.regression;
12
package org.eclipse.jdt.core.tests.compiler.regression;
12
13
13
import java.util.HashMap;
14
import java.util.HashMap;
14
import java.util.Map;
15
import java.util.Map;
15
16
17
import junit.framework.Test;
18
16
import org.eclipse.jdt.core.JavaCore;
19
import org.eclipse.jdt.core.JavaCore;
17
import org.eclipse.jdt.core.compiler.CategorizedProblem;
20
import org.eclipse.jdt.core.compiler.CategorizedProblem;
18
import org.eclipse.jdt.internal.compiler.CompilationResult;
21
import org.eclipse.jdt.internal.compiler.CompilationResult;
19
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
22
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
20
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
23
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
21
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
24
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
22
import junit.framework.Test;
23
25
24
/* Collects potential programming problems tests that are not segregated in a
26
/* Collects potential programming problems tests that are not segregated in a
25
 * dedicated test class (aka NullReferenceTest). */
27
 * dedicated test class (aka NullReferenceTest). */
Lines 1683-1686 Link Here
1683
		"The assignment to variable nvx has no effect\n" + 
1685
		"The assignment to variable nvx has no effect\n" + 
1684
		"----------\n");
1686
		"----------\n");
1685
}
1687
}
1688
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
1689
public void test0046() {
1690
	if (this.complianceLevel < ClassFileConstants.JDK1_5)
1691
		return;
1692
	Map customOptions = getCompilerOptions();
1693
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING);
1694
	this.runNegativeTest(
1695
			new String[] {
1696
				"X.java",
1697
				"class X {\n" + 
1698
				"    int foo() {\n" + 
1699
				"        int i=1;\n" + 
1700
				"        boolean b=false;\n" + 
1701
				"        b|=true;\n" + 			// not a relevant usage
1702
				"        int k = 2;\n" + 
1703
				"        --k;\n" + 				// not a relevant usage
1704
				"        k+=3;\n" + 			// not a relevant usage
1705
				"        Integer j = 3;\n" + 
1706
				"        j++;\n" + 				// relevant because unboxing is involved
1707
				"        return i++;\n" + 		// value after increment is used
1708
				"    }\n" + 
1709
				"}"
1710
			},
1711
			"----------\n" + 
1712
			"1. WARNING in X.java (at line 4)\n" + 
1713
			"	boolean b=false;\n" + 
1714
			"	        ^\n" + 
1715
			"The local variable b is never read\n" + 
1716
			"----------\n" + 
1717
			"2. WARNING in X.java (at line 6)\n" + 
1718
			"	int k = 2;\n" + 
1719
			"	    ^\n" + 
1720
			"The local variable k is never read\n" + 
1721
			"----------\n",
1722
			null/*classLibraries*/,
1723
			true/*shouldFlushOutputDirectory*/,
1724
			customOptions);
1725
}
1726
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
1727
public void test0047() {
1728
	if (this.complianceLevel < ClassFileConstants.JDK1_5)
1729
		return;
1730
	Map customOptions = getCompilerOptions();
1731
	customOptions.put(CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.WARNING);
1732
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING);
1733
	this.runNegativeTest(
1734
			new String[] {
1735
				"X.java",
1736
				"class X {\n" + 
1737
				"    void foo(int param1, int param2, Integer param3) {\n" + 
1738
				"        boolean b=false;\n" + 
1739
				"        b|=true;\n" + 			// not a relevant usage
1740
				"        param1++;\n" + 		// not a relevant usage
1741
				"        param2 += 1;\n" + 				// not a relevant usage
1742
				"        param3++;\n" + 			// relevant because unboxing is involved
1743
				"    }\n" + 
1744
				"}"
1745
			},
1746
			"----------\n" + 
1747
			"1. WARNING in X.java (at line 2)\n" + 
1748
			"	void foo(int param1, int param2, Integer param3) {\n" + 
1749
			"	             ^^^^^^\n" + 
1750
			"The parameter param1 is never read\n" + 
1751
			"----------\n" + 
1752
			"2. WARNING in X.java (at line 2)\n" + 
1753
			"	void foo(int param1, int param2, Integer param3) {\n" + 
1754
			"	                         ^^^^^^\n" + 
1755
			"The parameter param2 is never read\n" + 
1756
			"----------\n" + 
1757
			"3. WARNING in X.java (at line 3)\n" + 
1758
			"	boolean b=false;\n" + 
1759
			"	        ^\n" + 
1760
			"The local variable b is never read\n" + 
1761
			"----------\n",
1762
			null/*classLibraries*/,
1763
			true/*shouldFlushOutputDirectory*/,
1764
			customOptions);
1765
}
1766
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
1767
// To verify that unused parameter warning is not shown for an implementing method's parameter when
1768
// CompilerOptions.OPTION_ReportUnusedParameterWhenImplementingAbstract is disabled
1769
public void test0048() {
1770
	if (this.complianceLevel < ClassFileConstants.JDK1_5)
1771
		return;
1772
	Map customOptions = getCompilerOptions();
1773
	customOptions.put(CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.WARNING);
1774
	customOptions.put(CompilerOptions.OPTION_ReportUnusedParameterWhenImplementingAbstract, CompilerOptions.DISABLED);
1775
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING);
1776
	this.runNegativeTest(
1777
			new String[] {
1778
				"X.java",
1779
				"public class X extends A implements Y{\n" + 
1780
				"   public void foo(int param1, int param2, Integer param3) {\n" + // implementing method, so dont warn
1781
				"        boolean b=false;\n" + 
1782
				"        b|=true;\n" + 			// not a relevant usage
1783
				"        param1++;\n" + 		// not a relevant usage
1784
				"        param2 += 1;\n" + 				// not a relevant usage
1785
				"        param3++;\n" + 			// relevant because unboxing is involved
1786
				"    }\n" + 
1787
				"   public void foo(int param1, int param2) {\n" + // warn
1788
				"        boolean b=false;\n" + 
1789
				"        b|=true;\n" + 			// not a relevant usage
1790
				"        param1++;\n" + 		// not a relevant usage
1791
				"        param2 += 1;\n" + 				// not a relevant usage
1792
				"    }\n" +
1793
				"   public void bar(int param1, int param2, Integer param3) {\n" + // implementing method, so dont warn
1794
				"        param1++;\n" + 		// not a relevant usage
1795
				"        param2 += 1;\n" + 				// not a relevant usage
1796
				"        param3++;\n" + 			// relevant because unboxing is involved
1797
				"    }\n" +
1798
				"}\n" +
1799
				"interface Y{\n" +
1800
				"	public void foo(int param1, int param2, Integer param3);" +
1801
				"}\n" +
1802
				"abstract class A{\n" +
1803
				"	public abstract void bar(int param1, int param2, Integer param3);" +
1804
				"}\n"
1805
			},
1806
			"----------\n" + 
1807
			"1. WARNING in X.java (at line 3)\n" + 
1808
			"	boolean b=false;\n" + 
1809
			"	        ^\n" + 
1810
			"The local variable b is never read\n" + 
1811
			"----------\n" + 
1812
			"2. WARNING in X.java (at line 9)\n" + 
1813
			"	public void foo(int param1, int param2) {\n" + 
1814
			"	                    ^^^^^^\n" + 
1815
			"The parameter param1 is never read\n" + 
1816
			"----------\n" + 
1817
			"3. WARNING in X.java (at line 9)\n" + 
1818
			"	public void foo(int param1, int param2) {\n" + 
1819
			"	                                ^^^^^^\n" + 
1820
			"The parameter param2 is never read\n" + 
1821
			"----------\n" + 
1822
			"4. WARNING in X.java (at line 10)\n" + 
1823
			"	boolean b=false;\n" + 
1824
			"	        ^\n" + 
1825
			"The local variable b is never read\n" + 
1826
			"----------\n",
1827
			null/*classLibraries*/,
1828
			true/*shouldFlushOutputDirectory*/,
1829
			customOptions);
1830
}
1831
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
1832
// To verify that unused parameter warning is not shown for an overriding method's parameter when
1833
// CompilerOptions.OPTION_ReportUnusedParameterWhenOverridingConcrete is disabled
1834
public void test0049() {
1835
	if (this.complianceLevel < ClassFileConstants.JDK1_5)
1836
		return;
1837
	Map customOptions = getCompilerOptions();
1838
	customOptions.put(CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.WARNING);
1839
	customOptions.put(CompilerOptions.OPTION_ReportUnusedParameterWhenOverridingConcrete, CompilerOptions.DISABLED);
1840
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING);
1841
	this.runNegativeTest(
1842
			new String[] {
1843
				"X.java",
1844
				"public class X extends A {\n" + 
1845
				"   public void foo(int param1, int param2, Integer param3) {\n" + // overriding method, so dont warn
1846
				"        boolean b=false;\n" + 
1847
				"        b|=true;\n" + 			// not a relevant usage
1848
				"        param1++;\n" + 		// not a relevant usage
1849
				"        param2 += 1;\n" + 				// not a relevant usage
1850
				"        param3++;\n" + 			// relevant because unboxing is involved
1851
				"    }\n" + 
1852
				"   public void foo(int param1, Integer param3) {\n" + // overriding method, so dont warn
1853
				"        param1++;\n" + 		// not a relevant usage
1854
				"        param3++;\n" + 			// relevant because unboxing is involved
1855
				"    }\n" + 
1856
				"}\n" +
1857
				"class A{\n" +
1858
				"   public void foo(int param1, int param2, Integer param3) {\n" +
1859
				"        param1 -=1;\n" + 		// not a relevant usage
1860
				"        param2--;\n" + 				// not a relevant usage
1861
				"        param3--;\n" + 			// relevant because unboxing is involved
1862
				"    }\n" + 
1863
				"}\n"
1864
			},
1865
			"----------\n" + 
1866
			"1. WARNING in X.java (at line 3)\n" + 
1867
			"	boolean b=false;\n" + 
1868
			"	        ^\n" + 
1869
			"The local variable b is never read\n" + 
1870
			"----------\n" + 
1871
			"2. WARNING in X.java (at line 9)\n" + 
1872
			"	public void foo(int param1, Integer param3) {\n" + 
1873
			"	                    ^^^^^^\n" + 
1874
			"The parameter param1 is never read\n" + 
1875
			"----------\n" + 
1876
			"3. WARNING in X.java (at line 15)\n" + 
1877
			"	public void foo(int param1, int param2, Integer param3) {\n" + 
1878
			"	                    ^^^^^^\n" + 
1879
			"The parameter param1 is never read\n" + 
1880
			"----------\n" + 
1881
			"4. WARNING in X.java (at line 15)\n" + 
1882
			"	public void foo(int param1, int param2, Integer param3) {\n" + 
1883
			"	                                ^^^^^^\n" + 
1884
			"The parameter param2 is never read\n" + 
1885
			"----------\n",
1886
			null/*classLibraries*/,
1887
			true/*shouldFlushOutputDirectory*/,
1888
			customOptions);
1889
}
1890
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
1891
// To verify that unused local warning is not shown for locals declared in unreachable code
1892
public void test0050() {
1893
	if (this.complianceLevel < ClassFileConstants.JDK1_5)
1894
		return;
1895
	Map customOptions = getCompilerOptions();
1896
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING);
1897
	this.runNegativeTest(
1898
			new String[] {
1899
				"X.java",
1900
				"class X {\n" + 
1901
				"    int foo() {\n" + 
1902
				"        int i=1;\n" +
1903
				"		 if (false) {\n" + 
1904
				"        	boolean b=false;\n" + 
1905
				"        	b|=true;\n" +
1906
				"		 }\n" + 			// not a relevant usage
1907
				"        int k = 2;\n" + 
1908
				"        --k;\n" + 				// not a relevant usage
1909
				"        k+=3;\n" + 			// not a relevant usage
1910
				"        Integer j = 3;\n" + 
1911
				"        j++;\n" + 				// relevant because unboxing is involved
1912
				"        return i++;\n" + 		// value after increment is used
1913
				"    }\n" + 
1914
				"}"
1915
			},
1916
			"----------\n" + 
1917
			"1. WARNING in X.java (at line 4)\n" + 
1918
			"	if (false) {\n" + 
1919
			"        	boolean b=false;\n" + 
1920
			"        	b|=true;\n" + 
1921
			"		 }\n" + 
1922
			"	           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
1923
			"Dead code\n" + 
1924
			"----------\n" + 
1925
			"2. WARNING in X.java (at line 8)\n" + 
1926
			"	int k = 2;\n" + 
1927
			"	    ^\n" + 
1928
			"The local variable k is never read\n" + 
1929
			"----------\n",
1930
			null/*classLibraries*/,
1931
			true/*shouldFlushOutputDirectory*/,
1932
			customOptions);
1933
}
1686
}
1934
}

Return to bug 185682