View | Details | Raw Unified | Return to bug 160301
Collapse All | Expand All

(-)src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java (-2 / +244 lines)
Lines 7151-7158 Link Here
7151
	search(method, REFERENCES);
7151
	search(method, REFERENCES);
7152
	assertSearchResults(
7152
	assertSearchResults(
7153
		"src/other/Test.java void other.Test.testInterface(I) [test()] EXACT_MATCH SUPER INVOCATION\n" + 
7153
		"src/other/Test.java void other.Test.testInterface(I) [test()] EXACT_MATCH SUPER INVOCATION\n" + 
7154
		"src/other/Test.java void other.Test.testSuperInvocation(L1) [test()] EXACT_MATCH\n" + 
7154
		"src/other/Test.java void other.Test.testSuperInvocation(L1) [test()] EXACT_MATCH"
7155
		"src/other/Test.java void other.Test.testInvocation(L2) [test()] EXACT_MATCH"
7155
		// since bug 160301 fix, subclass overridden method calls are not reported
7156
		//"src/other/Test.java void other.Test.testInvocation(L2) [test()] EXACT_MATCH"
7157
	);
7158
}
7159
/**
7160
 * @bug 160301: [search] too many matches found for method references
7161
 * @test Ensure that correct number of method references are found
7162
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=160301"
7163
 */
7164
public void testBug160301() throws CoreException {
7165
	resultCollector.showRule = true;
7166
	workingCopies = new ICompilationUnit[1];
7167
	workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/Test.java",
7168
		"public class Test {\n" + 
7169
		"	class A {\n" + 
7170
		"		void foo() {}\n" + 
7171
		"		void bar() {\n" + 
7172
		"			foo();\n" + 
7173
		"		}\n" + 
7174
		"	}\n" + 
7175
		"	class B extends A {\n" + 
7176
		"		void foo() {}\n" + 
7177
		"		void bar() {\n" + 
7178
		"			foo();\n" + 
7179
		"		}\n" + 
7180
		"	}\n" + 
7181
		"	class C extends B {\n" + 
7182
		"		void method() {\n" + 
7183
		"			foo();\n" + 
7184
		"		}\n" + 
7185
		"	}\n" + 
7186
		"}"
7187
	);
7188
	IMethod method = workingCopies[0].getType("Test").getType("A").getMethod("foo", new String[0]);
7189
	search(method, REFERENCES);
7190
	assertSearchResults(
7191
		"src/Test.java void Test$A.bar() [foo()] EXACT_MATCH"
7192
	);
7193
}
7194
public void testBug160301b() throws CoreException {
7195
	resultCollector.showRule = true;
7196
	workingCopies = new ICompilationUnit[1];
7197
	workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/test/Test.java",
7198
		"package test;\n" + 
7199
		"public class Test {\n" + 
7200
		"	class A {\n" + 
7201
		"		void foo() {}\n" + 
7202
		"	}\n" + 
7203
		"	class B extends A {}\n" + 
7204
		"	class C extends B {\n" + 
7205
		"		void foo() {}\n" + 
7206
		"	}\n" + 
7207
		"	class D extends C {}\n" + 
7208
		"	void a() {\n" + 
7209
		"		new A().foo();\n" + 
7210
		"	}\n" + 
7211
		"	void b() {\n" + 
7212
		"		new B().foo();\n" + 
7213
		"	}\n" + 
7214
		"	void c() {\n" + 
7215
		"		new C().foo();\n" + 
7216
		"	}\n" + 
7217
		"	void d() {\n" + 
7218
		"		new D().foo();\n" + 
7219
		"	}\n" + 
7220
		"	\n" + 
7221
		"}"
7222
	);
7223
	IMethod method = workingCopies[0].getType("Test").getType("A").getMethod("foo", new String[0]);
7224
	search(method, REFERENCES);
7225
	assertSearchResults(
7226
		"src/test/Test.java void test.Test.a() [foo()] EXACT_MATCH\n" + 
7227
		"src/test/Test.java void test.Test.b() [foo()] EXACT_MATCH"
7228
	);
