C#: Reduce size of getAThrownException()

In the precense of multiple core libraries, `getAThrownException()` would return
multiple copies of the same exception, say `System.OverflowException`, one for each
core library. With this change we try to identify which core library a given control
flow element was compiled against, and only return the corresponding version.
This commit is contained in:
Tom Hvitved
2019-02-26 14:48:16 +01:00
parent 9d7877907b
commit 8abf76b618
2 changed files with 46 additions and 1 deletions

View File

@@ -19,6 +19,11 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
/** Gets the enclosing callable of this element, if any. */
Callable getEnclosingCallable() { none() }
/** Gets the assembly that this element was compiled into. */
Assembly getAssembly() {
result = this.getEnclosingCallable().getDeclaringType().getALocation()
}
/**
* Gets a control flow node for this element. That is, a node in the
* control flow graph that corresponds to this element.

View File

@@ -185,6 +185,35 @@ private class Overflowable extends UnaryOperation {
}
}
private class SystemType extends ValueOrRefType {
SystemType() { this.getNamespace() instanceof SystemNamespace }
}
private class SystemTypeMention extends TypeMention {
SystemTypeMention() { this.getType() instanceof SystemType }
Assembly getSystemAssembly() { result = this.getType().getALocation() }
Assembly getAssembly() { result = this.getTarget().(ControlFlowElement).getAssembly() }
}
/**
* Holds if assembly `a` was definitely compiled with core library `core`.
*
* The analysis is conservative, as it requires mentioning of a (non-special)
* core type inside assembly `a`.
*/
pragma[noinline]
private predicate assemblyCompiledWithCoreLib(Assembly a, Assembly core) {
exists(SystemTypeMention stm | a = stm.getAssembly() |
core = stm.getSystemAssembly() and
// Special built-in types like `object` and `int` are collapsed into one entity
// in the presence of multiple core libraries, so such entities cannot be used
// to determine the actual core library used at compilation
strictcount(stm.getSystemAssembly()) = 1
)
}
/** A control flow element that is inside a `try` block. */
private class TriedControlFlowElement extends ControlFlowElement {
TriedControlFlowElement() { this = any(TryStmt try).getATriedElement() }
@@ -192,7 +221,7 @@ private class TriedControlFlowElement extends ControlFlowElement {
/**
* Gets an exception class that is potentially thrown by this element, if any.
*/
Class getAThrownException() {
private Class getAThrownException0() {
this instanceof Overflowable and
result instanceof SystemOverflowExceptionClass
or
@@ -249,6 +278,17 @@ private class TriedControlFlowElement extends ControlFlowElement {
this instanceof StringLiteral and
result instanceof SystemOutOfMemoryExceptionClass
}
private Assembly getCoreLib() { assemblyCompiledWithCoreLib(this.getAssembly(), result) }
Class getAThrownException() {
result = this.getAThrownException0() and
(
not exists(this.getCoreLib())
or
this.getCoreLib() = result.getALocation()
)
}
}
pragma[noinline]