Skip to content

Commit 31ec798

Browse files
authored
Merge pull request #4631 from luchua-bc/java-nfe-library
Java: Factor NumberFormatException out into a library file
2 parents 3215f50 + d765c7b commit 31ec798

File tree

2 files changed

+74
-65
lines changed

2 files changed

+74
-65
lines changed

java/ql/src/Violations of Best Practice/Exception Handling/NumberFormatException.ql

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -11,71 +11,7 @@
1111
*/
1212

1313
import java
14-
15-
private class SpecialMethodAccess extends MethodAccess {
16-
predicate isValueOfMethod(string klass) {
17-
this.getMethod().getName() = "valueOf" and
18-
this.getQualifier().getType().(RefType).hasQualifiedName("java.lang", klass) and
19-
this.getAnArgument().getType().(RefType).hasQualifiedName("java.lang", "String")
20-
}
21-
22-
predicate isParseMethod(string klass, string name) {
23-
this.getMethod().getName() = name and
24-
this.getQualifier().getType().(RefType).hasQualifiedName("java.lang", klass)
25-
}
26-
27-
predicate throwsNFE() {
28-
this.isParseMethod("Byte", "parseByte") or
29-
this.isParseMethod("Short", "parseShort") or
30-
this.isParseMethod("Integer", "parseInt") or
31-
this.isParseMethod("Long", "parseLong") or
32-
this.isParseMethod("Float", "parseFloat") or
33-
this.isParseMethod("Double", "parseDouble") or
34-
this.isParseMethod("Byte", "decode") or
35-
this.isParseMethod("Short", "decode") or
36-
this.isParseMethod("Integer", "decode") or
37-
this.isParseMethod("Long", "decode") or
38-
this.isValueOfMethod("Byte") or
39-
this.isValueOfMethod("Short") or
40-
this.isValueOfMethod("Integer") or
41-
this.isValueOfMethod("Long") or
42-
this.isValueOfMethod("Float") or
43-
this.isValueOfMethod("Double")
44-
}
45-
}
46-
47-
private class SpecialClassInstanceExpr extends ClassInstanceExpr {
48-
predicate isStringConstructor(string klass) {
49-
this.getType().(RefType).hasQualifiedName("java.lang", klass) and
50-
this.getAnArgument().getType().(RefType).hasQualifiedName("java.lang", "String") and
51-
this.getNumArgument() = 1
52-
}
53-
54-
predicate throwsNFE() {
55-
this.isStringConstructor("Byte") or
56-
this.isStringConstructor("Short") or
57-
this.isStringConstructor("Integer") or
58-
this.isStringConstructor("Long") or
59-
this.isStringConstructor("Float") or
60-
this.isStringConstructor("Double")
61-
}
62-
}
63-
64-
class NumberFormatException extends RefType {
65-
NumberFormatException() { this.hasQualifiedName("java.lang", "NumberFormatException") }
66-
}
67-
68-
private predicate catchesNFE(TryStmt t) {
69-
exists(CatchClause cc, LocalVariableDeclExpr v |
70-
t.getACatchClause() = cc and
71-
cc.getVariable() = v and
72-
v.getType().(RefType).getASubtype*() instanceof NumberFormatException
73-
)
74-
}
75-
76-
private predicate throwsNFE(Expr e) {
77-
e.(SpecialClassInstanceExpr).throwsNFE() or e.(SpecialMethodAccess).throwsNFE()
78-
}
14+
import semmle.code.java.NumberFormatException
7915

8016
from Expr e
8117
where
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/** Provides classes and predicates for reasoning about `java.lang.NumberFormatException`. */
2+
3+
import java
4+
5+
/** A call to a string to number conversion. */
6+
private class SpecialMethodAccess extends MethodAccess {
7+
predicate isValueOfMethod(string klass) {
8+
this.getMethod().getName() = "valueOf" and
9+
this.getQualifier().getType().(RefType).hasQualifiedName("java.lang", klass) and
10+
this.getAnArgument().getType().(RefType).hasQualifiedName("java.lang", "String")
11+
}
12+
13+
predicate isParseMethod(string klass, string name) {
14+
this.getMethod().getName() = name and
15+
this.getQualifier().getType().(RefType).hasQualifiedName("java.lang", klass)
16+
}
17+
18+
predicate throwsNFE() {
19+
this.isParseMethod("Byte", "parseByte") or
20+
this.isParseMethod("Short", "parseShort") or
21+
this.isParseMethod("Integer", "parseInt") or
22+
this.isParseMethod("Long", "parseLong") or
23+
this.isParseMethod("Float", "parseFloat") or
24+
this.isParseMethod("Double", "parseDouble") or
25+
this.isParseMethod("Byte", "decode") or
26+
this.isParseMethod("Short", "decode") or
27+
this.isParseMethod("Integer", "decode") or
28+
this.isParseMethod("Long", "decode") or
29+
this.isValueOfMethod("Byte") or
30+
this.isValueOfMethod("Short") or
31+
this.isValueOfMethod("Integer") or
32+
this.isValueOfMethod("Long") or
33+
this.isValueOfMethod("Float") or
34+
this.isValueOfMethod("Double")
35+
}
36+
}
37+
38+
/** A `ClassInstanceExpr` that constructs a number from its string representation. */
39+
private class SpecialClassInstanceExpr extends ClassInstanceExpr {
40+
predicate isStringConstructor(string klass) {
41+
this.getType().(RefType).hasQualifiedName("java.lang", klass) and
42+
this.getAnArgument().getType().(RefType).hasQualifiedName("java.lang", "String") and
43+
this.getNumArgument() = 1
44+
}
45+
46+
predicate throwsNFE() {
47+
this.isStringConstructor("Byte") or
48+
this.isStringConstructor("Short") or
49+
this.isStringConstructor("Integer") or
50+
this.isStringConstructor("Long") or
51+
this.isStringConstructor("Float") or
52+
this.isStringConstructor("Double")
53+
}
54+
}
55+
56+
/** The class `java.lang.NumberFormatException`. */
57+
class NumberFormatException extends RefType {
58+
NumberFormatException() { this.hasQualifiedName("java.lang", "NumberFormatException") }
59+
}
60+
61+
/** Holds if `java.lang.NumberFormatException` is caught. */
62+
predicate catchesNFE(TryStmt t) {
63+
exists(CatchClause cc, LocalVariableDeclExpr v |
64+
t.getACatchClause() = cc and
65+
cc.getVariable() = v and
66+
v.getType().(RefType).getASubtype*() instanceof NumberFormatException
67+
)
68+
}
69+
70+
/** Holds if `java.lang.NumberFormatException` can be thrown. */
71+
predicate throwsNFE(Expr e) {
72+
e.(SpecialClassInstanceExpr).throwsNFE() or e.(SpecialMethodAccess).throwsNFE()
73+
}

0 commit comments

Comments
 (0)