7229
}
7230
public void testBug160301_Interface() throws CoreException {
7231
	resultCollector.showRule = true;
7232
	workingCopies = new ICompilationUnit[1];
7233
	workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/Test.java",
7234
		"public class Test {\n" + 
7235
		"	interface I {\n" + 
7236
		"		void foo();\n" + 
7237
		"	}\n" + 
7238
		"	class A1 implements I {\n" + 
7239
		"		public void foo() {}\n" + 
7240
		"		void a1() {\n" + 
7241
		"			foo();\n" + 
7242
		"		}\n" + 
7243
		"	}\n" + 
7244
		"	class B1 extends A1 {\n" + 
7245
		"		void b1() {\n" + 
7246
		"			foo();\n" + 
7247
		"		}\n" + 
7248
		"	}\n" + 
7249
		"	class C1 extends B1 {\n" + 
7250
		"		public void foo() {}\n" + 
7251
		"		void c1() {\n" + 
7252
		"			foo();\n" + 
7253
		"		}\n" + 
7254
		"	}\n" + 
7255
		"	abstract class A2 implements I {\n" + 
7256
		"		void a2() {\n" + 
7257
		"			foo();\n" + 
7258
		"		}\n" + 
7259
		"	}\n" + 
7260
		"	class B2 extends A2 {\n" + 
7261
		"		public void foo() {}\n" + 
7262
		"		void b2() {\n" + 
7263
		"			foo();\n" + 
7264
		"		}\n" + 
7265
		"	}\n" + 
7266
		"	class A3 implements I {\n" + 
7267
		"		public void foo() {}\n" + 
7268
		"		void a3() {\n" + 
7269
		"			foo();\n" + 
7270
		"		}\n" + 
7271
		"	}\n" + 
7272
		"}"
7273
	);
7274
	IMethod method = workingCopies[0].getType("Test").getType("I").getMethod("foo", new String[0]);
7275
	search(method, REFERENCES);
7276
	assertSearchResults(
7277
		"src/Test.java void Test$A1.a1() [foo()] EXACT_MATCH\n" + 
7278
		"src/Test.java void Test$B1.b1() [foo()] EXACT_MATCH\n" + 
7279
		"src/Test.java void Test$A2.a2() [foo()] EXACT_MATCH\n" + 
7280
		"src/Test.java void Test$B2.b2() [foo()] EXACT_MATCH\n" + 
7281
		"src/Test.java void Test$A3.a3() [foo()] EXACT_MATCH"
7282
	);
7283
}
7284
public void testBug160301_Abstract() throws CoreException {
7285
	resultCollector.showRule = true;
7286
	workingCopies = new ICompilationUnit[1];
7287
	workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/Test.java",
7288
		"public class Test {\n" + 
7289
		"	abstract class Abstract {\n" + 
7290
		"		abstract void foo();\n" + 
7291
		"	}\n" + 
7292
		"	class A1 extends Abstract {\n" + 
7293
		"		public void foo() {}\n" + 
7294
		"		void a1() {\n" + 
7295
		"			foo(); // valid match as A1.foo() is the first override in sub-class\n" + 
7296
		"		}\n" + 
7297
		"	}\n" + 
7298
		"	class B1 extends A1 {\n" + 
7299
		"		void b1() {\n" + 
7300
		"			foo(); // valid match as B1 does not override A.foo()\n" + 
7301
		"		}\n" + 
7302
		"	}\n" + 
7303
		"	class C1 extends B1 {\n" + 
7304
		"		public void foo() {}\n" + 
7305
		"		void c1() {\n" + 
7306
		"			foo(); // invalid match as C1 does override A.foo()\n" + 
7307
		"		}\n" + 
7308
		"	}\n" + 
7309
		"	abstract class A2 extends Abstract {\n" + 
7310
		"		void a2() {\n" + 
7311
		"			foo(); // valid match as A2 does not override Abstract.foo()\n" + 
7312
		"		}\n" + 
7313
		"	}\n" + 
7314
		"	class B2 extends A2 {\n" + 
7315
		"		public void foo() {}\n" + 
7316
		"		void b2() {\n" + 
7317
		"			foo(); // valid match as B2.foo() is the first override in sub-class\n" + 
7318
		"		}\n" + 
7319
		"	}\n" + 
7320
		"}"
7321
	);
