Skip to content

Commit 0dd463d

Browse files
authored
Merge pull request github#6520 from smowton/smowton/feature/allow-local-interfaces
Java: Allow local interfaces
2 parents 76a4114 + c20cf23 commit 0dd463d

File tree

18 files changed

+2083
-78
lines changed

18 files changed

+2083
-78
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* `Class.isLocal` has been replaced with `ClassOrInterface.isLocal`. This is because as of Java 16, interfaces can be declared method-local. Accordingly, `LocalClassDeclStmt.getLocalClass` is renamed `LocalTypeDeclStmt.getLocalType` and now returns a `ClassOrInterface`. `BusinessInterface`, declared in `EJB.qll`, has had its `isRemote` and `isLocal` methods renamed `isDeclaredLocal` and `isDeclaredRemote` to avoid a name clash.

java/ql/lib/config/semmlecode.dbscheme

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -440,10 +440,10 @@ isAnonymClass(
440440
int parent: @classinstancexpr ref
441441
);
442442

443-
#keyset[classid] #keyset[parent]
444-
isLocalClass(
445-
int classid: @class ref,
446-
int parent: @localclassdeclstmt ref
443+
#keyset[typeid] #keyset[parent]
444+
isLocalClassOrInterface(
445+
int typeid: @classorinterface ref,
446+
int parent: @localtypedeclstmt ref
447447
);
448448

449449
isDefConstr(
@@ -526,7 +526,7 @@ case @stmt.kind of
526526
| 15 = @labeledstmt
527527
| 16 = @assertstmt
528528
| 17 = @localvariabledeclstmt
529-
| 18 = @localclassdeclstmt
529+
| 18 = @localtypedeclstmt
530530
| 19 = @constructorinvocationstmt
531531
| 20 = @superconstructorinvocationstmt
532532
| 21 = @case

java/ql/lib/config/semmlecode.dbscheme.stats

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
<v>223232</v>
170170
</e>
171171
<e>
172-
<k>@localclassdeclstmt</k>
172+
<k>@localtypedeclstmt</k>
173173
<v>349</v>
174174
</e>
175175
<e>
@@ -16910,11 +16910,11 @@
1691016910
</dependencies>
1691116911
</relation>
1691216912
<relation>
16913-
<name>isLocalClass</name>
16913+
<name>isLocalClassOrInterface</name>
1691416914
<cardinality>349</cardinality>
1691516915
<columnsizes>
1691616916
<e>
16917-
<k>classid</k>
16917+
<k>typeid</k>
1691816918
<v>349</v>
1691916919
</e>
1692016920
<e>
@@ -16924,7 +16924,7 @@
1692416924
</columnsizes>
1692516925
<dependencies>
1692616926
<dep>
16927-
<src>classid</src>
16927+
<src>typeid</src>
1692816928
<trg>parent</trg>
1692916929
<val>
1693016930
<hist>
@@ -16941,7 +16941,7 @@
1694116941
</dep>
1694216942
<dep>
1694316943
<src>parent</src>
16944-
<trg>classid</trg>
16944+
<trg>typeid</trg>
1694516945
<val>
1694616946
<hist>
1694716947
<budget>12</budget>

java/ql/lib/semmle/code/java/ControlFlowGraph.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ private module ControlFlowGraphImpl {
456456
or
457457
this instanceof EmptyStmt
458458
or
459-
this instanceof LocalClassDeclStmt
459+
this instanceof LocalTypeDeclStmt
460460
or
461461
this instanceof AssertStmt
462462
}

java/ql/lib/semmle/code/java/Member.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ class Member extends Element, Annotatable, Modifiable, @member {
4040

4141
/**
4242
* Gets the immediately enclosing callable, if this member is declared in
43-
* an anonymous or local class.
43+
* an anonymous or local class or interface.
4444
*/
4545
Callable getEnclosingCallable() {
46-
exists(NestedClass nc | this.getDeclaringType() = nc |
47-
nc.(AnonymousClass).getClassInstanceExpr().getEnclosingCallable() = result or
48-
nc.(LocalClass).getLocalClassDeclStmt().getEnclosingCallable() = result
46+
exists(NestedType nt | this.getDeclaringType() = nt |
47+
nt.(AnonymousClass).getClassInstanceExpr().getEnclosingCallable() = result or
48+
nt.(LocalClassOrInterface).getLocalTypeDeclStmt().getEnclosingCallable() = result
4949
)
5050
}
5151
}

java/ql/lib/semmle/code/java/PrettyPrintAst.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,8 @@ private class PpLocalVariableDeclStmt extends PpAst, LocalVariableDeclStmt {
877877
}
878878
}
879879

880-
private class PpLocalClassDeclStmt extends PpAst, LocalClassDeclStmt {
881-
override PpAst getChild(int i) { i = 0 and result = this.getLocalClass() }
880+
private class PpLocalTypeDeclStmt extends PpAst, LocalTypeDeclStmt {
881+
override PpAst getChild(int i) { i = 0 and result = this.getLocalType() }
882882
}
883883

884884
/*

java/ql/lib/semmle/code/java/PrintAst.qll

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,19 +303,25 @@ final class ClassInstanceExprNode extends ExprStmtNode {
303303
}
304304

305305
/**
306-
* A node representing a `LocalClassDeclStmt`.
306+
* A node representing a `LocalTypeDeclStmt`.
307307
*/
308-
final class LocalClassDeclStmtNode extends ExprStmtNode {
309-
LocalClassDeclStmtNode() { element instanceof LocalClassDeclStmt }
308+
final class LocalTypeDeclStmtNode extends ExprStmtNode {
309+
LocalTypeDeclStmtNode() { element instanceof LocalTypeDeclStmt }
310310

311311
override ElementNode getChild(int childIndex) {
312312
result = super.getChild(childIndex)
313313
or
314314
childIndex = 0 and
315-
result.getElement() = element.(LocalClassDeclStmt).getLocalClass()
315+
result.getElement() = element.(LocalTypeDeclStmt).getLocalType()
316316
}
317317
}
318318

319+
/**
320+
* DEPRECATED: Renamed `LocalTypeDeclStmtNode` to reflect the fact that
321+
* as of Java 16 interfaces can also be declared locally, not just classes.
322+
*/
323+
deprecated class LocalClassDeclStmtNode = LocalTypeDeclStmtNode;
324+
319325
/**
320326
* A node representing a `ForStmt`.
321327
*/

java/ql/lib/semmle/code/java/Statement.qll

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -786,20 +786,38 @@ class LocalVariableDeclStmt extends Stmt, @localvariabledeclstmt {
786786
override string getAPrimaryQlClass() { result = "LocalVariableDeclStmt" }
787787
}
788788

789-
/** A statement that declares a local class. */
790-
class LocalClassDeclStmt extends Stmt, @localclassdeclstmt {
791-
/** Gets the local class declared by this statement. */
792-
LocalClass getLocalClass() { isLocalClass(result, this) }
789+
/** A statement that declares a local class or interface. */
790+
class LocalTypeDeclStmt extends Stmt, @localtypedeclstmt {
791+
/** Gets the local type declared by this statement. */
792+
LocalClassOrInterface getLocalType() { isLocalClassOrInterface(result, this) }
793793

794-
override string pp() { result = "class " + this.getLocalClass().toString() }
794+
/**
795+
* DEPRECATED: Renamed `getLocalType` to reflect the fact that
796+
* as of Java 16 interfaces can also be declared locally, not just classes.
797+
*/
798+
deprecated LocalClassOrInterface getLocalClass() { result = this.getLocalType() }
799+
800+
private string getDeclKeyword() {
801+
result = "class" and this.getLocalType() instanceof Class
802+
or
803+
result = "interface" and this.getLocalType() instanceof Interface
804+
}
795805

796-
override string toString() { result = "class ..." }
806+
override string pp() { result = this.getDeclKeyword() + " " + this.getLocalType().toString() }
797807

798-
override string getHalsteadID() { result = "LocalClassDeclStmt" }
808+
override string toString() { result = this.getDeclKeyword() + " ..." }
799809

800-
override string getAPrimaryQlClass() { result = "LocalClassDeclStmt" }
810+
override string getHalsteadID() { result = "LocalTypeDeclStmt" }
811+
812+
override string getAPrimaryQlClass() { result = "LocalTypeDeclStmt" }
801813
}
802814

815+
/**
816+
* DEPRECATED: Renamed `LocalTypeDeclStmt` to reflect the fact that
817+
* as of Java 16 interfaces can also be declared locally, not just classes.
818+
*/
819+
deprecated class LocalClassDeclStmt = LocalTypeDeclStmt;
820+
803821
/** An explicit `this(...)` constructor invocation. */
804822
class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructorinvocationstmt {
805823
/** Gets an argument of this constructor invocation. */

java/ql/lib/semmle/code/java/Type.qll

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
* (`Interface`).
77
*
88
* Reference types can be at the top level (`TopLevelType`) or nested (`NestedType`).
9-
* Classes can also be local (`LocalClass`) or anonymous (`AnonymousClass`).
10-
* Enumerated types (`EnumType`) are a special kind of class.
9+
* Classes and interfaces can also be local (`LocalClassOrInterface`, `LocalClass`) or anonymous (`AnonymousClass`).
10+
* Enumerated types (`EnumType`) and records (`Record`) are special kinds of classes.
1111
*/
1212

1313
import Member
@@ -269,7 +269,7 @@ predicate declaresMember(Type t, @member m) {
269269
// Since the type `@member` in the dbscheme includes all `@reftype`s,
270270
// anonymous and local classes need to be excluded here.
271271
not m instanceof AnonymousClass and
272-
not m instanceof LocalClass
272+
not m instanceof LocalClassOrInterface
273273
}
274274

275275
/**
@@ -608,20 +608,10 @@ class SrcRefType extends RefType {
608608
}
609609

610610
/** A class declaration. */
611-
class Class extends RefType, @class {
611+
class Class extends ClassOrInterface, @class {
612612
/** Holds if this class is an anonymous class. */
613613
predicate isAnonymous() { isAnonymClass(this, _) }
614614

615-
/** Holds if this class is a local class. */
616-
predicate isLocal() { isLocalClass(this, _) }
617-
618-
/** Holds if this class is package protected, that is, neither public nor private nor protected. */
619-
predicate isPackageProtected() {
620-
not isPrivate() and
621-
not isProtected() and
622-
not isPublic()
623-
}
624-
625615
override RefType getSourceDeclaration() { classes(this, _, _, result) }
626616

627617
/**
@@ -630,11 +620,13 @@ class Class extends RefType, @class {
630620
* Note that a class may inherit annotations from super-classes.
631621
*/
632622
override Annotation getAnAnnotation() {
633-
result = RefType.super.getAnAnnotation()
623+
result = ClassOrInterface.super.getAnAnnotation()
634624
or
635625
exists(AnnotationType tp | tp = result.getType() |
636626
tp.isInherited() and
637-
not exists(Annotation ann | ann = RefType.super.getAnAnnotation() | ann.getType() = tp) and
627+
not exists(Annotation ann | ann = ClassOrInterface.super.getAnAnnotation() |
628+
ann.getType() = tp
629+
) and
638630
result = this.getASupertype().(Class).getAnAnnotation()
639631
)
640632
}
@@ -643,8 +635,6 @@ class Class extends RefType, @class {
643635
}
644636

645637
/**
646-
* PREVIEW FEATURE in Java 14. Subject to removal in a future release.
647-
*
648638
* A record declaration.
649639
*/
650640
class Record extends Class {
@@ -727,12 +717,25 @@ class AnonymousClass extends NestedClass {
727717
override string getAPrimaryQlClass() { result = "AnonymousClass" }
728718
}
729719

730-
/** A local class. */
731-
class LocalClass extends NestedClass {
732-
LocalClass() { this.isLocal() }
720+
/** A local class or interface. */
721+
class LocalClassOrInterface extends NestedType, ClassOrInterface {
722+
LocalClassOrInterface() { this.isLocal() }
733723

734724
/** Gets the statement that declares this local class. */
735-
LocalClassDeclStmt getLocalClassDeclStmt() { isLocalClass(this, result) }
725+
LocalTypeDeclStmt getLocalTypeDeclStmt() { isLocalClassOrInterface(this, result) }
726+
727+
/**
728+
* DEPRECATED: renamed `getLocalTypeDeclStmt` to reflect the fact that
729+
* as of Java 16 interfaces can also be declared locally.
730+
*/
731+
deprecated LocalTypeDeclStmt getLocalClassDeclStmt() { result = this.getLocalTypeDeclStmt() }
732+
733+
override string getAPrimaryQlClass() { result = "LocalClassOrInterface" }
734+
}
735+
736+
/** A local class. */
737+
class LocalClass extends LocalClassOrInterface, NestedClass {
738+
LocalClass() { this.isLocal() }
736739

737740
override string getAPrimaryQlClass() { result = "LocalClass" }
738741
}
@@ -842,34 +845,32 @@ class InnerClass extends NestedClass {
842845
predicate hasEnclosingInstance() {
843846
// JLS 15.9.2. Determining Enclosing Instances
844847
not this.(AnonymousClass).getClassInstanceExpr().isInStaticContext() and
845-
not this.(LocalClass).getLocalClassDeclStmt().getEnclosingCallable().isStatic()
848+
not this.(LocalClass).getLocalTypeDeclStmt().getEnclosingCallable().isStatic()
846849
}
847850
}
848851

849852
/** An interface. */
850-
class Interface extends RefType, @interface {
853+
class Interface extends ClassOrInterface, @interface {
851854
override RefType getSourceDeclaration() { interfaces(this, _, _, result) }
852855

853856
override predicate isAbstract() {
854857
// JLS 9.1.1.1: "Every interface is implicitly abstract"
855858
any()
856859
}
857860

858-
/** Holds if this interface is package protected, that is, neither public nor private nor protected. */
859-
predicate isPackageProtected() {
860-
not isPrivate() and
861-
not isProtected() and
862-
not isPublic()
863-
}
864-
865861
override string getAPrimaryQlClass() { result = "Interface" }
866862
}
867863

868864
/** A class or interface. */
869-
class ClassOrInterface extends RefType {
870-
ClassOrInterface() {
871-
this instanceof Class or
872-
this instanceof Interface
865+
class ClassOrInterface extends RefType, @classorinterface {
866+
/** Holds if this class or interface is local. */
867+
predicate isLocal() { isLocalClassOrInterface(this, _) }
868+
869+
/** Holds if this class or interface is package protected, that is, neither public nor private nor protected. */
870+
predicate isPackageProtected() {
871+
not isPrivate() and
872+
not isProtected() and
873+
not isPublic()
873874
}
874875
}
875876

java/ql/lib/semmle/code/java/dataflow/SSA.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ private module SsaImpl {
238238
/** Gets the definition point of a nested class in the parent scope. */
239239
private ControlFlowNode parentDef(NestedClass nc) {
240240
nc.(AnonymousClass).getClassInstanceExpr() = result or
241-
nc.(LocalClass).getLocalClassDeclStmt() = result
241+
nc.(LocalClass).getLocalTypeDeclStmt() = result
242242
}
243243

244244
/**

0 commit comments

Comments
 (0)