Skip to content

Commit 591ac38

Browse files
authored
Merge pull request github#5591 from Marcono1234/marcono1234/member-nested-type
Java: Add MemberType
2 parents 54c79bf + 2965a1f commit 591ac38

File tree

5 files changed

+43
-18
lines changed

5 files changed

+43
-18
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* A CodeQL class `MemberType` is introduced to describe nested classes. Its `getQualifiedName` method returns `$`-delimited nested type names (for example, `mypackage.Outer$Middle$Inner`), where previously the same type would be named differently depending on whether it was addressed as a `NestedType` or a `Member`.

java/ql/src/Performance/InnerClassCouldBeStatic.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ predicate potentiallyStatic(InnerClass c) {
100100
m = a.getEnclosingCallable() and
101101
m.getDeclaringType() = c
102102
) and
103-
not c instanceof AnonymousClass and
104-
not c instanceof LocalClass and
103+
c instanceof MemberType and
105104
forall(
106105
InnerClass other // If nested and non-static, ...
107106
|

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,7 @@ final class ClassInterfaceNode extends ElementNode {
433433
or
434434
result.(FieldDeclaration).getAField().getDeclaringType() = ty
435435
or
436-
result.(NestedType).getEnclosingType().getSourceDeclaration() = ty and
437-
not result instanceof AnonymousClass and
438-
not result instanceof LocalClass
436+
result.(MemberType).getEnclosingType().getSourceDeclaration() = ty
439437
or
440438
isInitBlock(ty, result)
441439
}

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

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,12 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
517517
/** Holds if this is a top-level type, which is not nested inside any other types. */
518518
predicate isTopLevel() { this instanceof TopLevelType }
519519

520-
/** Holds if this type is declared in a specified package with the specified name. */
520+
/**
521+
* Holds if this type is declared in a specified package with the specified name.
522+
*
523+
* For nested types the name of the nested type is prefixed with a `$` and appended
524+
* to the name of the enclosing type, which might be a nested type as well.
525+
*/
521526
predicate hasQualifiedName(string package, string type) {
522527
this.getPackage().hasName(package) and type = this.nestedName()
523528
}
@@ -532,15 +537,26 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
532537
}
533538

534539
/**
535-
* Gets the qualified name of this type.
540+
* Gets the qualified name of this type, consisting of the package name followed by
541+
* a `.` and the name of this type.
542+
*
543+
* For nested types the name of the nested type is prefixed with a `$` and appended
544+
* to the name of the enclosing type, which might be a nested type as well. For example:
545+
* `java.lang.Thread$State`.
536546
*/
537547
string getQualifiedName() {
538548
exists(string pkgName | pkgName = getPackage().getName() |
539549
if pkgName = "" then result = nestedName() else result = pkgName + "." + nestedName()
540550
)
541551
}
542552

543-
/** Gets the nested name of this type. */
553+
/**
554+
* Gets the nested name of this type.
555+
*
556+
* If this type is not a nested type, the result is the same as `getName()`.
557+
* Otherwise the name of the nested type is prefixed with a `$` and appended to
558+
* the name of the enclosing type, which might be a nested type as well.
559+
*/
544560
string nestedName() {
545561
not this instanceof NestedType and result = this.getName()
546562
or
@@ -788,6 +804,21 @@ class NestedType extends RefType {
788804
}
789805
}
790806

807+
/**
808+
* A nested type which is a direct member of the enclosing type,
809+
* that is, neither an anonymous nor local class.
810+
*/
811+
class MemberType extends NestedType, Member {
812+
/**
813+
* Gets the qualified name of this member type.
814+
*
815+
* The qualified name consists of the package name, a `.`, the name of the declaring
816+
* type (which might be a nested or member type as well), followed by a `$` and the
817+
* name of this member type. For example: `java.lang.Thread$State`.
818+
*/
819+
override string getQualifiedName() { result = NestedType.super.getQualifiedName() }
820+
}
821+
791822
/**
792823
* A class declared within another type.
793824
*
@@ -797,8 +828,9 @@ class NestedType extends RefType {
797828
class NestedClass extends NestedType, Class { }
798829

799830
/**
800-
* An inner class is a nested class that is neither
801-
* explicitly nor implicitly declared static.
831+
* An inner class is a nested class that is neither explicitly nor
832+
* implicitly declared static. This includes anonymous and local
833+
* classes.
802834
*/
803835
class InnerClass extends NestedClass {
804836
InnerClass() { not this.isStatic() }

java/ql/src/semmle/code/java/frameworks/play/Play.qll

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,8 @@ class PlayAddCsrfTokenAnnotation extends Annotation {
4444
/**
4545
* The type `play.libs.F.Promise<Result>`.
4646
*/
47-
class PlayAsyncResultPromise extends Member {
48-
PlayAsyncResultPromise() {
49-
exists(Class c |
50-
c.hasQualifiedName("play.libs", "F") and
51-
this = c.getAMember() and
52-
this.getQualifiedName() = "F.Promise<Result>"
53-
)
54-
}
47+
class PlayAsyncResultPromise extends MemberType {
48+
PlayAsyncResultPromise() { hasQualifiedName("play.libs", "F$Promise<Result>") }
5549
}
5650

5751
/**

0 commit comments

Comments
 (0)