7322
	IMethod method = workingCopies[0].getType("Test").getType("Abstract").getMethod("foo", new String[0]);
7323
	search(method, REFERENCES);
7324
	assertSearchResults(
7325
		"src/Test.java void Test$A1.a1() [foo()] EXACT_MATCH\n" + 
7326
		"src/Test.java void Test$B1.b1() [foo()] EXACT_MATCH\n" + 
7327
		"src/Test.java void Test$A2.a2() [foo()] EXACT_MATCH\n" + 
7328
		"src/Test.java void Test$B2.b2() [foo()] EXACT_MATCH"
7329
	);
7330
}
7331
public void testBug160301_Abstract2() throws CoreException {
7332
	resultCollector.showRule = true;
7333
	workingCopies = new ICompilationUnit[1];
7334
	workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/Test.java",
7335
		"public class Test {\n" + 
7336
		"	abstract class Abstract {\n" + 
7337
		"		public abstract void foo();\n" + 
7338
		"	}\n" + 
7339
		"	abstract class A extends Abstract {\n" + 
7340
		"		public abstract void foo();\n" + 
7341
		"		void a() {\n" + 
7342
		"			foo(); // valid match as A is abstract => does not override Abstract.foo()\n" + 
7343
		"		}\n" + 
7344
		"	}\n" + 
7345
		"	class B extends A {\n" + 
7346
		"		public void foo() {}\n" + 
7347
		"		void b() {\n" + 
7348
		"			foo(); // valid match as B.foo() is the first override in sub-class\n" + 
7349
		"		}\n" + 
7350
		"	}\n" + 
7351
		"	class C extends B {\n" + 
7352
		"		public void foo() {}\n" + 
7353
		"		void c() {\n" + 
7354
		"			foo(); // invalid match as C.foo() overrides Abstract.foo() \n" + 
7355
		"		}\n" + 
7356
		"	}\n" + 
7357
		"}"
7358
	);
7359
	IMethod method = workingCopies[0].getType("Test").getType("Abstract").getMethod("foo", new String[0]);
7360
	search(method, REFERENCES);
7361
	assertSearchResults(
7362
		"src/Test.java void Test$A.a() [foo()] EXACT_MATCH\n" + 
7363
		"src/Test.java void Test$B.b() [foo()] EXACT_MATCH"
7364
	);
7365
}
7366
public void testBug160301_Abstract3() throws CoreException {
7367
	resultCollector.showRule = true;
7368
	workingCopies = new ICompilationUnit[1];
7369
	workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/Test.java",
7370
		"public class Test {\n" + 
7371
		"	abstract class Abstract {\n" + 
7372
		"		public abstract void foo();\n" + 
7373
		"	}\n" + 
7374
		"	class A extends Abstract {\n" + 
7375
		"		public void foo() {}\n" + 
7376
		"		void a() {\n" + 
7377
		"			foo(); // valid match as A.foo() is the first override in sub-class\n" + 
7378
		"		}\n" + 
7379
		"	}\n" + 
7380
		"	abstract class B extends A {\n" + 
7381
		"		public abstract void foo();\n" + 
7382
		"		void b() {\n" + 
7383
		"			foo(); // invalid match as B.foo() is hidden by the override A.foo()\n" + 
7384
		"		}\n" + 
7385
		"	}\n" + 
7386
		"	class C extends B {\n" + 
7387
		"		public void foo() {}\n" + 
7388
		"		void c() {\n" + 
7389
		"			foo(); // invalid match as C.foo() overrides A.foo()\n" + 
7390
		"		}\n" + 
7391
		"	}\n" + 
7392
		"}"
7393
	);
7394
	IMethod method = workingCopies[0].getType("Test").getType("Abstract").getMethod("foo", new String[0]);
7395
	search(method, REFERENCES);
7396
	assertSearchResults(
7397
		"src/Test.java void Test$A.a() [foo()] EXACT_MATCH"
7156
	);
7398
	);
7157
}
7399
}
7158
7400
(-)src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java (-1 / +2 lines)
Lines 1408-1414 Link Here
1408
		this.resultCollector);
