diff --git a/java/ql/lib/semmle/code/java/Type.qll b/java/ql/lib/semmle/code/java/Type.qll index a6977e954e14..7ce62ac0b859 100755 --- a/java/ql/lib/semmle/code/java/Type.qll +++ b/java/ql/lib/semmle/code/java/Type.qll @@ -568,12 +568,30 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { exists(Field f | f = m | f = this.getAField() or - not f.isPrivate() and not this.declaresField(f.getName()) and this.getASupertype().inherits(f) + not f.isPrivate() and + (f.isPackageProtected() implies f.getDeclaringType().getPackage() = this.getPackage()) and + not this.declaresField(f.getName()) and + this.getASupertype().inherits(f) or this.getSourceDeclaration().inherits(f) ) or this.hasMethod(m, _) + or + // Constructors are not inherited, but this predicate also considers declared members + m.(Constructor).getDeclaringType() = this.getSourceDeclaration() + or + exists(MemberType memberType | memberType = m | + m.(MemberType).getDeclaringType() = this + or + not memberType.isPrivate() and + (memberType.isPackageProtected() implies memberType.getPackage() = this.getPackage()) and + // And member type is not hidden by another member type with the same name (regardless of visibility) + not this.getAMember().(MemberType).getName() = memberType.getName() and + this.getASupertype().inherits(memberType) + or + this.getSourceDeclaration().inherits(memberType) + ) } /** Holds if this is a top-level type, which is not nested inside any other types. */ diff --git a/java/ql/test/library-tests/inheritance/inhertiance.expected b/java/ql/test/library-tests/inheritance/inhertiance.expected new file mode 100644 index 000000000000..84a645de09d9 --- /dev/null +++ b/java/ql/test/library-tests/inheritance/inhertiance.expected @@ -0,0 +1,82 @@ +onlyInherited +| package_a/FieldInheritanceA.java:36:19:36:36 | InheritingClashing | package_a/FieldInheritanceA.java:25:13:25:19 | staticI | +| package_a/FieldInheritanceA.java:36:19:36:36 | InheritingClashing | package_a/FieldInheritanceA.java:28:13:28:19 | staticI | +| package_a/FieldInheritanceA.java:36:19:36:36 | InheritingClashing | package_a/FieldInheritanceA.java:31:20:31:20 | i | +| package_a/FieldInheritanceA.java:36:19:36:36 | InheritingClashing | package_a/FieldInheritanceA.java:32:27:32:33 | staticI | +| package_a/FieldInheritanceA.java:43:26:43:45 | ExtendingHidingField | package_a/FieldInheritanceA.java:40:27:40:27 | i | +| package_a/FieldInheritanceA.java:43:26:43:45 | ExtendingHidingField | package_a/FieldInheritanceA.java:41:20:41:26 | staticI | +| package_a/FieldInheritanceAB.java:8:14:8:31 | FieldInheritanceAB | package_a/FieldInheritanceA.java:12:19:12:32 | protectedField | +| package_a/FieldInheritanceAB.java:8:14:8:31 | FieldInheritanceAB | package_a/FieldInheritanceA.java:13:26:13:45 | protectedStaticField | +| package_a/FieldInheritanceAB.java:8:14:8:31 | FieldInheritanceAB | package_a/FieldInheritanceA.java:15:16:15:26 | publicField | +| package_a/FieldInheritanceAB.java:8:14:8:31 | FieldInheritanceAB | package_a/FieldInheritanceA.java:16:23:16:39 | publicStaticField | +| package_a/FieldInheritanceOtherA.java:3:14:3:35 | FieldInheritanceOtherA | package_a/FieldInheritanceA.java:9:9:9:27 | packagePrivateField | +| package_a/FieldInheritanceOtherA.java:3:14:3:35 | FieldInheritanceOtherA | package_a/FieldInheritanceA.java:10:16:10:40 | packagePrivateStaticField | +| package_a/FieldInheritanceOtherA.java:3:14:3:35 | FieldInheritanceOtherA | package_a/FieldInheritanceA.java:12:19:12:32 | protectedField | +| package_a/FieldInheritanceOtherA.java:3:14:3:35 | FieldInheritanceOtherA | package_a/FieldInheritanceA.java:13:26:13:45 | protectedStaticField | +| package_a/FieldInheritanceOtherA.java:3:14:3:35 | FieldInheritanceOtherA | package_a/FieldInheritanceA.java:15:16:15:26 | publicField | +| package_a/FieldInheritanceOtherA.java:3:14:3:35 | FieldInheritanceOtherA | package_a/FieldInheritanceA.java:16:23:16:39 | publicStaticField | +| package_a/FieldInheritanceOtherA.java:3:14:3:35 | FieldInheritanceOtherA | package_a/FieldInheritanceA.java:55:18:55:35 | PrivateHidingField | +| package_a/MemberTypeInheritanceA.java:25:23:25:46 | ExtendingPublicInterface | package_a/MemberTypeInheritanceA.java:22:29:22:34 | Nested | +| package_a/MemberTypeInheritanceA.java:26:23:26:55 | ExtendingExtendingPublicInterface | package_a/MemberTypeInheritanceA.java:22:29:22:34 | Nested | +| package_a/MemberTypeInheritanceA.java:27:19:27:45 | ImplementingPublicInterface | package_a/MemberTypeInheritanceA.java:22:29:22:34 | Nested | +| package_a/MemberTypeInheritanceA.java:36:26:36:43 | InheritingClashing | package_a/MemberTypeInheritanceA.java:22:29:22:34 | Nested | +| package_a/MemberTypeInheritanceA.java:36:26:36:43 | InheritingClashing | package_a/MemberTypeInheritanceA.java:30:29:30:34 | Nested | +| package_a/MemberTypeInheritanceA.java:36:26:36:43 | InheritingClashing | package_a/MemberTypeInheritanceA.java:33:29:33:34 | Nested | +| package_a/MemberTypeInheritanceA.java:41:23:41:48 | ExtendingHidingNestedClass | package_a/MemberTypeInheritanceA.java:39:26:39:31 | Nested | +| package_a/MemberTypeInheritanceA.java:66:19:66:41 | ExtendingWithLocalTypes | package_a/MemberTypeInheritanceA.java:58:36:58:36 | o | +| package_a/MemberTypeInheritanceA.java:66:19:66:41 | ExtendingWithLocalTypes | package_a/MemberTypeInheritanceA.java:60:21:60:21 | m | +| package_a/MemberTypeInheritanceAB.java:8:14:8:36 | MemberTypeInheritanceAB | package_a/MemberTypeInheritanceA.java:16:21:16:34 | ProtectedClass | +| package_a/MemberTypeInheritanceAB.java:8:14:8:36 | MemberTypeInheritanceAB | package_a/MemberTypeInheritanceA.java:17:25:17:42 | ProtectedInterface | +| package_a/MemberTypeInheritanceAB.java:8:14:8:36 | MemberTypeInheritanceAB | package_a/MemberTypeInheritanceA.java:19:18:19:28 | PublicClass | +| package_a/MemberTypeInheritanceAB.java:8:14:8:36 | MemberTypeInheritanceAB | package_a/MemberTypeInheritanceA.java:20:25:20:41 | PublicStaticClass | +| package_a/MemberTypeInheritanceAB.java:8:14:8:36 | MemberTypeInheritanceAB | package_a/MemberTypeInheritanceA.java:21:22:21:36 | PublicInterface | +| package_a/MemberTypeInheritanceOtherA.java:3:14:3:40 | MemberTypeInheritanceOtherA | package_a/MemberTypeInheritanceA.java:13:11:13:29 | PackagePrivateClass | +| package_a/MemberTypeInheritanceOtherA.java:3:14:3:40 | MemberTypeInheritanceOtherA | package_a/MemberTypeInheritanceA.java:14:15:14:37 | PackagePrivateInterface | +| package_a/MemberTypeInheritanceOtherA.java:3:14:3:40 | MemberTypeInheritanceOtherA | package_a/MemberTypeInheritanceA.java:16:21:16:34 | ProtectedClass | +| package_a/MemberTypeInheritanceOtherA.java:3:14:3:40 | MemberTypeInheritanceOtherA | package_a/MemberTypeInheritanceA.java:17:25:17:42 | ProtectedInterface | +| package_a/MemberTypeInheritanceOtherA.java:3:14:3:40 | MemberTypeInheritanceOtherA | package_a/MemberTypeInheritanceA.java:19:18:19:28 | PublicClass | +| package_a/MemberTypeInheritanceOtherA.java:3:14:3:40 | MemberTypeInheritanceOtherA | package_a/MemberTypeInheritanceA.java:20:25:20:41 | PublicStaticClass | +| package_a/MemberTypeInheritanceOtherA.java:3:14:3:40 | MemberTypeInheritanceOtherA | package_a/MemberTypeInheritanceA.java:21:22:21:36 | PublicInterface | +| package_a/MemberTypeInheritanceOtherA.java:3:14:3:40 | MemberTypeInheritanceOtherA | package_a/MemberTypeInheritanceA.java:47:18:47:41 | HidingNestedClassPrivate | +| package_a/MethodInheritanceA.java:49:23:49:40 | ExtendingInterface | package_a/MethodInheritanceA.java:46:22:46:22 | d | +| package_a/MethodInheritanceA.java:49:23:49:40 | ExtendingInterface | package_a/MethodInheritanceA.java:47:14:47:14 | a | +| package_a/MethodInheritanceA.java:66:26:66:49 | ExtendingClassWithPublic | package_a/MethodInheritanceA.java:64:21:64:21 | m | +| package_a/MethodInheritanceA.java:69:28:69:53 | AbstractInheritingClashing | package_a/MethodInheritanceA.java:61:30:61:30 | m | +| package_a/MethodInheritanceA.java:72:19:72:36 | InheritingClashing | package_a/MethodInheritanceA.java:64:21:64:21 | m | +| package_a/MethodInheritanceA.java:76:19:76:46 | InheritingClashingTransitive | package_a/MethodInheritanceA.java:64:21:64:21 | m | +| package_a/MethodInheritanceA.java:82:23:82:46 | ExtendingMultipleMethods | package_a/MethodInheritanceA.java:80:14:80:14 | m | +| package_a/MethodInheritanceA.java:102:26:102:40 | BaseAndOverride | package_a/MethodInheritanceA.java:96:22:96:22 | m | +| package_a/MethodInheritanceA.java:104:23:104:45 | ExtendingOverridingBase | package_a/MethodInheritanceA.java:96:22:96:22 | m | +| package_a/MethodInheritanceA.java:106:26:106:49 | BaseAndExtendingOverride | package_a/MethodInheritanceA.java:96:22:96:22 | m | +| package_a/MethodInheritanceA.java:117:19:117:40 | InheritingSubsignature | package_a/MethodInheritanceA.java:112:21:112:21 | m | +| package_a/MethodInheritanceAB.java:7:14:7:32 | MethodInheritanceAB | package_a/MethodInheritanceA.java:17:20:17:34 | protectedMethod | +| package_a/MethodInheritanceAB.java:7:14:7:32 | MethodInheritanceAB | package_a/MethodInheritanceA.java:18:27:18:47 | protectedStaticMethod | +| package_a/MethodInheritanceAB.java:7:14:7:32 | MethodInheritanceAB | package_a/MethodInheritanceA.java:20:17:20:28 | publicMethod | +| package_a/MethodInheritanceAB.java:7:14:7:32 | MethodInheritanceAB | package_a/MethodInheritanceA.java:21:24:21:41 | publicStaticMethod | +| package_b/FieldInheritanceB.java:5:14:5:30 | FieldInheritanceB | package_a/FieldInheritanceA.java:12:19:12:32 | protectedField | +| package_b/FieldInheritanceB.java:5:14:5:30 | FieldInheritanceB | package_a/FieldInheritanceA.java:13:26:13:45 | protectedStaticField | +| package_b/FieldInheritanceB.java:5:14:5:30 | FieldInheritanceB | package_a/FieldInheritanceA.java:15:16:15:26 | publicField | +| package_b/FieldInheritanceB.java:5:14:5:30 | FieldInheritanceB | package_a/FieldInheritanceA.java:16:23:16:39 | publicStaticField | +| package_b/FieldInheritanceBTransitive.java:3:14:3:40 | FieldInheritanceBTransitive | package_a/FieldInheritanceA.java:12:19:12:32 | protectedField | +| package_b/FieldInheritanceBTransitive.java:3:14:3:40 | FieldInheritanceBTransitive | package_a/FieldInheritanceA.java:13:26:13:45 | protectedStaticField | +| package_b/FieldInheritanceBTransitive.java:3:14:3:40 | FieldInheritanceBTransitive | package_a/FieldInheritanceA.java:15:16:15:26 | publicField | +| package_b/FieldInheritanceBTransitive.java:3:14:3:40 | FieldInheritanceBTransitive | package_a/FieldInheritanceA.java:16:23:16:39 | publicStaticField | +| package_b/MemberTypeInheritanceB.java:5:14:5:35 | MemberTypeInheritanceB | package_a/MemberTypeInheritanceA.java:16:21:16:34 | ProtectedClass | +| package_b/MemberTypeInheritanceB.java:5:14:5:35 | MemberTypeInheritanceB | package_a/MemberTypeInheritanceA.java:17:25:17:42 | ProtectedInterface | +| package_b/MemberTypeInheritanceB.java:5:14:5:35 | MemberTypeInheritanceB | package_a/MemberTypeInheritanceA.java:19:18:19:28 | PublicClass | +| package_b/MemberTypeInheritanceB.java:5:14:5:35 | MemberTypeInheritanceB | package_a/MemberTypeInheritanceA.java:20:25:20:41 | PublicStaticClass | +| package_b/MemberTypeInheritanceB.java:5:14:5:35 | MemberTypeInheritanceB | package_a/MemberTypeInheritanceA.java:21:22:21:36 | PublicInterface | +| package_b/MemberTypeInheritanceBTransitive.java:3:14:3:45 | MemberTypeInheritanceBTransitive | package_a/MemberTypeInheritanceA.java:16:21:16:34 | ProtectedClass | +| package_b/MemberTypeInheritanceBTransitive.java:3:14:3:45 | MemberTypeInheritanceBTransitive | package_a/MemberTypeInheritanceA.java:17:25:17:42 | ProtectedInterface | +| package_b/MemberTypeInheritanceBTransitive.java:3:14:3:45 | MemberTypeInheritanceBTransitive | package_a/MemberTypeInheritanceA.java:19:18:19:28 | PublicClass | +| package_b/MemberTypeInheritanceBTransitive.java:3:14:3:45 | MemberTypeInheritanceBTransitive | package_a/MemberTypeInheritanceA.java:20:25:20:41 | PublicStaticClass | +| package_b/MemberTypeInheritanceBTransitive.java:3:14:3:45 | MemberTypeInheritanceBTransitive | package_a/MemberTypeInheritanceA.java:21:22:21:36 | PublicInterface | +| package_b/MethodInheritanceB.java:5:14:5:31 | MethodInheritanceB | package_a/MethodInheritanceA.java:17:20:17:34 | protectedMethod | +| package_b/MethodInheritanceB.java:5:14:5:31 | MethodInheritanceB | package_a/MethodInheritanceA.java:18:27:18:47 | protectedStaticMethod | +| package_b/MethodInheritanceB.java:5:14:5:31 | MethodInheritanceB | package_a/MethodInheritanceA.java:20:17:20:28 | publicMethod | +| package_b/MethodInheritanceB.java:5:14:5:31 | MethodInheritanceB | package_a/MethodInheritanceA.java:21:24:21:41 | publicStaticMethod | +| package_b/MethodInheritanceBTransitive.java:3:14:3:41 | MethodInheritanceBTransitive | package_a/MethodInheritanceA.java:17:20:17:34 | protectedMethod | +| package_b/MethodInheritanceBTransitive.java:3:14:3:41 | MethodInheritanceBTransitive | package_a/MethodInheritanceA.java:18:27:18:47 | protectedStaticMethod | +| package_b/MethodInheritanceBTransitive.java:3:14:3:41 | MethodInheritanceBTransitive | package_a/MethodInheritanceA.java:20:17:20:28 | publicMethod | +| package_b/MethodInheritanceBTransitive.java:3:14:3:41 | MethodInheritanceBTransitive | package_a/MethodInheritanceA.java:21:24:21:41 | publicStaticMethod | +bugDeclaredButNotInherited diff --git a/java/ql/test/library-tests/inheritance/inhertiance.ql b/java/ql/test/library-tests/inheritance/inhertiance.ql new file mode 100644 index 000000000000..c159407ea9b3 --- /dev/null +++ b/java/ql/test/library-tests/inheritance/inhertiance.ql @@ -0,0 +1,17 @@ +import java + +/** Matches members which are only inherited, but not declared by the type */ +query Member onlyInherited(RefType t) { + t.fromSource() and + t.inherits(result) and + not result.getDeclaringType() instanceof TypeObject and + // Ignore declared members; query predicate below verifies that they are a subset + not result.getDeclaringType() = t +} + +/** Verifies that declared members are a subset of inherited members */ +query Member bugDeclaredButNotInherited(RefType t) { + t.fromSource() and + result.getDeclaringType() = t and + not t.inherits(result) +} diff --git a/java/ql/test/library-tests/inheritance/options b/java/ql/test/library-tests/inheritance/options new file mode 100644 index 000000000000..fc57fe025b9a --- /dev/null +++ b/java/ql/test/library-tests/inheritance/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -source 16 -target 16 diff --git a/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceA.java b/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceA.java new file mode 100644 index 000000000000..143192e513ee --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceA.java @@ -0,0 +1,59 @@ +// See https://docs.oracle.com/javase/specs/jls/se17/html/jls-8.html#jls-8.3 + +package package_a; + +public class FieldInheritanceA { + private int privateField; + private static int privateStaticField; + + int packagePrivateField; + static int packagePrivateStaticField; + + protected int protectedField; + protected static int protectedStaticField; + + public int publicField; + public static int publicStaticField; + + private static class ClassWithPrivate { + private int i; + private static int staticI; + } + private class ExtendingClassWithPrivate extends ClassWithPrivate {} + + private interface InterfaceWithPublic { + int staticI = 1; + } + private interface OtherInterfaceWithPublic { + int staticI = 1; + } + private static class ClassWithPublic { + public int i; + public static int staticI; + } + + // Should inherit all fields called staticI + private class InheritingClashing extends ClassWithPublic implements InterfaceWithPublic, OtherInterfaceWithPublic {} + + private static class HidingField extends ClassWithPublic { + // Whether fields are static or not does not make a difference + public static int i; + public int staticI; + } + private static class ExtendingHidingField extends HidingField {} + private static class HidingTransitiveField extends ExtendingHidingField { + public int i; + public static int staticI; + } + + private static class HidingWithDifferentType extends ClassWithPublic { + private String i; + private static String staticI; + } + + // Has subclass in FieldInheritanceOtherA + static class PrivateHidingField extends ClassWithPublic { + private String i; + private static String staticI; + } +} diff --git a/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceAB.java b/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceAB.java new file mode 100644 index 000000000000..efa8f7ddfa00 --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceAB.java @@ -0,0 +1,9 @@ +package package_a; + +import package_b.FieldInheritanceB; + +// Tries to transitively inherit package-private fields which were not inherited by FieldInheritanceB +// These fields should not be considered inherited per JLS, even though the javac error message when +// trying to access them is misleading: "cannot be accessed from outside package" +public class FieldInheritanceAB extends FieldInheritanceB { +} diff --git a/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceOtherA.java b/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceOtherA.java new file mode 100644 index 000000000000..4aa675a5f7bc --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/FieldInheritanceOtherA.java @@ -0,0 +1,7 @@ +package package_a; + +public class FieldInheritanceOtherA extends FieldInheritanceA { + // Cannot inheriting original fields, due to fields in PrivateHidingField + // even though they are not accessible here + class ExtendingPrivateHidingField extends PrivateHidingField {} +} diff --git a/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceA.java b/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceA.java new file mode 100644 index 000000000000..c18f12ffa9dd --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceA.java @@ -0,0 +1,67 @@ +// See https://docs.oracle.com/javase/specs/jls/se17/html/jls-8.html#jls-8.5 + +package package_a; + +public class MemberTypeInheritanceA { + private class PrivateClass { + private class Nested {} + } + private class ExtendingPrivateClass extends PrivateClass {} + + private interface PrivateInterface {} + + class PackagePrivateClass {} + interface PackagePrivateInterface {} + + protected class ProtectedClass {} + protected interface ProtectedInterface {} + + public class PublicClass {} + public static class PublicStaticClass {} + public interface PublicInterface { + public static class Nested {} + } + + private interface ExtendingPublicInterface extends PublicInterface {} + private interface ExtendingExtendingPublicInterface extends ExtendingPublicInterface {} + private class ImplementingPublicInterface implements PublicInterface {} + + private interface OtherInterface { + public static class Nested {} + } + private static class OtherClass { + public static class Nested {} + } + // Should inherit all classes called Nested + private static class InheritingClashing extends OtherClass implements PublicInterface, OtherInterface {} + + private interface HidingNestedClass extends OtherInterface { + public interface Nested {} + } + private interface ExtendingHidingNestedClass extends HidingNestedClass {} + private interface HidingTransitiveNestedClass extends ExtendingPublicInterface { + public interface Nested {} + } + + // Has subclass in MemberTypeInheritanceOtherA + static class HidingNestedClassPrivate implements OtherInterface { + private interface Nested {} + } + + private class WithLocalTypes { + // Local and anonymous types are not inherited + + { + class LocalClass {} + } + + public static final Object o = new Object() {}; + + public void m() { + class LocalClass {} + interface LocalInterface {} + record LocalRecord() {} + } + } + private class ExtendingWithLocalTypes extends WithLocalTypes {} +} diff --git a/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceAB.java b/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceAB.java new file mode 100644 index 000000000000..a317e6295927 --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceAB.java @@ -0,0 +1,9 @@ +package package_a; + +import package_b.MemberTypeInheritanceB; + +// Tries to transitively inherit package-private member types which were not inherited by MemberTypeInheritanceB +// These member types should not be considered inherited per JLS, even though the javac error message when +// trying to access them is misleading: "cannot be accessed from outside package" +public class MemberTypeInheritanceAB extends MemberTypeInheritanceB { +} diff --git a/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceOtherA.java b/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceOtherA.java new file mode 100644 index 000000000000..8dba7058eccc --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/MemberTypeInheritanceOtherA.java @@ -0,0 +1,7 @@ +package package_a; + +public class MemberTypeInheritanceOtherA extends MemberTypeInheritanceA { + // Cannot inheriting original class, due to class in HidingNestedClassPrivate + // even though it is not accessible here + private static class ExtendendingHidingNestedClassPrivate extends HidingNestedClassPrivate {} +} diff --git a/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceA.java b/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceA.java new file mode 100644 index 000000000000..97846291b328 --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceA.java @@ -0,0 +1,126 @@ +// See https://docs.oracle.com/javase/specs/jls/se17/html/jls-8.html#jls-8.4.8 + +package package_a; + +import java.util.List; + +public class MethodInheritanceA { + // Constructor is not inherited + public MethodInheritanceA() {} + + private void privateMethod() {} + private static void privateStaticMethod() {} + + void packagePrivateMethod() {} + static void packagePrivateStaticMethod() {} + + protected void protectedMethod() {} + protected static void protectedStaticMethod() {} + + public void publicMethod() {} + public static void publicStaticMethod() {} + + private static class ClassWithPrivate { + // Initializer are not inherited + { + System.out.println("init"); + } + static { + System.out.println("static init"); + } + + private void m() {} + } + private static class ExtendingClassWithPrivate extends ClassWithPrivate {} + + private interface InterfaceWithPrivate { + private void m() {} + private static void staticM() {} + // Static methods are not inherited from interfaces + public static void publicStaticM() {} + } + private interface ExtendingInterfaceWithPrivate extends InterfaceWithPrivate {} + private class ImplementingInterfaceWithPrivate implements InterfaceWithPrivate {} + + private interface Interface { + default void d() {} + void a(); + } + private interface ExtendingInterface extends Interface {} + + private interface InterfaceWithPublic { + void m(); + } + private interface OtherInterfaceWithPublic { + void m(); + } + private interface InterfaceWithDefault { + default void m() {} + } + private static abstract class AbstractClassWithPublic { + public abstract void m(); + } + private static class ClassWithPublic { + public void m() {} + } + private static class ExtendingClassWithPublic extends ClassWithPublic {} + + // Should inherit all methods called m() + private abstract class AbstractInheritingClashing extends AbstractClassWithPublic implements InterfaceWithPublic, OtherInterfaceWithPublic, InterfaceWithDefault {} + + // Should only inherit m() from ClassWithPublic + private class InheritingClashing extends ClassWithPublic implements InterfaceWithPublic, OtherInterfaceWithPublic, InterfaceWithDefault {} + + // Should only inherit concrete method m() from ClassWithPublic, even though it is only + // transitively inherited + private class InheritingClashingTransitive extends ExtendingClassWithPublic implements InterfaceWithPublic, OtherInterfaceWithPublic, InterfaceWithDefault {} + + private interface MultipleMethods { + void m(int i); + void m(Integer i); + } + private interface ExtendingMultipleMethods extends MultipleMethods { + @Override + void m(int i); + + // Other method should still be inherited + } + + private interface Base { + default void m() { + System.out.println("base"); + } + } + private interface OverridingBase extends Base { + @Override + default void m() { + System.out.println("overridden"); + } + } + + // Should only inherit OverridingBase.m() + private static class BaseAndOverride implements OverridingBase, Base {} + + private interface ExtendingOverridingBase extends OverridingBase {} + // Should only inherit OverridingBase.m() + private static class BaseAndExtendingOverride implements ExtendingOverridingBase, Base {} + + private class ClassWithParameterized { + public void m(List l) {} + } + private class ClassWithRaw { + public void m(List raw) {} + } + private interface InterfaceWithParameterized { + void m(List l); + } + private class InheritingSubsignature extends ClassWithRaw implements InterfaceWithParameterized {} + private class OverridingSubsignatureRawClass extends ClassWithRaw implements InterfaceWithParameterized { + @Override + public void m(List raw) {} + } + private class OverridingSubsignatureParameterized extends ClassWithParameterized implements InterfaceWithParameterized { + @Override + public void m(List raw) {} + } +} diff --git a/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceAB.java b/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceAB.java new file mode 100644 index 000000000000..7bf985450c4b --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceAB.java @@ -0,0 +1,14 @@ +package package_a; + +import package_b.MethodInheritanceB; + +// Tries to transitively inherit package-private methods which were not inherited by FieldInheritanceB +// These methods should not be considered inherited per JLS +public class MethodInheritanceAB extends MethodInheritanceB { + // Interestingly it is possible to override the method, but not to refer to the super implementation + @Override + void packagePrivateMethod() { + // Does not compile + // super.packagePrivateMethod(); + } +} diff --git a/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceOtherA.java b/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceOtherA.java new file mode 100644 index 000000000000..2867439b1114 --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_a/MethodInheritanceOtherA.java @@ -0,0 +1,4 @@ +package package_a; + +public class MethodInheritanceOtherA { +} diff --git a/java/ql/test/library-tests/inheritance/package_b/FieldInheritanceB.java b/java/ql/test/library-tests/inheritance/package_b/FieldInheritanceB.java new file mode 100644 index 000000000000..4a799fa0a84f --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_b/FieldInheritanceB.java @@ -0,0 +1,6 @@ +package package_b; + +import package_a.FieldInheritanceA; + +public class FieldInheritanceB extends FieldInheritanceA { +} diff --git a/java/ql/test/library-tests/inheritance/package_b/FieldInheritanceBTransitive.java b/java/ql/test/library-tests/inheritance/package_b/FieldInheritanceBTransitive.java new file mode 100644 index 000000000000..19fed8cac031 --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_b/FieldInheritanceBTransitive.java @@ -0,0 +1,4 @@ +package package_b; + +public class FieldInheritanceBTransitive extends FieldInheritanceB { +} diff --git a/java/ql/test/library-tests/inheritance/package_b/MemberTypeInheritanceB.java b/java/ql/test/library-tests/inheritance/package_b/MemberTypeInheritanceB.java new file mode 100644 index 000000000000..94e47c825e96 --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_b/MemberTypeInheritanceB.java @@ -0,0 +1,6 @@ +package package_b; + +import package_a.MemberTypeInheritanceA; + +public class MemberTypeInheritanceB extends MemberTypeInheritanceA { +} diff --git a/java/ql/test/library-tests/inheritance/package_b/MemberTypeInheritanceBTransitive.java b/java/ql/test/library-tests/inheritance/package_b/MemberTypeInheritanceBTransitive.java new file mode 100644 index 000000000000..949766d1ce2a --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_b/MemberTypeInheritanceBTransitive.java @@ -0,0 +1,4 @@ +package package_b; + +public class MemberTypeInheritanceBTransitive extends MemberTypeInheritanceB { +} diff --git a/java/ql/test/library-tests/inheritance/package_b/MethodInheritanceB.java b/java/ql/test/library-tests/inheritance/package_b/MethodInheritanceB.java new file mode 100644 index 000000000000..8fcc43a7108e --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_b/MethodInheritanceB.java @@ -0,0 +1,6 @@ +package package_b; + +import package_a.MethodInheritanceA; + +public class MethodInheritanceB extends MethodInheritanceA { +} diff --git a/java/ql/test/library-tests/inheritance/package_b/MethodInheritanceBTransitive.java b/java/ql/test/library-tests/inheritance/package_b/MethodInheritanceBTransitive.java new file mode 100644 index 000000000000..7bb24b71b44c --- /dev/null +++ b/java/ql/test/library-tests/inheritance/package_b/MethodInheritanceBTransitive.java @@ -0,0 +1,4 @@ +package package_b; + +public class MethodInheritanceBTransitive extends MethodInheritanceB { +}