diff --git a/java/ql/src/Complexity/ComplexCondition.ql b/java/ql/src/Complexity/ComplexCondition.ql
index e8f7b67f35e..0a03abb0adb 100644
--- a/java/ql/src/Complexity/ComplexCondition.ql
+++ b/java/ql/src/Complexity/ComplexCondition.ql
@@ -13,7 +13,10 @@ import java
predicate nontrivialLogicalOperator(BinaryExpr e) {
e instanceof LogicExpr and
- not e.getParent().(Expr).getKind() = e.getKind()
+ (
+ not e.getParent().(Expr).getKind() = e.getKind() or
+ e.isParenthesized()
+ )
}
Expr getSimpleParent(Expr e) {
diff --git a/java/ql/src/Likely Bugs/Arithmetic/MultiplyRemainder.ql b/java/ql/src/Likely Bugs/Arithmetic/MultiplyRemainder.ql
index 8653f9cc8d5..8992d1753d9 100644
--- a/java/ql/src/Likely Bugs/Arithmetic/MultiplyRemainder.ql
+++ b/java/ql/src/Likely Bugs/Arithmetic/MultiplyRemainder.ql
@@ -12,8 +12,9 @@
import java
-from MulExpr e
+from MulExpr e, RemExpr lhs
where
- e.getLeftOperand() instanceof RemExpr and
+ e.getLeftOperand() = lhs and
+ not lhs.isParenthesized() and
e.getRightOperand().getType().hasName("int")
select e, "Result of a remainder operation multiplied by an integer."
diff --git a/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql b/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql
index 12218a0ac49..db806ef760c 100644
--- a/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql
+++ b/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql
@@ -120,12 +120,24 @@ predicate endOfBinaryLhs(BinaryExpr expr, int line, int col) {
)
}
+/** Compute the number of parenthesis characters next to the operator. */
+int getParensNextToOp(BinaryExpr expr) {
+ exists(Expr left, Expr right, int pleft, int pright |
+ left = expr.getLeftOperand() and
+ right = expr.getRightOperand() and
+ (if left.isParenthesized() then isParenthesized(left, pleft) else pleft = 0) and
+ (if right.isParenthesized() then isParenthesized(right, pright) else pright = 0) and
+ result = pleft + pright
+ )
+}
+
/** Compute whitespace around the operator. */
int operatorWS(BinaryExpr expr) {
- exists(int line, int lcol, int rcol |
+ exists(int line, int lcol, int rcol, int parens |
endOfBinaryLhs(expr, line, lcol) and
startOfBinaryRhs(expr, line, rcol) and
- result = rcol - lcol + 1 - expr.getOp().length()
+ parens = getParensNextToOp(expr) and
+ result = rcol - lcol + 1 - expr.getOp().length() - parens
)
}
@@ -133,7 +145,8 @@ int operatorWS(BinaryExpr expr) {
predicate interestingNesting(BinaryExpr inner, BinaryExpr outer) {
inner = outer.getAChildExpr() and
not inner instanceof AssocNestedExpr and
- not inner instanceof HarmlessNestedExpr
+ not inner instanceof HarmlessNestedExpr and
+ not inner.isParenthesized()
}
from BinaryExpr inner, BinaryExpr outer, int wsouter, int wsinner
diff --git a/java/ql/src/config/semmlecode.dbscheme b/java/ql/src/config/semmlecode.dbscheme
index e7706df98aa..054d7e823b2 100755
--- a/java/ql/src/config/semmlecode.dbscheme
+++ b/java/ql/src/config/semmlecode.dbscheme
@@ -516,6 +516,11 @@ statementEnclosingExpr(
int statement_id: @stmt ref
);
+isParenthesized(
+ unique int id: @expr ref,
+ int parentheses: int ref
+);
+
case @expr.kind of
1 = @arrayaccess
| 2 = @arraycreationexpr
@@ -570,7 +575,7 @@ case @expr.kind of
| 51 = @castexpr
| 52 = @newexpr
| 53 = @conditionalexpr
-| 54 = @parexpr
+| 54 = @parexpr // deprecated
| 55 = @instanceofexpr
| 56 = @localvariabledeclexpr
| 57 = @typeliteral
diff --git a/java/ql/src/config/semmlecode.dbscheme.stats b/java/ql/src/config/semmlecode.dbscheme.stats
index 22e7ff7e830..165db4674b5 100644
--- a/java/ql/src/config/semmlecode.dbscheme.stats
+++ b/java/ql/src/config/semmlecode.dbscheme.stats
@@ -18307,6 +18307,59 @@
+isParenthesized
+76010
+
+
+id
+76010
+
+
+parentheses
+2
+
+
+
+
+id
+parentheses
+
+
+12
+
+
+1
+2
+76010
+
+
+
+
+
+
+parentheses
+id
+
+
+12
+
+
+30
+31
+1
+
+
+75980
+75981
+1
+
+
+
+
+
+
+
+
callableBinding
1437798
diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll
index 313a8eb6aa8..3b95094e46e 100755
--- a/java/ql/src/semmle/code/java/Expr.qll
+++ b/java/ql/src/semmle/code/java/Expr.qll
@@ -95,6 +95,9 @@ class Expr extends ExprParent, @expr {
or
exists(LambdaExpr lam | lam.asMethod() = getEnclosingCallable() and lam.isInStaticContext())
}
+
+ /** Holds if this expression is parenthesized. */
+ predicate isParenthesized() { isParenthesized(this, _) }
}
/**
@@ -1330,7 +1333,11 @@ class VarAccess extends Expr, @varaccess {
/** Gets a printable representation of this expression. */
override string toString() {
- result = this.getQualifier().toString() + "." + this.getVariable().getName()
+ exists(Expr q | q = this.getQualifier() |
+ if q.isParenthesized()
+ then result = "(...)." + this.getVariable().getName()
+ else result = q.toString() + "." + this.getVariable().getName()
+ )
or
not this.hasQualifier() and result = this.getVariable().getName()
}
diff --git a/java/ql/test/library-tests/constants/CompileTimeConstantExpr.expected b/java/ql/test/library-tests/constants/CompileTimeConstantExpr.expected
index 49a0c2285d4..f5e508b4a3c 100644
--- a/java/ql/test/library-tests/constants/CompileTimeConstantExpr.expected
+++ b/java/ql/test/library-tests/constants/CompileTimeConstantExpr.expected
@@ -7,10 +7,8 @@
| constants/Constants.java:15:15:15:37 | ... + ... |
| constants/Constants.java:15:37:15:37 | 1 |
| constants/Constants.java:16:23:16:41 | Initializers.SFIELD |
-| constants/Constants.java:18:15:18:18 | (...) |
| constants/Constants.java:18:16:18:17 | 12 |
| constants/Constants.java:19:19:19:28 | "a string" |
-| constants/Constants.java:20:17:20:23 | (...) |
| constants/Constants.java:20:17:20:31 | ...?...:... |
| constants/Constants.java:20:18:20:18 | 3 |
| constants/Constants.java:20:18:20:22 | ... < ... |
diff --git a/java/ql/test/library-tests/constants/getIntValue.expected b/java/ql/test/library-tests/constants/getIntValue.expected
index acf4117a0ac..bee36f5122b 100644
--- a/java/ql/test/library-tests/constants/getIntValue.expected
+++ b/java/ql/test/library-tests/constants/getIntValue.expected
@@ -31,7 +31,7 @@
| constants/Values.java:67:27:67:33 | ... & ... | 42 |
| constants/Values.java:68:26:68:32 | ... \| ... | 42 |
| constants/Values.java:69:27:69:33 | ... ^ ... | 42 |
-| constants/Values.java:83:19:83:22 | (...) | 42 |
+| constants/Values.java:83:20:83:21 | 42 | 42 |
| constants/Values.java:86:25:86:35 | final_field | 42 |
| constants/Values.java:87:33:87:34 | 42 | 42 |
| constants/Values.java:88:25:88:35 | final_local | 42 |
diff --git a/java/ql/test/query-tests/Nullness/NullExprDeref.expected b/java/ql/test/query-tests/Nullness/NullExprDeref.expected
index c8177626302..00aec204617 100644
--- a/java/ql/test/query-tests/Nullness/NullExprDeref.expected
+++ b/java/ql/test/query-tests/Nullness/NullExprDeref.expected
@@ -1 +1 @@
-| ExprDeref.java:7:12:7:34 | (...) | This expression is dereferenced and may be null. |
+| ExprDeref.java:7:13:7:33 | ...?...:... | This expression is dereferenced and may be null. |
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/annotValue.ql b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/annotValue.ql
new file mode 100644
index 00000000000..60836f7f418
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/annotValue.ql
@@ -0,0 +1,27 @@
+class Annotation extends @annotation {
+ string toString() { result = "annotation" }
+}
+
+class Method extends @method {
+ string toString() { result = "method" }
+}
+
+class Expr extends @expr {
+ string toString() { result = "expr" }
+}
+
+class ParExpr extends Expr, @parexpr {
+ override string toString() { result = "(...)" }
+}
+
+predicate parExprGetExpr(ParExpr pe, Expr e) { exprs(e, _, _, pe, _) }
+
+from Annotation parentid, Method id2, Expr oldvalue, Expr value
+where
+ annotValue(parentid, id2, oldvalue) and
+ if oldvalue instanceof ParExpr
+ then
+ parExprGetExpr+(oldvalue, value) and
+ not value instanceof ParExpr
+ else value = oldvalue
+select parentid, id2, value
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/callableEnclosingExpr.ql b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/callableEnclosingExpr.ql
new file mode 100644
index 00000000000..ba1e29ef8e4
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/callableEnclosingExpr.ql
@@ -0,0 +1,17 @@
+class Expr extends @expr {
+ string toString() { result = "expr" }
+}
+
+class ParExpr extends Expr, @parexpr {
+ override string toString() { result = "(...)" }
+}
+
+class Callable extends @callable {
+ string toString() { result = "callable" }
+}
+
+from Expr id, Callable c
+where
+ callableEnclosingExpr(id, c) and
+ not id instanceof ParExpr
+select id, c
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/exprs.ql b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/exprs.ql
new file mode 100644
index 00000000000..9c3fffdc99e
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/exprs.ql
@@ -0,0 +1,38 @@
+class ExprParent extends @exprparent {
+ string toString() { result = "exprparent" }
+}
+
+class Expr extends ExprParent, @expr {
+ override string toString() { result = "expr" }
+}
+
+class ParExpr extends Expr, @parexpr {
+ override string toString() { result = "(...)" }
+}
+
+class Type extends @type {
+ string toString() { result = "type" }
+}
+
+predicate astlink(ExprParent parent, Expr e, int idx, int parens) {
+ exprs(e, _, _, parent, idx) and
+ parens = 0 and
+ not parent instanceof ParExpr and
+ e instanceof ParExpr
+ or
+ exists(ParExpr pe |
+ exprs(e, _, _, pe, _) and
+ astlink(parent, pe, idx, parens - 1)
+ )
+}
+
+from Expr id, int kind, Type typeid, ExprParent oldparent, ExprParent parent, int oldidx, int idx
+where
+ exprs(id, kind, typeid, oldparent, oldidx) and
+ not id instanceof ParExpr and
+ if oldparent instanceof ParExpr
+ then astlink(parent, id, idx, _)
+ else (
+ parent = oldparent and idx = oldidx
+ )
+select id, kind, typeid, parent, idx
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/hasLocation.ql b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/hasLocation.ql
new file mode 100644
index 00000000000..704c355f5d3
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/hasLocation.ql
@@ -0,0 +1,17 @@
+class Locatable extends @locatable {
+ string toString() { result = "locatable" }
+}
+
+class Location extends @location {
+ string toString() { result = "location" }
+}
+
+class ParExpr extends Locatable, @parexpr {
+ override string toString() { result = "(...)" }
+}
+
+from Locatable locatable, Location location
+where
+ hasLocation(locatable, location) and
+ not locatable instanceof ParExpr
+select locatable, location
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/isParenthesized.ql b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/isParenthesized.ql
new file mode 100644
index 00000000000..5fce41b94e8
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/isParenthesized.ql
@@ -0,0 +1,29 @@
+class ExprParent extends @exprparent {
+ string toString() { result = "exprparent" }
+}
+
+class Expr extends ExprParent, @expr {
+ override string toString() { result = "expr" }
+}
+
+class ParExpr extends Expr, @parexpr {
+ override string toString() { result = "(...)" }
+}
+
+predicate astlink(ExprParent parent, Expr e, int idx, int parens) {
+ exprs(e, _, _, parent, idx) and
+ parens = 0 and
+ not parent instanceof ParExpr and
+ e instanceof ParExpr
+ or
+ exists(ParExpr pe |
+ exprs(e, _, _, pe, _) and
+ astlink(parent, pe, idx, parens - 1)
+ )
+}
+
+from Expr e, int parentheses
+where
+ astlink(_, e, _, parentheses) and
+ not e instanceof ParExpr
+select e, parentheses
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/numlines.ql b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/numlines.ql
new file mode 100644
index 00000000000..716e940cfb5
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/numlines.ql
@@ -0,0 +1,13 @@
+class Sourceline extends @sourceline {
+ string toString() { result = "sourceline" }
+}
+
+class ParExpr extends Sourceline, @parexpr {
+ override string toString() { result = "(...)" }
+}
+
+from Sourceline id, int l, int code, int comm
+where
+ numlines(id, l, code, comm) and
+ not id instanceof ParExpr
+select id, l, code, comm
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/old.dbscheme b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/old.dbscheme
new file mode 100755
index 00000000000..e7706df98aa
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/old.dbscheme
@@ -0,0 +1,945 @@
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * javac A.java B.java C.java
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ /**
+ * An invocation of the compiler. Note that more than one file may
+ * be compiled per invocation. For example, this command compiles
+ * three source files:
+ *
+ * javac A.java B.java C.java
+ */
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * javac A.java B.java C.java
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | *path to extractor*
+ * 1 | `--javac-args`
+ * 2 | A.java
+ * 3 | B.java
+ * 4 | C.java
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * javac A.java B.java C.java
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | A.java
+ * 1 | B.java
+ * 2 | C.java
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+/*
+ * External artifacts
+ */
+
+externalData(
+ int id : @externalDataElement,
+ string path : string ref,
+ int column: int ref,
+ string value : string ref
+);
+
+snapshotDate(
+ unique date snapshotDate : date ref
+);
+
+sourceLocationPrefix(
+ string prefix : string ref
+);
+
+/*
+ * Duplicate code
+ */
+
+duplicateCode(
+ unique int id : @duplication,
+ string relativePath : string ref,
+ int equivClass : int ref
+);
+
+similarCode(
+ unique int id : @similarity,
+ string relativePath : string ref,
+ int equivClass : int ref
+);
+
+@duplication_or_similarity = @duplication | @similarity
+
+tokens(
+ int id : @duplication_or_similarity ref,
+ int offset : int ref,
+ int beginLine : int ref,
+ int beginColumn : int ref,
+ int endLine : int ref,
+ int endColumn : int ref
+);
+
+/*
+ * Locations and files
+ */
+
+@location = @location_default ;
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+hasLocation(
+ int locatableid: @locatable ref,
+ int id: @location ref
+);
+
+@sourceline = @locatable ;
+
+#keyset[element_id]
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref
+);
+
+files(
+ unique int id: @file,
+ string name: string ref,
+ string simple: string ref,
+ string ext: string ref,
+ int fromSource: int ref // deprecated
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref,
+ string simple: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+/*
+ * Java
+ */
+
+cupackage(
+ unique int id: @file ref,
+ int packageid: @package ref
+);
+
+#keyset[fileid,keyName]
+jarManifestMain(
+ int fileid: @file ref,
+ string keyName: string ref,
+ string value: string ref
+);
+
+#keyset[fileid,entryName,keyName]
+jarManifestEntries(
+ int fileid: @file ref,
+ string entryName: string ref,
+ string keyName: string ref,
+ string value: string ref
+);
+
+packages(
+ unique int id: @package,
+ string nodeName: string ref
+);
+
+primitives(
+ unique int id: @primitive,
+ string nodeName: string ref
+);
+
+modifiers(
+ unique int id: @modifier,
+ string nodeName: string ref
+);
+
+classes(
+ unique int id: @class,
+ string nodeName: string ref,
+ int parentid: @package ref,
+ int sourceid: @class ref
+);
+
+interfaces(
+ unique int id: @interface,
+ string nodeName: string ref,
+ int parentid: @package ref,
+ int sourceid: @interface ref
+);
+
+fielddecls(
+ unique int id: @fielddecl,
+ int parentid: @reftype ref
+);
+
+#keyset[fieldId] #keyset[fieldDeclId,pos]
+fieldDeclaredIn(
+ int fieldId: @field ref,
+ int fieldDeclId: @fielddecl ref,
+ int pos: int ref
+);
+
+fields(
+ unique int id: @field,
+ string nodeName: string ref,
+ int typeid: @type ref,
+ int parentid: @reftype ref,
+ int sourceid: @field ref
+);
+
+constrs(
+ unique int id: @constructor,
+ string nodeName: string ref,
+ string signature: string ref,
+ int typeid: @type ref,
+ int parentid: @reftype ref,
+ int sourceid: @constructor ref
+);
+
+methods(
+ unique int id: @method,
+ string nodeName: string ref,
+ string signature: string ref,
+ int typeid: @type ref,
+ int parentid: @reftype ref,
+ int sourceid: @method ref
+);
+
+#keyset[parentid,pos]
+params(
+ unique int id: @param,
+ int typeid: @type ref,
+ int pos: int ref,
+ int parentid: @callable ref,
+ int sourceid: @param ref
+);
+
+paramName(
+ unique int id: @param ref,
+ string nodeName: string ref
+);
+
+isVarargsParam(
+ int param: @param ref
+);
+
+exceptions(
+ unique int id: @exception,
+ int typeid: @type ref,
+ int parentid: @callable ref
+);
+
+isAnnotType(
+ int interfaceid: @interface ref
+);
+
+isAnnotElem(
+ int methodid: @method ref
+);
+
+annotValue(
+ int parentid: @annotation ref,
+ int id2: @method ref,
+ unique int value: @expr ref
+);
+
+isEnumType(
+ int classid: @class ref
+);
+
+isEnumConst(
+ int fieldid: @field ref
+);
+
+#keyset[parentid,pos]
+typeVars(
+ unique int id: @typevariable,
+ string nodeName: string ref,
+ int pos: int ref,
+ int kind: int ref, // deprecated
+ int parentid: @typeorcallable ref
+);
+
+wildcards(
+ unique int id: @wildcard,
+ string nodeName: string ref,
+ int kind: int ref
+);
+
+#keyset[parentid,pos]
+typeBounds(
+ unique int id: @typebound,
+ int typeid: @reftype ref,
+ int pos: int ref,
+ int parentid: @boundedtype ref
+);
+
+#keyset[parentid,pos]
+typeArgs(
+ int argumentid: @reftype ref,
+ int pos: int ref,
+ int parentid: @typeorcallable ref
+);
+
+isParameterized(
+ int memberid: @member ref
+);
+
+isRaw(
+ int memberid: @member ref
+);
+
+erasure(
+ unique int memberid: @member ref,
+ int erasureid: @member ref
+);
+
+#keyset[classid] #keyset[parent]
+isAnonymClass(
+ int classid: @class ref,
+ int parent: @classinstancexpr ref
+);
+
+#keyset[classid] #keyset[parent]
+isLocalClass(
+ int classid: @class ref,
+ int parent: @localclassdeclstmt ref
+);
+
+isDefConstr(
+ int constructorid: @constructor ref
+);
+
+#keyset[exprId]
+lambdaKind(
+ int exprId: @lambdaexpr ref,
+ int bodyKind: int ref
+);
+
+arrays(
+ unique int id: @array,
+ string nodeName: string ref,
+ int elementtypeid: @type ref,
+ int dimension: int ref,
+ int componenttypeid: @type ref
+);
+
+enclInReftype(
+ unique int child: @reftype ref,
+ int parent: @reftype ref
+);
+
+extendsReftype(
+ int id1: @reftype ref,
+ int id2: @classorinterface ref
+);
+
+implInterface(
+ int id1: @classorarray ref,
+ int id2: @interface ref
+);
+
+hasModifier(
+ int id1: @modifiable ref,
+ int id2: @modifier ref
+);
+
+imports(
+ unique int id: @import,
+ int holder: @typeorpackage ref,
+ string name: string ref,
+ int kind: int ref
+);
+
+#keyset[parent,idx]
+stmts(
+ unique int id: @stmt,
+ int kind: int ref,
+ int parent: @stmtparent ref,
+ int idx: int ref,
+ int bodydecl: @callable ref
+);
+
+@stmtparent = @callable | @stmt | @switchexpr;
+
+case @stmt.kind of
+ 0 = @block
+| 1 = @ifstmt
+| 2 = @forstmt
+| 3 = @enhancedforstmt
+| 4 = @whilestmt
+| 5 = @dostmt
+| 6 = @trystmt
+| 7 = @switchstmt
+| 8 = @synchronizedstmt
+| 9 = @returnstmt
+| 10 = @throwstmt
+| 11 = @breakstmt
+| 12 = @continuestmt
+| 13 = @emptystmt
+| 14 = @exprstmt
+| 15 = @labeledstmt
+| 16 = @assertstmt
+| 17 = @localvariabledeclstmt
+| 18 = @localclassdeclstmt
+| 19 = @constructorinvocationstmt
+| 20 = @superconstructorinvocationstmt
+| 21 = @case
+| 22 = @catchclause
+| 23 = @yieldstmt
+;
+
+#keyset[parent,idx]
+exprs(
+ unique int id: @expr,
+ int kind: int ref,
+ int typeid: @type ref,
+ int parent: @exprparent ref,
+ int idx: int ref
+);
+
+callableEnclosingExpr(
+ unique int id: @expr ref,
+ int callable_id: @callable ref
+);
+
+statementEnclosingExpr(
+ unique int id: @expr ref,
+ int statement_id: @stmt ref
+);
+
+case @expr.kind of
+ 1 = @arrayaccess
+| 2 = @arraycreationexpr
+| 3 = @arrayinit
+| 4 = @assignexpr
+| 5 = @assignaddexpr
+| 6 = @assignsubexpr
+| 7 = @assignmulexpr
+| 8 = @assigndivexpr
+| 9 = @assignremexpr
+| 10 = @assignandexpr
+| 11 = @assignorexpr
+| 12 = @assignxorexpr
+| 13 = @assignlshiftexpr
+| 14 = @assignrshiftexpr
+| 15 = @assignurshiftexpr
+| 16 = @booleanliteral
+| 17 = @integerliteral
+| 18 = @longliteral
+| 19 = @floatingpointliteral
+| 20 = @doubleliteral
+| 21 = @characterliteral
+| 22 = @stringliteral
+| 23 = @nullliteral
+| 24 = @mulexpr
+| 25 = @divexpr
+| 26 = @remexpr
+| 27 = @addexpr
+| 28 = @subexpr
+| 29 = @lshiftexpr
+| 30 = @rshiftexpr
+| 31 = @urshiftexpr
+| 32 = @andbitexpr
+| 33 = @orbitexpr
+| 34 = @xorbitexpr
+| 35 = @andlogicalexpr
+| 36 = @orlogicalexpr
+| 37 = @ltexpr
+| 38 = @gtexpr
+| 39 = @leexpr
+| 40 = @geexpr
+| 41 = @eqexpr
+| 42 = @neexpr
+| 43 = @postincexpr
+| 44 = @postdecexpr
+| 45 = @preincexpr
+| 46 = @predecexpr
+| 47 = @minusexpr
+| 48 = @plusexpr
+| 49 = @bitnotexpr
+| 50 = @lognotexpr
+| 51 = @castexpr
+| 52 = @newexpr
+| 53 = @conditionalexpr
+| 54 = @parexpr
+| 55 = @instanceofexpr
+| 56 = @localvariabledeclexpr
+| 57 = @typeliteral
+| 58 = @thisaccess
+| 59 = @superaccess
+| 60 = @varaccess
+| 61 = @methodaccess
+| 62 = @unannotatedtypeaccess
+| 63 = @arraytypeaccess
+| 64 = @packageaccess
+| 65 = @wildcardtypeaccess
+| 66 = @declannotation
+| 67 = @uniontypeaccess
+| 68 = @lambdaexpr
+| 69 = @memberref
+| 70 = @annotatedtypeaccess
+| 71 = @typeannotation
+| 72 = @intersectiontypeaccess
+| 73 = @switchexpr
+;
+
+@classinstancexpr = @newexpr | @lambdaexpr | @memberref
+
+@annotation = @declannotation | @typeannotation
+@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess
+
+@assignment = @assignexpr
+ | @assignop;
+
+@unaryassignment = @postincexpr
+ | @postdecexpr
+ | @preincexpr
+ | @predecexpr;
+
+@assignop = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ | @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ | @assignurshiftexpr;
+
+@literal = @booleanliteral
+ | @integerliteral
+ | @longliteral
+ | @floatingpointliteral
+ | @doubleliteral
+ | @characterliteral
+ | @stringliteral
+ | @nullliteral;
+
+@binaryexpr = @mulexpr
+ | @divexpr
+ | @remexpr
+ | @addexpr
+ | @subexpr
+ | @lshiftexpr
+ | @rshiftexpr
+ | @urshiftexpr
+ | @andbitexpr
+ | @orbitexpr
+ | @xorbitexpr
+ | @andlogicalexpr
+ | @orlogicalexpr
+ | @ltexpr
+ | @gtexpr
+ | @leexpr
+ | @geexpr
+ | @eqexpr
+ | @neexpr;
+
+@unaryexpr = @postincexpr
+ | @postdecexpr
+ | @preincexpr
+ | @predecexpr
+ | @minusexpr
+ | @plusexpr
+ | @bitnotexpr
+ | @lognotexpr;
+
+@caller = @classinstancexpr
+ | @methodaccess
+ | @constructorinvocationstmt
+ | @superconstructorinvocationstmt;
+
+callableBinding(
+ unique int callerid: @caller ref,
+ int callee: @callable ref
+);
+
+memberRefBinding(
+ unique int id: @expr ref,
+ int callable: @callable ref
+);
+
+@exprparent = @stmt | @expr | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable;
+
+variableBinding(
+ unique int expr: @varaccess ref,
+ int variable: @variable ref
+);
+
+@variable = @localscopevariable | @field;
+
+@localscopevariable = @localvar | @param;
+
+localvars(
+ unique int id: @localvar,
+ string nodeName: string ref,
+ int typeid: @type ref,
+ int parentid: @localvariabledeclexpr ref
+);
+
+@namedexprorstmt = @breakstmt
+ | @continuestmt
+ | @labeledstmt
+ | @literal;
+
+namestrings(
+ string name: string ref,
+ string value: string ref,
+ unique int parent: @namedexprorstmt ref
+);
+
+/*
+ * Modules
+ */
+
+#keyset[name]
+modules(
+ unique int id: @module,
+ string name: string ref
+);
+
+isOpen(
+ int id: @module ref
+);
+
+#keyset[fileId]
+cumodule(
+ int fileId: @file ref,
+ int moduleId: @module ref
+);
+
+@directive = @requires
+ | @exports
+ | @opens
+ | @uses
+ | @provides
+
+#keyset[directive]
+directives(
+ int id: @module ref,
+ int directive: @directive ref
+);
+
+requires(
+ unique int id: @requires,
+ int target: @module ref
+);
+
+isTransitive(
+ int id: @requires ref
+);
+
+isStatic(
+ int id: @requires ref
+);
+
+exports(
+ unique int id: @exports,
+ int target: @package ref
+);
+
+exportsTo(
+ int id: @exports ref,
+ int target: @module ref
+);
+
+opens(
+ unique int id: @opens,
+ int target: @package ref
+);
+
+opensTo(
+ int id: @opens ref,
+ int target: @module ref
+);
+
+uses(
+ unique int id: @uses,
+ string serviceInterface: string ref
+);
+
+provides(
+ unique int id: @provides,
+ string serviceInterface: string ref
+);
+
+providesWith(
+ int id: @provides ref,
+ string serviceImpl: string ref
+);
+
+/*
+ * Javadoc
+ */
+
+javadoc(
+ unique int id: @javadoc
+);
+
+isNormalComment(
+ int commentid : @javadoc ref
+);
+
+isEolComment(
+ int commentid : @javadoc ref
+);
+
+hasJavadoc(
+ int documentableid: @member ref,
+ int javadocid: @javadoc ref
+);
+
+#keyset[parentid,idx]
+javadocTag(
+ unique int id: @javadocTag,
+ string name: string ref,
+ int parentid: @javadocParent ref,
+ int idx: int ref
+);
+
+#keyset[parentid,idx]
+javadocText(
+ unique int id: @javadocText,
+ string text: string ref,
+ int parentid: @javadocParent ref,
+ int idx: int ref
+);
+
+@javadocParent = @javadoc | @javadocTag;
+@javadocElement = @javadocTag | @javadocText;
+
+@typeorpackage = @type | @package;
+
+@typeorcallable = @type | @callable;
+@classorinterface = @interface | @class;
+@boundedtype = @typevariable | @wildcard;
+@reftype = @classorinterface | @array | @boundedtype;
+@classorarray = @class | @array;
+@type = @primitive | @reftype;
+@callable = @method | @constructor;
+@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field |
+ @annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl;
+
+@modifiable = @member_modifiable| @param | @localvar ;
+
+@member_modifiable = @class | @interface | @method | @constructor | @field ;
+
+@member = @method | @constructor | @field | @reftype ;
+
+@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception
+ | @boundedtype | @typebound | @array | @primitive
+ | @import | @stmt | @expr | @localvar | @javadoc | @javadocTag | @javadocText
+ | @xmllocatable;
+
+@top = @element | @locatable | @folder;
+
+/*
+ * XML Files
+ */
+
+xmlEncoding(
+ unique int id: @file ref,
+ string encoding: string ref
+);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref
+);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref
+);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref
+);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref
+);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/*
+ * configuration files with key value pairs
+ */
+
+configs(
+ unique int id: @config
+);
+
+configNames(
+ unique int id: @configName,
+ int config: @config ref,
+ string name: string ref
+);
+
+configValues(
+ unique int id: @configValue,
+ int config: @config ref,
+ string value: string ref
+);
+
+configLocations(
+ int locatable: @configLocatable ref,
+ int location: @location_default ref
+);
+
+@configLocatable = @config | @configName | @configValue;
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/semmlecode.dbscheme b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/semmlecode.dbscheme
new file mode 100755
index 00000000000..054d7e823b2
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/semmlecode.dbscheme
@@ -0,0 +1,950 @@
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * javac A.java B.java C.java
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ /**
+ * An invocation of the compiler. Note that more than one file may
+ * be compiled per invocation. For example, this command compiles
+ * three source files:
+ *
+ * javac A.java B.java C.java
+ */
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * javac A.java B.java C.java
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | *path to extractor*
+ * 1 | `--javac-args`
+ * 2 | A.java
+ * 3 | B.java
+ * 4 | C.java
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * javac A.java B.java C.java
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | A.java
+ * 1 | B.java
+ * 2 | C.java
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+/*
+ * External artifacts
+ */
+
+externalData(
+ int id : @externalDataElement,
+ string path : string ref,
+ int column: int ref,
+ string value : string ref
+);
+
+snapshotDate(
+ unique date snapshotDate : date ref
+);
+
+sourceLocationPrefix(
+ string prefix : string ref
+);
+
+/*
+ * Duplicate code
+ */
+
+duplicateCode(
+ unique int id : @duplication,
+ string relativePath : string ref,
+ int equivClass : int ref
+);
+
+similarCode(
+ unique int id : @similarity,
+ string relativePath : string ref,
+ int equivClass : int ref
+);
+
+@duplication_or_similarity = @duplication | @similarity
+
+tokens(
+ int id : @duplication_or_similarity ref,
+ int offset : int ref,
+ int beginLine : int ref,
+ int beginColumn : int ref,
+ int endLine : int ref,
+ int endColumn : int ref
+);
+
+/*
+ * Locations and files
+ */
+
+@location = @location_default ;
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+hasLocation(
+ int locatableid: @locatable ref,
+ int id: @location ref
+);
+
+@sourceline = @locatable ;
+
+#keyset[element_id]
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref
+);
+
+files(
+ unique int id: @file,
+ string name: string ref,
+ string simple: string ref,
+ string ext: string ref,
+ int fromSource: int ref // deprecated
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref,
+ string simple: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+/*
+ * Java
+ */
+
+cupackage(
+ unique int id: @file ref,
+ int packageid: @package ref
+);
+
+#keyset[fileid,keyName]
+jarManifestMain(
+ int fileid: @file ref,
+ string keyName: string ref,
+ string value: string ref
+);
+
+#keyset[fileid,entryName,keyName]
+jarManifestEntries(
+ int fileid: @file ref,
+ string entryName: string ref,
+ string keyName: string ref,
+ string value: string ref
+);
+
+packages(
+ unique int id: @package,
+ string nodeName: string ref
+);
+
+primitives(
+ unique int id: @primitive,
+ string nodeName: string ref
+);
+
+modifiers(
+ unique int id: @modifier,
+ string nodeName: string ref
+);
+
+classes(
+ unique int id: @class,
+ string nodeName: string ref,
+ int parentid: @package ref,
+ int sourceid: @class ref
+);
+
+interfaces(
+ unique int id: @interface,
+ string nodeName: string ref,
+ int parentid: @package ref,
+ int sourceid: @interface ref
+);
+
+fielddecls(
+ unique int id: @fielddecl,
+ int parentid: @reftype ref
+);
+
+#keyset[fieldId] #keyset[fieldDeclId,pos]
+fieldDeclaredIn(
+ int fieldId: @field ref,
+ int fieldDeclId: @fielddecl ref,
+ int pos: int ref
+);
+
+fields(
+ unique int id: @field,
+ string nodeName: string ref,
+ int typeid: @type ref,
+ int parentid: @reftype ref,
+ int sourceid: @field ref
+);
+
+constrs(
+ unique int id: @constructor,
+ string nodeName: string ref,
+ string signature: string ref,
+ int typeid: @type ref,
+ int parentid: @reftype ref,
+ int sourceid: @constructor ref
+);
+
+methods(
+ unique int id: @method,
+ string nodeName: string ref,
+ string signature: string ref,
+ int typeid: @type ref,
+ int parentid: @reftype ref,
+ int sourceid: @method ref
+);
+
+#keyset[parentid,pos]
+params(
+ unique int id: @param,
+ int typeid: @type ref,
+ int pos: int ref,
+ int parentid: @callable ref,
+ int sourceid: @param ref
+);
+
+paramName(
+ unique int id: @param ref,
+ string nodeName: string ref
+);
+
+isVarargsParam(
+ int param: @param ref
+);
+
+exceptions(
+ unique int id: @exception,
+ int typeid: @type ref,
+ int parentid: @callable ref
+);
+
+isAnnotType(
+ int interfaceid: @interface ref
+);
+
+isAnnotElem(
+ int methodid: @method ref
+);
+
+annotValue(
+ int parentid: @annotation ref,
+ int id2: @method ref,
+ unique int value: @expr ref
+);
+
+isEnumType(
+ int classid: @class ref
+);
+
+isEnumConst(
+ int fieldid: @field ref
+);
+
+#keyset[parentid,pos]
+typeVars(
+ unique int id: @typevariable,
+ string nodeName: string ref,
+ int pos: int ref,
+ int kind: int ref, // deprecated
+ int parentid: @typeorcallable ref
+);
+
+wildcards(
+ unique int id: @wildcard,
+ string nodeName: string ref,
+ int kind: int ref
+);
+
+#keyset[parentid,pos]
+typeBounds(
+ unique int id: @typebound,
+ int typeid: @reftype ref,
+ int pos: int ref,
+ int parentid: @boundedtype ref
+);
+
+#keyset[parentid,pos]
+typeArgs(
+ int argumentid: @reftype ref,
+ int pos: int ref,
+ int parentid: @typeorcallable ref
+);
+
+isParameterized(
+ int memberid: @member ref
+);
+
+isRaw(
+ int memberid: @member ref
+);
+
+erasure(
+ unique int memberid: @member ref,
+ int erasureid: @member ref
+);
+
+#keyset[classid] #keyset[parent]
+isAnonymClass(
+ int classid: @class ref,
+ int parent: @classinstancexpr ref
+);
+
+#keyset[classid] #keyset[parent]
+isLocalClass(
+ int classid: @class ref,
+ int parent: @localclassdeclstmt ref
+);
+
+isDefConstr(
+ int constructorid: @constructor ref
+);
+
+#keyset[exprId]
+lambdaKind(
+ int exprId: @lambdaexpr ref,
+ int bodyKind: int ref
+);
+
+arrays(
+ unique int id: @array,
+ string nodeName: string ref,
+ int elementtypeid: @type ref,
+ int dimension: int ref,
+ int componenttypeid: @type ref
+);
+
+enclInReftype(
+ unique int child: @reftype ref,
+ int parent: @reftype ref
+);
+
+extendsReftype(
+ int id1: @reftype ref,
+ int id2: @classorinterface ref
+);
+
+implInterface(
+ int id1: @classorarray ref,
+ int id2: @interface ref
+);
+
+hasModifier(
+ int id1: @modifiable ref,
+ int id2: @modifier ref
+);
+
+imports(
+ unique int id: @import,
+ int holder: @typeorpackage ref,
+ string name: string ref,
+ int kind: int ref
+);
+
+#keyset[parent,idx]
+stmts(
+ unique int id: @stmt,
+ int kind: int ref,
+ int parent: @stmtparent ref,
+ int idx: int ref,
+ int bodydecl: @callable ref
+);
+
+@stmtparent = @callable | @stmt | @switchexpr;
+
+case @stmt.kind of
+ 0 = @block
+| 1 = @ifstmt
+| 2 = @forstmt
+| 3 = @enhancedforstmt
+| 4 = @whilestmt
+| 5 = @dostmt
+| 6 = @trystmt
+| 7 = @switchstmt
+| 8 = @synchronizedstmt
+| 9 = @returnstmt
+| 10 = @throwstmt
+| 11 = @breakstmt
+| 12 = @continuestmt
+| 13 = @emptystmt
+| 14 = @exprstmt
+| 15 = @labeledstmt
+| 16 = @assertstmt
+| 17 = @localvariabledeclstmt
+| 18 = @localclassdeclstmt
+| 19 = @constructorinvocationstmt
+| 20 = @superconstructorinvocationstmt
+| 21 = @case
+| 22 = @catchclause
+| 23 = @yieldstmt
+;
+
+#keyset[parent,idx]
+exprs(
+ unique int id: @expr,
+ int kind: int ref,
+ int typeid: @type ref,
+ int parent: @exprparent ref,
+ int idx: int ref
+);
+
+callableEnclosingExpr(
+ unique int id: @expr ref,
+ int callable_id: @callable ref
+);
+
+statementEnclosingExpr(
+ unique int id: @expr ref,
+ int statement_id: @stmt ref
+);
+
+isParenthesized(
+ unique int id: @expr ref,
+ int parentheses: int ref
+);
+
+case @expr.kind of
+ 1 = @arrayaccess
+| 2 = @arraycreationexpr
+| 3 = @arrayinit
+| 4 = @assignexpr
+| 5 = @assignaddexpr
+| 6 = @assignsubexpr
+| 7 = @assignmulexpr
+| 8 = @assigndivexpr
+| 9 = @assignremexpr
+| 10 = @assignandexpr
+| 11 = @assignorexpr
+| 12 = @assignxorexpr
+| 13 = @assignlshiftexpr
+| 14 = @assignrshiftexpr
+| 15 = @assignurshiftexpr
+| 16 = @booleanliteral
+| 17 = @integerliteral
+| 18 = @longliteral
+| 19 = @floatingpointliteral
+| 20 = @doubleliteral
+| 21 = @characterliteral
+| 22 = @stringliteral
+| 23 = @nullliteral
+| 24 = @mulexpr
+| 25 = @divexpr
+| 26 = @remexpr
+| 27 = @addexpr
+| 28 = @subexpr
+| 29 = @lshiftexpr
+| 30 = @rshiftexpr
+| 31 = @urshiftexpr
+| 32 = @andbitexpr
+| 33 = @orbitexpr
+| 34 = @xorbitexpr
+| 35 = @andlogicalexpr
+| 36 = @orlogicalexpr
+| 37 = @ltexpr
+| 38 = @gtexpr
+| 39 = @leexpr
+| 40 = @geexpr
+| 41 = @eqexpr
+| 42 = @neexpr
+| 43 = @postincexpr
+| 44 = @postdecexpr
+| 45 = @preincexpr
+| 46 = @predecexpr
+| 47 = @minusexpr
+| 48 = @plusexpr
+| 49 = @bitnotexpr
+| 50 = @lognotexpr
+| 51 = @castexpr
+| 52 = @newexpr
+| 53 = @conditionalexpr
+| 54 = @parexpr // deprecated
+| 55 = @instanceofexpr
+| 56 = @localvariabledeclexpr
+| 57 = @typeliteral
+| 58 = @thisaccess
+| 59 = @superaccess
+| 60 = @varaccess
+| 61 = @methodaccess
+| 62 = @unannotatedtypeaccess
+| 63 = @arraytypeaccess
+| 64 = @packageaccess
+| 65 = @wildcardtypeaccess
+| 66 = @declannotation
+| 67 = @uniontypeaccess
+| 68 = @lambdaexpr
+| 69 = @memberref
+| 70 = @annotatedtypeaccess
+| 71 = @typeannotation
+| 72 = @intersectiontypeaccess
+| 73 = @switchexpr
+;
+
+@classinstancexpr = @newexpr | @lambdaexpr | @memberref
+
+@annotation = @declannotation | @typeannotation
+@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess
+
+@assignment = @assignexpr
+ | @assignop;
+
+@unaryassignment = @postincexpr
+ | @postdecexpr
+ | @preincexpr
+ | @predecexpr;
+
+@assignop = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ | @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ | @assignurshiftexpr;
+
+@literal = @booleanliteral
+ | @integerliteral
+ | @longliteral
+ | @floatingpointliteral
+ | @doubleliteral
+ | @characterliteral
+ | @stringliteral
+ | @nullliteral;
+
+@binaryexpr = @mulexpr
+ | @divexpr
+ | @remexpr
+ | @addexpr
+ | @subexpr
+ | @lshiftexpr
+ | @rshiftexpr
+ | @urshiftexpr
+ | @andbitexpr
+ | @orbitexpr
+ | @xorbitexpr
+ | @andlogicalexpr
+ | @orlogicalexpr
+ | @ltexpr
+ | @gtexpr
+ | @leexpr
+ | @geexpr
+ | @eqexpr
+ | @neexpr;
+
+@unaryexpr = @postincexpr
+ | @postdecexpr
+ | @preincexpr
+ | @predecexpr
+ | @minusexpr
+ | @plusexpr
+ | @bitnotexpr
+ | @lognotexpr;
+
+@caller = @classinstancexpr
+ | @methodaccess
+ | @constructorinvocationstmt
+ | @superconstructorinvocationstmt;
+
+callableBinding(
+ unique int callerid: @caller ref,
+ int callee: @callable ref
+);
+
+memberRefBinding(
+ unique int id: @expr ref,
+ int callable: @callable ref
+);
+
+@exprparent = @stmt | @expr | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable;
+
+variableBinding(
+ unique int expr: @varaccess ref,
+ int variable: @variable ref
+);
+
+@variable = @localscopevariable | @field;
+
+@localscopevariable = @localvar | @param;
+
+localvars(
+ unique int id: @localvar,
+ string nodeName: string ref,
+ int typeid: @type ref,
+ int parentid: @localvariabledeclexpr ref
+);
+
+@namedexprorstmt = @breakstmt
+ | @continuestmt
+ | @labeledstmt
+ | @literal;
+
+namestrings(
+ string name: string ref,
+ string value: string ref,
+ unique int parent: @namedexprorstmt ref
+);
+
+/*
+ * Modules
+ */
+
+#keyset[name]
+modules(
+ unique int id: @module,
+ string name: string ref
+);
+
+isOpen(
+ int id: @module ref
+);
+
+#keyset[fileId]
+cumodule(
+ int fileId: @file ref,
+ int moduleId: @module ref
+);
+
+@directive = @requires
+ | @exports
+ | @opens
+ | @uses
+ | @provides
+
+#keyset[directive]
+directives(
+ int id: @module ref,
+ int directive: @directive ref
+);
+
+requires(
+ unique int id: @requires,
+ int target: @module ref
+);
+
+isTransitive(
+ int id: @requires ref
+);
+
+isStatic(
+ int id: @requires ref
+);
+
+exports(
+ unique int id: @exports,
+ int target: @package ref
+);
+
+exportsTo(
+ int id: @exports ref,
+ int target: @module ref
+);
+
+opens(
+ unique int id: @opens,
+ int target: @package ref
+);
+
+opensTo(
+ int id: @opens ref,
+ int target: @module ref
+);
+
+uses(
+ unique int id: @uses,
+ string serviceInterface: string ref
+);
+
+provides(
+ unique int id: @provides,
+ string serviceInterface: string ref
+);
+
+providesWith(
+ int id: @provides ref,
+ string serviceImpl: string ref
+);
+
+/*
+ * Javadoc
+ */
+
+javadoc(
+ unique int id: @javadoc
+);
+
+isNormalComment(
+ int commentid : @javadoc ref
+);
+
+isEolComment(
+ int commentid : @javadoc ref
+);
+
+hasJavadoc(
+ int documentableid: @member ref,
+ int javadocid: @javadoc ref
+);
+
+#keyset[parentid,idx]
+javadocTag(
+ unique int id: @javadocTag,
+ string name: string ref,
+ int parentid: @javadocParent ref,
+ int idx: int ref
+);
+
+#keyset[parentid,idx]
+javadocText(
+ unique int id: @javadocText,
+ string text: string ref,
+ int parentid: @javadocParent ref,
+ int idx: int ref
+);
+
+@javadocParent = @javadoc | @javadocTag;
+@javadocElement = @javadocTag | @javadocText;
+
+@typeorpackage = @type | @package;
+
+@typeorcallable = @type | @callable;
+@classorinterface = @interface | @class;
+@boundedtype = @typevariable | @wildcard;
+@reftype = @classorinterface | @array | @boundedtype;
+@classorarray = @class | @array;
+@type = @primitive | @reftype;
+@callable = @method | @constructor;
+@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field |
+ @annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl;
+
+@modifiable = @member_modifiable| @param | @localvar ;
+
+@member_modifiable = @class | @interface | @method | @constructor | @field ;
+
+@member = @method | @constructor | @field | @reftype ;
+
+@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception
+ | @boundedtype | @typebound | @array | @primitive
+ | @import | @stmt | @expr | @localvar | @javadoc | @javadocTag | @javadocText
+ | @xmllocatable;
+
+@top = @element | @locatable | @folder;
+
+/*
+ * XML Files
+ */
+
+xmlEncoding(
+ unique int id: @file ref,
+ string encoding: string ref
+);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref
+);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref
+);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref
+);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref
+);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/*
+ * configuration files with key value pairs
+ */
+
+configs(
+ unique int id: @config
+);
+
+configNames(
+ unique int id: @configName,
+ int config: @config ref,
+ string name: string ref
+);
+
+configValues(
+ unique int id: @configValue,
+ int config: @config ref,
+ string value: string ref
+);
+
+configLocations(
+ int locatable: @configLocatable ref,
+ int location: @location_default ref
+);
+
+@configLocatable = @config | @configName | @configValue;
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/statementEnclosingExpr.ql b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/statementEnclosingExpr.ql
new file mode 100644
index 00000000000..f5823b7794d
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/statementEnclosingExpr.ql
@@ -0,0 +1,17 @@
+class Expr extends @expr {
+ string toString() { result = "expr" }
+}
+
+class ParExpr extends Expr, @parexpr {
+ override string toString() { result = "(...)" }
+}
+
+class Statement extends @stmt {
+ string toString() { result = "stmt" }
+}
+
+from Expr id, Statement s
+where
+ statementEnclosingExpr(id, s) and
+ not id instanceof ParExpr
+select id, s
diff --git a/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/upgrade.properties b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/upgrade.properties
new file mode 100644
index 00000000000..679092fa830
--- /dev/null
+++ b/java/upgrades/e7706df98aaefcf055f35f50582f2686f41c23bb/upgrade.properties
@@ -0,0 +1,9 @@
+description: Refactor extraction of parentheses
+compatibility: full
+isParenthesized.rel: run isParenthesized.qlo
+exprs.rel: run exprs.qlo
+callableEnclosingExpr.rel: run callableEnclosingExpr.qlo
+statementEnclosingExpr.rel: run statementEnclosingExpr.qlo
+annotValue.rel: run annotValue.qlo
+hasLocation.rel: run hasLocation.qlo
+numlines.rel: run numlines.qlo