1408
		this.resultCollector);
1409
	assertSearchResults(
1409
	assertSearchResults(
1410
		"src/Test.java void Test.main(String[]) [foo(1, \"a\", y)]\n" + 
1410
		"src/Test.java void Test.main(String[]) [foo(1, \"a\", y)]\n" + 
1411
		"src/Test.java void Test.main(String[]) [foo(1, \"a\", z)]\n" + 
1411
		// since bug 160301 fix, subclass overridden method calls are not reported
1412
		//"src/Test.java void Test.main(String[]) [foo(1, \"a\", z)]\n" + 
1412
		"src/p/Z.java void p.Z.foo(int, String, X) [foo(i, s, new Y(true))]",
1413
		"src/p/Z.java void p.Z.foo(int, String, X) [foo(i, s, new Y(true))]",
1413
		this.resultCollector);
1414
		this.resultCollector);
1414
}
1415
}
(-)search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java (+1 lines)
Lines 48-53 Link Here
48
public static final int CAMELCASE_FLAVOR = 0x0100;
48
public static final int CAMELCASE_FLAVOR = 0x0100;
49
public static final int SUPER_INVOCATION_FLAVOR = 0x0200;
49
public static final int SUPER_INVOCATION_FLAVOR = 0x0200;
50
public static final int SUB_INVOCATION_FLAVOR = 0x0400;
50
public static final int SUB_INVOCATION_FLAVOR = 0x0400;
51
public static final int OVERRIDDEN_METHOD_FLAVOR = 0x0800;
51
public static final int MATCH_LEVEL_MASK = 0x0F;
52
public static final int MATCH_LEVEL_MASK = 0x0F;
52
public static final int FLAVORS_MASK = ~MATCH_LEVEL_MASK;
53
public static final int FLAVORS_MASK = ~MATCH_LEVEL_MASK;
53
54
(-)search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java (-8 / +47 lines)
Lines 597-603 Link Here
597
		subType = CharOperation.compareWith(this.pattern.declaringQualification, method.declaringClass.fPackage.shortReadableName()) == 0;
597
		subType = CharOperation.compareWith(this.pattern.declaringQualification, method.declaringClass.fPackage.shortReadableName()) == 0;
598
	}
598
	}
599
	int declaringLevel = subType
599
	int declaringLevel = subType
600
		? resolveLevelAsSubtype(qualifiedPattern, method.declaringClass)
600
		? resolveLevelAsSubtype(qualifiedPattern, method.declaringClass, null)
601
		: resolveLevelForType(qualifiedPattern, method.declaringClass);
601
		: resolveLevelForType(qualifiedPattern, method.declaringClass);
602
	return methodLevel > declaringLevel ? declaringLevel : methodLevel; // return the weaker match
602
	return methodLevel > declaringLevel ? declaringLevel : methodLevel; // return the weaker match
603
}
603
}
Lines 631-637 Link Here
631
	int declaringLevel;
631
	int declaringLevel;
632
	if (isVirtualInvoke(method, messageSend) && (messageSend.actualReceiverType instanceof ReferenceBinding)) {
632
	if (isVirtualInvoke(method, messageSend) && (messageSend.actualReceiverType instanceof ReferenceBinding)) {
633
		ReferenceBinding methodReceiverType = (ReferenceBinding) messageSend.actualReceiverType;
633
		ReferenceBinding methodReceiverType = (ReferenceBinding) messageSend.actualReceiverType;
634
		declaringLevel = resolveLevelAsSubtype(qualifiedPattern, methodReceiverType);
634
		declaringLevel = resolveLevelAsSubtype(qualifiedPattern, methodReceiverType, method.parameters);
635
		if (declaringLevel == IMPOSSIBLE_MATCH) {
635
		if (declaringLevel == IMPOSSIBLE_MATCH) {
636
			if (method.declaringClass == null || this.allSuperDeclaringTypeNames == null) {
636
			if (method.declaringClass == null || this.allSuperDeclaringTypeNames == null) {
637
				declaringLevel = INACCURATE_MATCH;
637
				declaringLevel = INACCURATE_MATCH;
Lines 669-692 Link Here
669
 * Returns INACCURATE_MATCH if resolve fails
669
 * Returns INACCURATE_MATCH if resolve fails
670
 * Returns IMPOSSIBLE_MATCH if it doesn't.
670
 * Returns IMPOSSIBLE_MATCH if it doesn't.
671
 */
671
 */
672
protected int resolveLevelAsSubtype(char[] qualifiedPattern, ReferenceBinding type) {
672
protected int resolveLevelAsSubtype(char[] qualifiedPattern, ReferenceBinding type, TypeBinding[] argumentTypes) {
673
	if (type == null) return INACCURATE_MATCH;
673
	if (type == null) return INACCURATE_MATCH;
674
674
675
	int level = resolveLevelForType(qualifiedPattern, type);
675
	int level = resolveLevelForType(qualifiedPattern, type);
676
	if (level != IMPOSSIBLE_MATCH) return level;
676
	if (level != IMPOSSIBLE_MATCH) {
677
		if (!type.isAbstract() && !type.isInterface()) { // if concrete class, then method is overridden
678
			level |= OVERRIDDEN_METHOD_FLAVOR;
679
		}
680
		return level;
681
	}
677
682
678
	// matches superclass
683
	// matches superclass
679
	if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) {
684
	if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) {
680
		level = resolveLevelAsSubtype(qualifiedPattern, type.superclass());
685
		level = resolveLevelAsSubtype(qualifiedPattern, type.superclass(), argumentTypes);
681
		if (level != IMPOSSIBLE_MATCH) return level | SUB_INVOCATION_FLAVOR; // add flavor to returned level
686
		if (level != IMPOSSIBLE_MATCH) {
687
			if (argumentTypes != null) {
688
				// need to verify if method may be overridden
689
				MethodBinding[] methods = type.getMethods(this.pattern.selector);
690
				for (int i=0, length=methods.length; i<length; i++) {
691
					MethodBinding method = methods[i];
692
					TypeBinding[] parameters = method.parameters;
693
					if (argumentTypes.length == parameters.length) {
694
						boolean found = true;
695
						for (int j=0,l=parameters.length; j<l; j++) {
696
							if (parameters[j].erasure() != argumentTypes[j].erasure()) {
697
								found = false;
698
								break;
699
							}
700
						}
701
						if (found) { // one method match in hierarchy
702
							if ((level & OVERRIDDEN_METHOD_FLAVOR) != 0) {
703
								// this method is already overridden on a super class, current match is impossible
704
								return IMPOSSIBLE_MATCH;
705
							}
706
							if (!method.isAbstract() && !type.isInterface()) {
707
								// store the fact that the method is overridden
708
								level |= OVERRIDDEN_METHOD_FLAVOR;
709
							}
710
						}
711
					}
712
				}
713
			}
714
			return level | SUB_INVOCATION_FLAVOR; // add flavor to returned level
715
		}
682
	}
716
	}
683
717
684
	// matches interfaces
718
	// matches interfaces
685
	ReferenceBinding[] interfaces = type.superInterfaces();
719
	ReferenceBinding[] interfaces = type.superInterfaces();
686
	if (interfaces == null) return INACCURATE_MATCH;
720
	if (interfaces == null) return INACCURATE_MATCH;
687
	for (int i = 0; i < interfaces.length; i++) {
721
	for (int i = 0; i < interfaces.length; i++) {
688
		level = resolveLevelAsSubtype(qualifiedPattern, interfaces[i]);
722
		level = resolveLevelAsSubtype(qualifiedPattern, interfaces[i], null);
689
		if (level != IMPOSSIBLE_MATCH) return level | SUB_INVOCATION_FLAVOR; // add flavor to returned level
723
		if (level != IMPOSSIBLE_MATCH) {
724
			if (!type.isAbstract() && !type.isInterface()) { // if concrete class, then method is overridden
725
				level |= OVERRIDDEN_METHOD_FLAVOR;
726
			}
727
			return level | SUB_INVOCATION_FLAVOR; // add flavor to returned level
728
		}
690
	}
729
	}
691
	return IMPOSSIBLE_MATCH;
730
	return IMPOSSIBLE_MATCH;
692
}
731
}

Return to bug 160301