C#: Autoformat QLL files

This commit is contained in:
Tom Hvitved
2019-01-11 14:47:17 +01:00
parent bbc49dce40
commit b81d2ca8fa
185 changed files with 6276 additions and 8176 deletions

View File

@@ -4,28 +4,18 @@ private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.frameworks.system.web.UI
class DisposableType extends RefType {
DisposableType() {
this.getABaseType+() instanceof SystemIDisposableInterface
}
DisposableType() { this.getABaseType+() instanceof SystemIDisposableInterface }
}
class DisposableField extends Field {
DisposableField() {
this.getType() instanceof DisposableType
}
DisposableField() { this.getType() instanceof DisposableType }
}
class WebControl extends RefType {
WebControl() {
this.getBaseClass*() instanceof SystemWebUIControlClass
}
WebControl() { this.getBaseClass*() instanceof SystemWebUIControlClass }
}
class WebPage extends RefType {
WebPage() {
this.getBaseClass*() instanceof SystemWebUIPageClass
}
}
class WebPage extends RefType { WebPage() { this.getBaseClass*() instanceof SystemWebUIPageClass } }
/**
* Holds if `f` is an auto-disposed web control.
@@ -37,15 +27,13 @@ class WebPage extends RefType {
* `UnloadRecursive()`.
*/
predicate isAutoDisposedWebControl(Field f) {
f.getType() instanceof WebControl
and
f.getType() instanceof WebControl and
f.getDeclaringType() = any(RefType t |
t instanceof WebControl or
t instanceof WebPage
)
t instanceof WebControl or
t instanceof WebPage
)
}
/**
* An object creation that creates an `IDisposable` instance into the local scope.
*/
@@ -56,13 +44,13 @@ class LocalScopeDisposableCreation extends Call {
// Type extends IDisposable
t instanceof DisposableType and
// Within function, not field or instance initializer
exists(this.getEnclosingCallable()) |
exists(this.getEnclosingCallable())
|
// Either an ordinary object creation
this instanceof ObjectCreation
or
// Or a creation using a factory method
exists(Method create |
this.getTarget() = create |
exists(Method create | this.getTarget() = create |
create.hasName("Create") and
create.isStatic() and
create.getDeclaringType().getSourceDeclaration() = t.getSourceDeclaration()
@@ -74,20 +62,17 @@ class LocalScopeDisposableCreation extends Call {
* Gets an expression that, if it is disposed of, will imply that the object
* created by this creation is disposed of as well.
*/
Expr getADisposeTarget() {
result = getADisposeTarget0().asExpr()
}
Expr getADisposeTarget() { result = getADisposeTarget0().asExpr() }
private DataFlow::Node getADisposeTarget0() {
result = exprNode(this)
or
exists(DataFlow::Node mid |
mid = this.getADisposeTarget0() |
exists(DataFlow::Node mid | mid = this.getADisposeTarget0() |
localFlowStep(mid, result)
or
result.asExpr() = any(LocalScopeDisposableCreation other |
other.getAnArgument() = mid.asExpr()
)
other.getAnArgument() = mid.asExpr()
)
)
}
}

View File

@@ -3,45 +3,188 @@ import semmle.code.csharp.commons.GeneratedCode
import semmle.code.csharp.frameworks.System
/*
*
* Counting nontrivial literal occurrences
*
*/
private predicate trivialPositiveIntValue(string s) {
s="0" or s="1" or s="2" or s="3" or s="4" or s="5" or s="6" or s="7" or s="8" or
s="9" or s="10" or s="11" or s="12" or s="13" or s="14" or s="15" or s="16" or s="17" or
s="18" or s="19" or s="20"
or
s="16" or s="32" or s="64" or s="128" or s="256" or s="512" or s="1024" or
s="2048" or s="4096" or s="16384" or s="32768" or s="65536" or
s="1048576" or s="2147483648" or s="4294967296"
or
s="15" or s="31" or s="63" or s="127" or s="255" or s="511" or s="1023" or
s="2047" or s="4095" or s="16383" or s="32767" or s="65535" or
s="1048577" or s="2147483647" or s="4294967295"
or
s = "0x00000001" or s = "0x00000002" or s = "0x00000004" or s = "0x00000008" or s = "0x00000010" or s = "0x00000020" or s = "0x00000040" or s = "0x00000080" or s = "0x00000100" or s = "0x00000200" or s = "0x00000400" or s = "0x00000800" or s = "0x00001000" or s = "0x00002000" or s = "0x00004000" or s = "0x00008000" or s = "0x00010000" or s = "0x00020000" or s = "0x00040000" or s = "0x00080000" or s = "0x00100000" or s = "0x00200000" or s = "0x00400000" or s = "0x00800000" or s = "0x01000000" or s = "0x02000000" or s = "0x04000000" or s = "0x08000000" or s = "0x10000000" or s = "0x20000000" or s = "0x40000000" or s = "0x80000000" or
s = "0x00000001" or s = "0x00000003" or s = "0x00000007" or s = "0x0000000f" or s = "0x0000001f" or s = "0x0000003f" or s = "0x0000007f" or s = "0x000000ff" or s = "0x000001ff" or s = "0x000003ff" or s = "0x000007ff" or s = "0x00000fff" or s = "0x00001fff" or s = "0x00003fff" or s = "0x00007fff" or s = "0x0000ffff" or s = "0x0001ffff" or s = "0x0003ffff" or s = "0x0007ffff" or s = "0x000fffff" or s = "0x001fffff" or s = "0x003fffff" or s = "0x007fffff" or s = "0x00ffffff" or s = "0x01ffffff" or s = "0x03ffffff" or s = "0x07ffffff" or s = "0x0fffffff" or s = "0x1fffffff" or s = "0x3fffffff" or s = "0x7fffffff" or s = "0xffffffff" or
s = "0x0001" or s = "0x0002" or s = "0x0004" or s = "0x0008" or s = "0x0010" or s = "0x0020" or s = "0x0040" or s = "0x0080" or s = "0x0100" or s = "0x0200" or s = "0x0400" or s = "0x0800" or s = "0x1000" or s = "0x2000" or s = "0x4000" or s = "0x8000" or
s = "0x0001" or s = "0x0003" or s = "0x0007" or s = "0x000f" or s = "0x001f" or s = "0x003f" or s = "0x007f" or s = "0x00ff" or s = "0x01ff" or s = "0x03ff" or s = "0x07ff" or s = "0x0fff" or s = "0x1fff" or s = "0x3fff" or s = "0x7fff" or s = "0xffff" or
s = "0x01" or s = "0x02" or s = "0x04" or s = "0x08" or s = "0x10" or s = "0x20" or s = "0x40" or s = "0x80" or
s = "0x01" or s = "0x03" or s = "0x07" or s = "0x0f" or s = "0x1f" or s = "0x3f" or s = "0x7f" or s = "0xff" or
s = "0x00"
or
s = "10" or s = "100" or s = "1000" or s = "10000" or s = "100000" or s = "1000000" or s = "10000000" or s = "100000000" or s = "1000000000"
s = "0" or
s = "1" or
s = "2" or
s = "3" or
s = "4" or
s = "5" or
s = "6" or
s = "7" or
s = "8" or
s = "9" or
s = "10" or
s = "11" or
s = "12" or
s = "13" or
s = "14" or
s = "15" or
s = "16" or
s = "17" or
s = "18" or
s = "19" or
s = "20" or
s = "16" or
s = "32" or
s = "64" or
s = "128" or
s = "256" or
s = "512" or
s = "1024" or
s = "2048" or
s = "4096" or
s = "16384" or
s = "32768" or
s = "65536" or
s = "1048576" or
s = "2147483648" or
s = "4294967296" or
s = "15" or
s = "31" or
s = "63" or
s = "127" or
s = "255" or
s = "511" or
s = "1023" or
s = "2047" or
s = "4095" or
s = "16383" or
s = "32767" or
s = "65535" or
s = "1048577" or
s = "2147483647" or
s = "4294967295" or
s = "0x00000001" or
s = "0x00000002" or
s = "0x00000004" or
s = "0x00000008" or
s = "0x00000010" or
s = "0x00000020" or
s = "0x00000040" or
s = "0x00000080" or
s = "0x00000100" or
s = "0x00000200" or
s = "0x00000400" or
s = "0x00000800" or
s = "0x00001000" or
s = "0x00002000" or
s = "0x00004000" or
s = "0x00008000" or
s = "0x00010000" or
s = "0x00020000" or
s = "0x00040000" or
s = "0x00080000" or
s = "0x00100000" or
s = "0x00200000" or
s = "0x00400000" or
s = "0x00800000" or
s = "0x01000000" or
s = "0x02000000" or
s = "0x04000000" or
s = "0x08000000" or
s = "0x10000000" or
s = "0x20000000" or
s = "0x40000000" or
s = "0x80000000" or
s = "0x00000001" or
s = "0x00000003" or
s = "0x00000007" or
s = "0x0000000f" or
s = "0x0000001f" or
s = "0x0000003f" or
s = "0x0000007f" or
s = "0x000000ff" or
s = "0x000001ff" or
s = "0x000003ff" or
s = "0x000007ff" or
s = "0x00000fff" or
s = "0x00001fff" or
s = "0x00003fff" or
s = "0x00007fff" or
s = "0x0000ffff" or
s = "0x0001ffff" or
s = "0x0003ffff" or
s = "0x0007ffff" or
s = "0x000fffff" or
s = "0x001fffff" or
s = "0x003fffff" or
s = "0x007fffff" or
s = "0x00ffffff" or
s = "0x01ffffff" or
s = "0x03ffffff" or
s = "0x07ffffff" or
s = "0x0fffffff" or
s = "0x1fffffff" or
s = "0x3fffffff" or
s = "0x7fffffff" or
s = "0xffffffff" or
s = "0x0001" or
s = "0x0002" or
s = "0x0004" or
s = "0x0008" or
s = "0x0010" or
s = "0x0020" or
s = "0x0040" or
s = "0x0080" or
s = "0x0100" or
s = "0x0200" or
s = "0x0400" or
s = "0x0800" or
s = "0x1000" or
s = "0x2000" or
s = "0x4000" or
s = "0x8000" or
s = "0x0001" or
s = "0x0003" or
s = "0x0007" or
s = "0x000f" or
s = "0x001f" or
s = "0x003f" or
s = "0x007f" or
s = "0x00ff" or
s = "0x01ff" or
s = "0x03ff" or
s = "0x07ff" or
s = "0x0fff" or
s = "0x1fff" or
s = "0x3fff" or
s = "0x7fff" or
s = "0xffff" or
s = "0x01" or
s = "0x02" or
s = "0x04" or
s = "0x08" or
s = "0x10" or
s = "0x20" or
s = "0x40" or
s = "0x80" or
s = "0x01" or
s = "0x03" or
s = "0x07" or
s = "0x0f" or
s = "0x1f" or
s = "0x3f" or
s = "0x7f" or
s = "0xff" or
s = "0x00" or
s = "10" or
s = "100" or
s = "1000" or
s = "10000" or
s = "100000" or
s = "1000000" or
s = "10000000" or
s = "100000000" or
s = "1000000000"
}
private predicate trivialIntValue(string s) {
trivialPositiveIntValue(s) or
trivialPositiveIntValue(s)
or
exists(string pos | trivialPositiveIntValue(pos) and s = "-" + pos)
}
@@ -50,7 +193,15 @@ private predicate intTrivial(Literal lit) {
}
private predicate powerOfTen(float f) {
f = 10 or f = 100 or f = 1000 or f = 10000 or f = 100000 or f = 1000000 or f = 10000000 or f = 100000000 or f = 1000000000
f = 10 or
f = 100 or
f = 1000 or
f = 10000 or
f = 100000 or
f = 1000000 or
f = 10000000 or
f = 100000000 or
f = 1000000000
}
private predicate floatTrivial(Literal lit) {
@@ -59,16 +210,12 @@ private predicate floatTrivial(Literal lit) {
lit.getValue() = value and
f = value.toFloat() and
(f.abs() <= 20.0 or powerOfTen(f))
)
)
}
private predicate stringTrivial(StringLiteral lit) {
lit.getValue().length() < 8
}
private predicate stringTrivial(StringLiteral lit) { lit.getValue().length() < 8 }
private predicate small(Literal lit) {
lit.getValue().length() <= 1
}
private predicate small(Literal lit) { lit.getValue().length() <= 1 }
private predicate trivial(Literal lit) {
intTrivial(lit) or
@@ -81,10 +228,8 @@ private predicate trivial(Literal lit) {
}
private predicate literalIsConstantInitializer(Literal literal, string value, Field f) {
literal.getValue() = value
and
literal = f.getInitializer().stripCasts()
and
literal.getValue() = value and
literal = f.getInitializer().stripCasts() and
(
f.isReadOnly() and f.isStatic()
or
@@ -93,19 +238,16 @@ private predicate literalIsConstantInitializer(Literal literal, string value, Fi
}
private predicate literalInArrayInitializer(Literal literal) {
exists(ArrayInitializer arrayInit |
arrayInit.getAnElement().stripCasts() = literal
)
exists(ArrayInitializer arrayInit | arrayInit.getAnElement().stripCasts() = literal)
}
private predicate literalInAttribute(Literal literal) {
literal.getParent+() instanceof Attribute
}
private predicate literalInAttribute(Literal literal) { literal.getParent+() instanceof Attribute }
private predicate literalInGetHashCode(Literal literal) {
exists(Method m, Method getHashCode |
m = literal.getEnclosingCallable() and
getHashCode = any(SystemObjectClass c).getGetHashCodeMethod() |
getHashCode = any(SystemObjectClass c).getGetHashCodeMethod()
|
m = getHashCode.getAnOverrider*()
)
}
@@ -121,8 +263,10 @@ private predicate relevantLiteral(Literal literal, string value) {
}
private predicate valueOccurrenceCount(string value, int n) {
n = strictcount(Location loc | exists(Literal lit | relevantLiteral(lit, value) | lit.getLocation()=loc))
and n > 20
n = strictcount(Location loc |
exists(Literal lit | relevantLiteral(lit, value) | lit.getLocation() = loc)
) and
n > 20
}
private predicate occurenceCount(Literal lit, string value, int n) {
@@ -131,24 +275,23 @@ private predicate occurenceCount(Literal lit, string value, int n) {
relevantLiteral(lit, value)
}
/*
*
* Literals repeated frequently
*
*/
private predicate check(Literal lit, string value, int n, File f) {
// Check that the literal is nontrivial
not trivial(lit) and
// Check that it is repeated a number of times
occurenceCount(lit, value, n) and n > 20 and
occurenceCount(lit, value, n) and
n > 20 and
f = lit.getFile()
}
private predicate checkWithFileCount(string value, int overallCount, int fileCount, File f) {
fileCount = strictcount(Location loc | exists(Literal lit |
check(lit, value, overallCount, f) | lit.getLocation()=loc) )
fileCount = strictcount(Location loc |
exists(Literal lit | check(lit, value, overallCount, f) | lit.getLocation() = loc)
)
}
private predicate start(Literal lit, int startLine) {
@@ -164,32 +307,34 @@ private predicate firstOccurrence(Literal lit, string value, int n) {
check(lit2, value, n, f) and
start(lit, start1) and
start(lit2, start2) and
start2 < start1)
start2 < start1
)
)
}
private predicate isFloat(Literal lit) {
lit.getType() instanceof FloatingPointType
}
private predicate isFloat(Literal lit) { lit.getType() instanceof FloatingPointType }
predicate isNumber(Literal lit) {
lit.getType() instanceof IntegralType
or isFloat(lit)
lit.getType() instanceof IntegralType or
isFloat(lit)
}
predicate magicConstant(Literal e, string msg) {
exists(string value, int n | firstOccurrence(e, value, n)
and msg = "Magic constant: literal '" + value + "' is repeated " + n.toString() + " times and should be encapsulated in a constant.")
exists(string value, int n |
firstOccurrence(e, value, n) and
msg = "Magic constant: literal '" + value + "' is repeated " + n.toString() +
" times and should be encapsulated in a constant."
)
}
/*
*
* Literals where there is a defined constant with the same value
*
*/
private predicate relevantField(Field f, string value) {
exists(Literal lit | not trivial(lit) and value = lit.getValue() and literalIsConstantInitializer(lit, value, f))
exists(Literal lit |
not trivial(lit) and value = lit.getValue() and literalIsConstantInitializer(lit, value, f)
)
}
private predicate relevantDeclaration(Declaration d, Literal lit, string value) {
@@ -207,44 +352,43 @@ private predicate hasAccessModifier(Field field) {
//Default accessibility rules http://msdn.microsoft.com/en-us/library/ba0a1yw2%28v=vs.71%29.aspx
private predicate isPublic(Field field) {
field.isPublic() or
(not hasAccessModifier(field) and (field.getDeclaringType() instanceof Interface or field.getDeclaringType() instanceof Enum))
field.isPublic()
or
not hasAccessModifier(field) and
(field.getDeclaringType() instanceof Interface or field.getDeclaringType() instanceof Enum)
}
private predicate isPrivate(Field field) {
field.isPrivate() or
(not hasAccessModifier(field) and (field.getDeclaringType() instanceof Class or field.getDeclaringType() instanceof Struct))
field.isPrivate()
or
not hasAccessModifier(field) and
(field.getDeclaringType() instanceof Class or field.getDeclaringType() instanceof Struct)
}
private predicate isVisible(Field field, string value, Declaration fromDeclaration) {
//public
(
relevantField(field, value) and
field.getDeclaringType().isPublic() and
isPublic(field) and
relevantDeclaration(fromDeclaration, _, value)
)
relevantField(field, value) and
field.getDeclaringType().isPublic() and
isPublic(field) and
relevantDeclaration(fromDeclaration, _, value)
or
//in same class
(
relevantField(field, value) and
exists(RefType t |
t = field.getDeclaringType() and
t = fromDeclaration.getDeclaringType())
and relevantDeclaration(fromDeclaration, _, value)
)
relevantField(field, value) and
exists(RefType t |
t = field.getDeclaringType() and
t = fromDeclaration.getDeclaringType()
) and
relevantDeclaration(fromDeclaration, _, value)
or
//in subclass and not private
(
relevantField(field, value) and
not isPrivate(field) and
exists(RefType sup, RefType sub |
sup = field.getDeclaringType() and
sub.getABaseType+() = sup and
sub = fromDeclaration.getDeclaringType()
) and
relevantDeclaration(fromDeclaration, _, value)
)
relevantField(field, value) and
not isPrivate(field) and
exists(RefType sup, RefType sub |
sup = field.getDeclaringType() and
sub.getABaseType+() = sup and
sub = fromDeclaration.getDeclaringType()
) and
relevantDeclaration(fromDeclaration, _, value)
//internal and in same assembly
//TODO: internal (I don't think we can do this yet, as we don't associate elements in source to assemblies)
}
@@ -252,24 +396,23 @@ private predicate isVisible(Field field, string value, Declaration fromDeclarati
/**
* Literal.getValue() restricted to literals which aren't used as constant initialisers.
*/
private string magicLiteralValue(Literal l) {
relevantLiteral(l, result)
}
private string magicLiteralValue(Literal l) { relevantLiteral(l, result) }
private predicate canUseFieldInsteadOfLiteral(Field constField, Literal magicLiteral, string value) {
exists(Literal initLiteral |
literalIsConstantInitializer(initLiteral, value, constField) and
value = initLiteral.getValue() and
value = magicLiteralValue(magicLiteral)
and exists(Declaration d |
value = magicLiteralValue(magicLiteral) and
exists(Declaration d |
relevantDeclaration(d, magicLiteral, value) and
isVisible(constField, value, d)
)
)
)
}
predicate literalInsteadOfConstant(Literal magicLiteral, string value, string message, Field constField) {
predicate literalInsteadOfConstant(
Literal magicLiteral, string value, string message, Field constField
) {
canUseFieldInsteadOfLiteral(constField, magicLiteral, value) and
message =
"Literal value '" + value + "' used instead of constant $@."
message = "Literal value '" + value + "' used instead of constant $@."
}

View File

@@ -1,120 +1,78 @@
// Various utilities for writing concurrency queries.
import csharp
class WaitCall extends MethodCall
{
WaitCall()
{
class WaitCall extends MethodCall {
WaitCall() {
getTarget().hasName("Wait") and
getTarget().getDeclaringType().hasQualifiedName("System.Threading.Monitor")
}
Expr getExpr()
{
result = getArgument(0)
}
Expr getExpr() { result = getArgument(0) }
}
class WaitStmt extends ExprStmt
{
WaitStmt()
{
getExpr() instanceof WaitCall
}
class WaitStmt extends ExprStmt {
WaitStmt() { getExpr() instanceof WaitCall }
Expr getLock()
{
result = ((WaitCall)getExpr()).getExpr()
}
Expr getLock() { result = getExpr().(WaitCall).getExpr() }
// If we are waiting on a variable
Variable getWaitVariable()
{
result.getAnAccess() = getLock()
}
Variable getWaitVariable() { result.getAnAccess() = getLock() }
// If we are waiting on 'this'
predicate isWaitThis()
{
getLock() instanceof ThisAccess
}
predicate isWaitThis() { getLock() instanceof ThisAccess }
// If we are waiting on a typeof()
Type getWaitTypeObject()
{
result = ((TypeofExpr)getLock()).getTypeAccess().getTarget()
}
Type getWaitTypeObject() { result = getLock().(TypeofExpr).getTypeAccess().getTarget() }
}
class SynchronizedMethodAttribute extends Attribute
{
SynchronizedMethodAttribute()
{
class SynchronizedMethodAttribute extends Attribute {
SynchronizedMethodAttribute() {
getType().hasQualifiedName("System.Runtime.CompilerServices.MethodImplAttribute") and
exists( MemberConstantAccess a, MemberConstant mc |
a=getArgument(0) and
a.getTarget()=mc and
exists(MemberConstantAccess a, MemberConstant mc |
a = getArgument(0) and
a.getTarget() = mc and
mc.hasName("Synchronized") and
mc.getDeclaringType().hasQualifiedName("System.Runtime.CompilerServices.MethodImplOptions")
)
)
}
}
// A method with attribute [MethodImpl(MethodImplOptions.Synchronized)]
class SynchronizedMethod extends Method
{
SynchronizedMethod()
{
getAnAttribute() instanceof SynchronizedMethodAttribute
}
class SynchronizedMethod extends Method {
SynchronizedMethod() { getAnAttribute() instanceof SynchronizedMethodAttribute }
predicate isLockThis()
{
not isStatic()
}
predicate isLockThis() { not isStatic() }
Type getLockTypeObject()
{
isStatic() and result=getDeclaringType()
}
Type getLockTypeObject() { isStatic() and result = getDeclaringType() }
}
abstract class LockedBlock extends BlockStmt
{
abstract class LockedBlock extends BlockStmt {
abstract predicate isLockThis();
abstract Variable getLockVariable();
abstract Type getLockTypeObject();
Stmt getALockedStmt()
{
Stmt getALockedStmt() {
// Do this instead of getParent+, because we don't want to escape
// delegates and lambdas
result.getParent() = this
or exists( Stmt mid | mid=getALockedStmt() and result.getParent()=mid )
or
exists(Stmt mid | mid = getALockedStmt() and result.getParent() = mid)
}
}
class LockStmtBlock extends LockedBlock
{
LockStmtBlock()
{
exists( LockStmt s | this=s.getBlock() )
class LockStmtBlock extends LockedBlock {
LockStmtBlock() { exists(LockStmt s | this = s.getBlock()) }
override predicate isLockThis() { exists(LockStmt s | this = s.getBlock() and s.isLockThis()) }
override Variable getLockVariable() {
exists(LockStmt s | this = s.getBlock() and result = s.getLockVariable())
}
override predicate isLockThis()
{
exists( LockStmt s | this=s.getBlock() and s.isLockThis() )
}
override Variable getLockVariable()
{
exists( LockStmt s | this=s.getBlock() and result=s.getLockVariable() )
}
override Type getLockTypeObject()
{
exists( LockStmt s | this=s.getBlock() and result=s.getLockTypeObject() )
override Type getLockTypeObject() {
exists(LockStmt s | this = s.getBlock() and result = s.getLockTypeObject())
}
}
@@ -124,32 +82,24 @@ class LockStmtBlock extends LockedBlock
class LockingCall extends MethodCall {
LockingCall() {
this.getTarget() = any(Method m |
m.getDeclaringType().hasQualifiedName("System.Threading", "Monitor") and
m.getName().matches("%Enter%")
) or
m.getDeclaringType().hasQualifiedName("System.Threading", "Monitor") and
m.getName().matches("%Enter%")
) or
this.getTarget().hasName("EnterReadLock") or
this.getTarget().hasName("EnterWriteLock")
}
}
class SynchronizedMethodBlock extends LockedBlock
{
SynchronizedMethodBlock()
{
exists( SynchronizedMethod m | this=m.getStatementBody() )
}
override predicate isLockThis()
{
exists( SynchronizedMethod m | this=m.getStatementBody() and m.isLockThis() )
class SynchronizedMethodBlock extends LockedBlock {
SynchronizedMethodBlock() { exists(SynchronizedMethod m | this = m.getStatementBody()) }
override predicate isLockThis() {
exists(SynchronizedMethod m | this = m.getStatementBody() and m.isLockThis())
}
override Variable getLockVariable()
{
none()
}
override Variable getLockVariable() { none() }
override Type getLockTypeObject()
{
exists( SynchronizedMethod m | this=m.getStatementBody() and result=m.getLockTypeObject() )
override Type getLockTypeObject() {
exists(SynchronizedMethod m | this = m.getStatementBody() and result = m.getLockTypeObject())
}
}

View File

@@ -4,6 +4,7 @@
* In C#, fields are only one kind of data member -- indexers and properties
* give rise to very similar concepts that we may want to treat uniformly.
*/
import csharp
/**
@@ -32,9 +33,7 @@ class DataMember extends Member {
* A data member which is also a collection.
*/
class CollectionMember extends DataMember {
CollectionMember() {
this.getType().(ValueOrRefType).getABaseType*().hasName("ICollection")
}
CollectionMember() { this.getType().(ValueOrRefType).getABaseType*().hasName("ICollection") }
/**
* Gets an expression corresponding to a read or write of this collection member.
@@ -60,8 +59,11 @@ class CollectionMember extends DataMember {
// A write of a field or property can be a method call to certain methods...
exists(MethodCall call | call = result |
call.getQualifier() = this.getAnAccess() and
call.getTarget().getName().regexpMatch("Add.*|Append|Clear.*|Delete|"
+ "(Try)?Dequeue|Enqueue|Insert.*|(Try)?Pop|Push|(Try?)Remove.*|Replace.*|SafeDelete|Set.*|")
call
.getTarget()
.getName()
.regexpMatch("Add.*|Append|Clear.*|Delete|" +
"(Try)?Dequeue|Enqueue|Insert.*|(Try)?Pop|Push|(Try?)Remove.*|Replace.*|SafeDelete|Set.*|")
)
or
// ... or an indexer access that is in an assignment position

View File

@@ -1,6 +1,7 @@
/**
* A library for reasoning about thread creation events in C#.
*/
import Concurrency
/**
@@ -12,7 +13,11 @@ class ThreadStartingCallable extends Callable {
this.(Method).getQualifiedName() = "System.Threading.Tasks.Task.Run" or
this.(Constructor).getDeclaringType().getQualifiedName() = "System.Threading.Thread" or
this.(Method).getQualifiedName() = "System.Threading.Thread.Start" or
this.(Constructor).getDeclaringType().getQualifiedName().matches("System.Threading.Tasks.Task<%>")
this
.(Constructor)
.getDeclaringType()
.getQualifiedName()
.matches("System.Threading.Tasks.Task<%>")
}
}
@@ -26,9 +31,7 @@ abstract class ConcurrentEntryPoint extends Callable { }
/**
* Methods annotated with the `async` keyword are concurrent entry points.
*/
class AsyncMethod extends ConcurrentEntryPoint {
AsyncMethod() { this.(Modifiable).isAsync() }
}
class AsyncMethod extends ConcurrentEntryPoint { AsyncMethod() { this.(Modifiable).isAsync() } }
/**
* Lambdas or methods passed into the thread or task creation library functions
@@ -38,7 +41,8 @@ class LibraryTask extends ConcurrentEntryPoint {
LibraryTask() {
exists(Call c, Expr arg |
c.getTarget() instanceof ThreadStartingCallable and
arg = c.getAnArgument() |
arg = c.getAnArgument()
|
this = arg or
this = arg.(DelegateCreation).getArgument().(CallableAccess).getTarget()
)

View File

@@ -7,7 +7,8 @@ MethodCall getAnAccessByReflection(Method m) {
typeof.getTypeAccess().getType() = m.getDeclaringType() and
result.getTarget().hasName("GetMethod") and
result.getQualifier() = typeof and
result.getArgument(0).getValue() = m.getName())
result.getArgument(0).getValue() = m.getName()
)
}
Expr getAnAccessByDynamicCall(Method m) {
@@ -18,15 +19,18 @@ Expr getAnAccessByDynamicCall(Method m) {
receiverType instanceof DynamicType
or
m.getDeclaringType().getABaseType*() = receiverType
)
and result=call)
or exists(MethodCall mc, Method target |
) and
result = call
)
or
exists(MethodCall mc, Method target |
target = mc.getTarget() and
target.hasName("InvokeMember") and
target.getDeclaringType().hasQualifiedName("System.Type") and
mc.getArgument(0).(StringLiteral).getValue() = m.getName() and
mc.getArgument(3).getType().(RefType).hasMethod(m) and
result=mc)
result = mc
)
}
Expr getAMethodAccess(Method m) {
@@ -37,14 +41,14 @@ Expr getAMethodAccess(Method m) {
}
predicate potentiallyAccessedByForEach(Method m) {
m.hasName("GetEnumerator")
and m.getDeclaringType().getABaseType+().hasQualifiedName("System.Collections.IEnumerable")
m.hasName("GetEnumerator") and
m.getDeclaringType().getABaseType+().hasQualifiedName("System.Collections.IEnumerable")
}
predicate isRecursivelyLiveExpression(Expr e)
{
exists(Callable c | c=e.getEnclosingCallable() |
isRecursivelyLiveMethod(c) or not c instanceof Method )
predicate isRecursivelyLiveExpression(Expr e) {
exists(Callable c | c = e.getEnclosingCallable() |
isRecursivelyLiveMethod(c) or not c instanceof Method
)
}
predicate isRecursivelyLiveMethod(Method m) {
@@ -69,28 +73,27 @@ predicate isRecursivelyLiveMethod(Method m) {
)
}
predicate nunitValueSource(Method m)
{
exists(ValueSourceAttribute attribute | attribute.getSourceMethod()=m)
predicate nunitValueSource(Method m) {
exists(ValueSourceAttribute attribute | attribute.getSourceMethod() = m)
}
predicate nunitTestCaseSource(Declaration f)
{
exists(TestCaseSourceAttribute attribute | attribute.getSourceDeclaration()=f)
predicate nunitTestCaseSource(Declaration f) {
exists(TestCaseSourceAttribute attribute | attribute.getSourceDeclaration() = f)
}
predicate isDeadMethod(Method m) {
not isRecursivelyLiveMethod(m)
and m.isSourceDeclaration()
not isRecursivelyLiveMethod(m) and
m.isSourceDeclaration()
}
predicate isDeadField(Field f) {
f.isPrivate()
and not f.getDeclaringType() instanceof AnonymousClass
and f.getSourceDeclaration() = f
and not nunitTestCaseSource(f)
and forall(FieldAccess fc | fc.getTarget().getSourceDeclaration() = f |
f.isPrivate() and
not f.getDeclaringType() instanceof AnonymousClass and
f.getSourceDeclaration() = f and
not nunitTestCaseSource(f) and
forall(FieldAccess fc | fc.getTarget().getSourceDeclaration() = f |
isDeadMethod(fc.getEnclosingCallable())
or (not fc instanceof FieldRead and not fc.isRefArgument())
or
not fc instanceof FieldRead and not fc.isRefArgument()
)
}

View File

@@ -1,10 +1,6 @@
import csharp
class SourceDeclaration extends Declaration {
SourceDeclaration() {
this.isSourceDeclaration()
}
}
class SourceDeclaration extends Declaration { SourceDeclaration() { this.isSourceDeclaration() } }
/** A parameter that has come from source code. */
class SourceParameter extends SourceDeclaration, Parameter { }
@@ -26,98 +22,87 @@ class SourceMethodOrConstructor extends SourceDeclaration, Callable {
}
/** Gets an XML comment bound to this declaration. */
XmlComment getADeclarationXmlComment(Declaration d)
{
result=getADeclarationCommentBlock(d).getAChild()
XmlComment getADeclarationXmlComment(Declaration d) {
result = getADeclarationCommentBlock(d).getAChild()
}
/** Gets a comment block bound to this declaration. */
CommentBlock getADeclarationCommentBlock(Declaration d)
{
CommentBlock getADeclarationCommentBlock(Declaration d) {
// getAfter() is slightly more relaxed than getElement(),
// because sometimes CommentBlocks
// get split up or don't have spaces before them so aren't
// automatically attributed to the declaration.
result.getAfter()=d
result.getAfter() = d
}
/** Whether the declaration has a documentation comment. */
predicate declarationHasXmlComment(Declaration d)
{
exists(getADeclarationXmlComment(d))
}
predicate declarationHasXmlComment(Declaration d) { exists(getADeclarationXmlComment(d)) }
/** Whether a declaration should have documentation. */
predicate isDocumentationNeeded(Modifiable decl)
{
decl.getSourceDeclaration()=decl // Exclude constructed types and methods
and not exists(decl.(Attributable).getAnAttribute()) // An attribute may serve to document
and decl.isPublic()
and
predicate isDocumentationNeeded(Modifiable decl) {
decl.getSourceDeclaration() = decl and // Exclude constructed types and methods
not exists(decl.(Attributable).getAnAttribute()) and // An attribute may serve to document
decl.isPublic() and
(
// The documentation of the overridden method (e.g. in an interface) is sufficient.
exists(SourceMethod m | decl=m | not m.overrides() )
or exists(ValueOrRefType t | decl=t | t.fromSource() )
or decl instanceof SourceConstructor
exists(SourceMethod m | decl = m | not m.overrides())
or
exists(ValueOrRefType t | decl = t | t.fromSource())
or
decl instanceof SourceConstructor
)
}
/** An XML comment containing a `<returns>` tag. */
class ReturnsXmlComment extends XmlComment
{
ReturnsXmlComment() { getOpenTag(_)="returns" }
class ReturnsXmlComment extends XmlComment {
ReturnsXmlComment() { getOpenTag(_) = "returns" }
predicate hasBody(int offset) { hasBody("returns",offset) }
predicate hasBody(int offset) { hasBody("returns", offset) }
predicate isOpenTag(int offset) { "returns"=getOpenTag(offset) }
predicate isOpenTag(int offset) { "returns" = getOpenTag(offset) }
predicate isEmptyTag(int offset) { "returns"=getEmptyTag(offset) }
predicate isEmptyTag(int offset) { "returns" = getEmptyTag(offset) }
}
/** An XML comment containing an `<exception>` tag. */
class ExceptionXmlComment extends XmlComment
{
ExceptionXmlComment() { getOpenTag(_)="exception" }
class ExceptionXmlComment extends XmlComment {
ExceptionXmlComment() { getOpenTag(_) = "exception" }
string getCref(int offset) { result=getAttribute("exception","cref",offset) }
string getCref(int offset) { result = getAttribute("exception", "cref", offset) }
predicate hasBody(int offset) { hasBody("exception",offset) }
predicate hasBody(int offset) { hasBody("exception", offset) }
}
/** An XML comment containing a `<param>` tag. */
class ParamXmlComment extends XmlComment
{
ParamXmlComment() { getOpenTag(_)="param" }
class ParamXmlComment extends XmlComment {
ParamXmlComment() { getOpenTag(_) = "param" }
string getName(int offset) { getAttribute("param","name",offset)=result }
string getName(int offset) { getAttribute("param", "name", offset) = result }
predicate hasBody(int offset) { hasBody("param",offset) }
predicate hasBody(int offset) { hasBody("param", offset) }
}
/** An XML comment containing a `<typeparam>` tag. */
class TypeparamXmlComment extends XmlComment
{
TypeparamXmlComment() { getOpenTag(_)="typeparam" }
class TypeparamXmlComment extends XmlComment {
TypeparamXmlComment() { getOpenTag(_) = "typeparam" }
string getName(int offset) { getAttribute("typeparam","name",offset)=result }
string getName(int offset) { getAttribute("typeparam", "name", offset) = result }
predicate hasBody(int offset) { hasBody("typeparam",offset) }
predicate hasBody(int offset) { hasBody("typeparam", offset) }
}
/** An XML comment containing a `<summary>` tag. */
class SummaryXmlComment extends XmlComment
{
SummaryXmlComment() { getOpenTag(_)="summary" }
class SummaryXmlComment extends XmlComment {
SummaryXmlComment() { getOpenTag(_) = "summary" }
predicate hasBody(int offset) { hasBody("summary",offset) }
predicate hasBody(int offset) { hasBody("summary", offset) }
predicate isOpenTag(int offset) { "summary"=getOpenTag(offset) }
predicate isOpenTag(int offset) { "summary" = getOpenTag(offset) }
predicate isEmptyTag(int offset) { "summary"=getEmptyTag(offset) }
predicate isEmptyTag(int offset) { "summary" = getEmptyTag(offset) }
}
/** An XML comment containing an `<inheritdoc>` tag. */
class InheritDocXmlComment extends XmlComment
{
InheritDocXmlComment() { getOpenTag(_)="inheritdoc" }
class InheritDocXmlComment extends XmlComment {
InheritDocXmlComment() { getOpenTag(_) = "inheritdoc" }
}

View File

@@ -6,143 +6,115 @@
import csharp
//#################### PREDICATES ####################
Stmt firstStmt(ForeachStmt fes)
{
if fes.getBody() instanceof BlockStmt then
result = fes.getBody().(BlockStmt).getStmt(0)
else
result = fes.getBody()
Stmt firstStmt(ForeachStmt fes) {
if fes.getBody() instanceof BlockStmt
then result = fes.getBody().(BlockStmt).getStmt(0)
else result = fes.getBody()
}
predicate isEnumerableType(ValueOrRefType t)
{
t.hasQualifiedName("System.Linq.Enumerable")
}
predicate isEnumerableType(ValueOrRefType t) { t.hasQualifiedName("System.Linq.Enumerable") }
predicate isIEnumerableType(ValueOrRefType t)
{
predicate isIEnumerableType(ValueOrRefType t) {
t.getQualifiedName().matches("System.Collections.Generic.IEnumerable%")
}
predicate missedAllOpportunity(ForeachStmt fes)
{
predicate missedAllOpportunity(ForeachStmt fes) {
exists(IfStmt is |
// The loop contains an if statement with no else case, and nothing else.
is = firstStmt(fes)
and numStmts(fes) = 1
and not exists(is.getElse())
is = firstStmt(fes) and
numStmts(fes) = 1 and
not exists(is.getElse()) and
// The if statement accesses the loop variable.
and is.getCondition().getAChildExpr*() = fes.getVariable().getAnAccess()
is.getCondition().getAChildExpr*() = fes.getVariable().getAnAccess() and
// The then case of the if assigns false to something and breaks out of the loop.
and exists(Assignment a, BoolLiteral bl |
a = is.getThen().getAChild*()
and bl = a.getRValue()
and bl.toString() = "false"
)
and exists(BreakStmt bs |
bs = is.getThen().getAChild*()
)
exists(Assignment a, BoolLiteral bl |
a = is.getThen().getAChild*() and
bl = a.getRValue() and
bl.toString() = "false"
) and
exists(BreakStmt bs | bs = is.getThen().getAChild*())
)
}
predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s)
{
s = firstStmt(fes)
and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | va = s.getAVariableDeclExpr().getAChildExpr*())
and exists(CastExpr ce |
ce = s.getAVariableDeclExpr().getInitializer()
and ce.getExpr() = fes.getVariable().getAnAccess()
predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
s = firstStmt(fes) and
forex(VariableAccess va | va = fes.getVariable().getAnAccess() |
va = s.getAVariableDeclExpr().getAChildExpr*()
) and
exists(CastExpr ce |
ce = s.getAVariableDeclExpr().getInitializer() and
ce.getExpr() = fes.getVariable().getAnAccess()
)
}
predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s)
{
s = firstStmt(fes)
and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | va = s.getAVariableDeclExpr().getAChildExpr*())
and exists(AsExpr ae |
ae = s.getAVariableDeclExpr().getInitializer()
and ae.getExpr() = fes.getVariable().getAnAccess()
predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
s = firstStmt(fes) and
forex(VariableAccess va | va = fes.getVariable().getAnAccess() |
va = s.getAVariableDeclExpr().getAChildExpr*()
) and
exists(AsExpr ae |
ae = s.getAVariableDeclExpr().getInitializer() and
ae.getExpr() = fes.getVariable().getAnAccess()
)
}
predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s)
{
s = firstStmt(fes)
and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | va = s.getAVariableDeclExpr().getAChildExpr*())
and not(s.getAVariableDeclExpr().getInitializer() instanceof Cast)
predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
s = firstStmt(fes) and
forex(VariableAccess va | va = fes.getVariable().getAnAccess() |
va = s.getAVariableDeclExpr().getAChildExpr*()
) and
not s.getAVariableDeclExpr().getInitializer() instanceof Cast
}
predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is)
{
predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) {
// The very first thing the foreach loop does is test its iteration variable.
is = firstStmt(fes)
and exists(VariableAccess va |
va.getTarget() = fes.getVariable()
and va = is.getCondition().getAChildExpr*()
)
is = firstStmt(fes) and
exists(VariableAccess va |
va.getTarget() = fes.getVariable() and
va = is.getCondition().getAChildExpr*()
) and
// It then either (a) continues, or (b) performs the entire body of the loop within the condition.
and
(
is.getThen() instanceof ContinueStmt
or
(
not exists(is.getElse())
and numStmts(fes) = 1
)
not exists(is.getElse()) and
numStmts(fes) = 1
)
}
int numStmts(ForeachStmt fes)
{
if fes.getBody() instanceof BlockStmt then
result = count(fes.getBody().(BlockStmt).getAStmt())
else
result = 1
int numStmts(ForeachStmt fes) {
if fes.getBody() instanceof BlockStmt
then result = count(fes.getBody().(BlockStmt).getAStmt())
else result = 1
}
//#################### CLASSES ####################
/** A LINQ Any(...) call. */
class AnyCall extends MethodCall
{
AnyCall()
{
class AnyCall extends MethodCall {
AnyCall() {
exists(Method m |
m = getTarget()
and isEnumerableType(m.getDeclaringType())
and m.hasName("Any")
m = getTarget() and
isEnumerableType(m.getDeclaringType()) and
m.hasName("Any")
)
}
}
/** A variable of type IEnumerable&lt;T>, for some T. */
class IEnumerableSequence extends Variable
{
IEnumerableSequence()
{
isIEnumerableType(getType())
}
class IEnumerableSequence extends Variable {
IEnumerableSequence() { isIEnumerableType(getType()) }
}
/** A LINQ Select(...) call. */
class SelectCall extends ExtensionMethodCall
{
SelectCall()
{
class SelectCall extends ExtensionMethodCall {
SelectCall() {
exists(Method m |
m = getTarget()
and isEnumerableType(m.getDeclaringType())
and m.hasName("Select")
m = getTarget() and
isEnumerableType(m.getDeclaringType()) and
m.hasName("Select")
)
}
/** Gets the anonymous function expression supplied as the argument to the Select (if possible). */
AnonymousFunctionExpr getFunctionExpr()
{
result = getArgument(1)
}
AnonymousFunctionExpr getFunctionExpr() { result = getArgument(1) }
}

View File

@@ -16,26 +16,35 @@ class MicrosoftAdvisory4021279 extends Vulnerability {
override string getUrl() { result = "https://github.com/dotnet/corefx/issues/19535" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "System.Text.Encodings.Web" and (
name = "System.Text.Encodings.Web" and
(
affected = "4.0.0" and fixed = "4.0.1"
or
affected = "4.3.0" and fixed = "4.3.1"
) or
name = "System.Net.Http" and (
)
or
name = "System.Net.Http" and
(
affected = "4.1.1" and fixed = "4.1.2"
or
affected = "4.3.1" and fixed = "4.3.2"
) or
name = "System.Net.Http.WinHttpHandler" and (
)
or
name = "System.Net.Http.WinHttpHandler" and
(
affected = "4.0.1" and fixed = "4.0.2"
or
affected = "4.3.0" and fixed = "4.3.1"
) or
name = "System.Net.Security" and (
)
or
name = "System.Net.Security" and
(
affected = "4.0.0" and fixed = "4.0.1"
or
affected = "4.3.0" and fixed = "4.3.1"
) or (
)
or
(
name = "Microsoft.AspNetCore.Mvc"
or
name = "Microsoft.AspNetCore.Mvc.Core"
@@ -63,7 +72,8 @@ class MicrosoftAdvisory4021279 extends Vulnerability {
name = "Microsoft.AspNetCore.Mvc.ViewFeatures"
or
name = "Microsoft.AspNetCore.Mvc.WebApiCompatShim"
) and (
) and
(
affected = "1.0.0" and fixed = "1.0.4"
or
affected = "1.1.0" and fixed = "1.1.3"
@@ -81,7 +91,8 @@ class CVE_2017_8700 extends Vulnerability {
name = "Microsoft.AspNetCore.Mvc.Core"
or
name = "Microsoft.AspNetCore.Mvc.Cors"
) and (
) and
(
affected = "1.0.0" and fixed = "1.0.6"
or
affected = "1.1.0" and fixed = "1.1.6"
@@ -132,7 +143,8 @@ class CVE_2018_8409 extends Vulnerability {
name = "System.IO.Pipelines" and affected = "4.5.0" and fixed = "4.5.1"
or
(name = "Microsoft.AspNetCore.All" or name = "Microsoft.AspNetCore.App") and
affected = "2.1.0" and fixed = "2.1.4"
affected = "2.1.0" and
fixed = "2.1.4"
}
}
@@ -142,7 +154,8 @@ class CVE_2018_8171 extends Vulnerability {
override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/310" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "Microsoft.AspNetCore.Identity" and (
name = "Microsoft.AspNetCore.Identity" and
(
affected = "1.0.0" and fixed = "1.0.6"
or
affected = "1.1.0" and fixed = "1.1.6"
@@ -166,7 +179,8 @@ class CVE_2018_8356 extends Vulnerability {
name = "System.ServiceModel.Http"
or
name = "System.ServiceModel.NetTcp"
) and (
) and
(
affected = "4.0.0" and fixed = "4.1.3"
or
affected = "4.3.0" and fixed = "4.3.3"
@@ -180,7 +194,8 @@ class CVE_2018_8356 extends Vulnerability {
name = "System.ServiceModel.Duplex"
or
name = "System.ServiceModel.Security"
) and (
) and
(
affected = "4.0.0" and fixed = "4.0.4"
or
affected = "4.3.0" and fixed = "4.3.3"
@@ -190,7 +205,8 @@ class CVE_2018_8356 extends Vulnerability {
affected = "4.5.0" and fixed = "4.5.3"
)
or
name = "System.ServiceModel.NetTcp" and (
name = "System.ServiceModel.NetTcp" and
(
affected = "4.0.0" and fixed = "4.1.3"
or
affected = "4.3.0" and fixed = "4.3.3"
@@ -208,13 +224,15 @@ class ASPNETCore_Jul18 extends Vulnerability {
override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/311" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "Microsoft.AspNetCore.Server.Kestrel.Core" and (
name = "Microsoft.AspNetCore.Server.Kestrel.Core" and
(
affected = "2.0.0" and fixed = "2.0.4"
or
affected = "2.1.0" and fixed = "2.1.2"
)
or
name = "Microsoft.AspNetCore.All" and (
name = "Microsoft.AspNetCore.All" and
(
affected = "2.0.0" and fixed = "2.0.9"
or
affected = "2.1.0" and fixed = "2.1.2"
@@ -232,7 +250,8 @@ class CVE_2018_8292 extends Vulnerability {
override string getUrl() { result = "https://github.com/dotnet/announcements/issues/88" }
override predicate matchesVersion(string name, Version affected, Version fixed) {
name = "System.Net.Http" and (
name = "System.Net.Http" and
(
affected = "2.0" or
affected = "4.0.0" or
affected = "4.1.0" or
@@ -265,12 +284,14 @@ class CVE_2018_0786 extends Vulnerability {
name = "System.ServiceModel.Security"
or
name = "System.Private.ServiceModel"
) and (
) and
(
affected = "4.4.0" and fixed = "4.4.1"
or
affected = "4.3.0" and fixed = "4.3.1"
)
or (
or
(
name = "System.ServiceModel.Primitives"
or
name = "System.ServiceModel.Http"
@@ -281,7 +302,8 @@ class CVE_2018_0786 extends Vulnerability {
) and
affected = "4.1.0" and
fixed = "4.1.1"
or (
or
(
name = "System.ServiceModel.Duplex"
or
name = "System.ServiceModel.Security"

View File

@@ -6,6 +6,7 @@ import csharp
*/
class Package extends XMLElement {
string name;
Version version;
Package() {
@@ -19,18 +20,12 @@ class Package extends XMLElement {
}
/** Gets the name of the package, for example `System.IO.Pipelines`. */
string getPackageName() {
result = name
}
string getPackageName() { result = name }
/** Gets the version of the package, for example `4.5.1`. */
Version getVersion() {
result = version
}
Version getVersion() { result = version }
override string toString() {
result = name + " " + version
}
override string toString() { result = name + " " + version }
}
/**
@@ -63,8 +58,7 @@ abstract class Vulnerability extends string {
*/
bindingset[name, version]
predicate isVulnerable(string name, Version version, Version fixed) {
exists(Version affected, string n |
name.toLowerCase() = n.toLowerCase() |
exists(Version affected, string n | name.toLowerCase() = n.toLowerCase() |
matchesRange(n, affected, fixed) and
version.compareTo(fixed) < 0 and
version.compareTo(affected) >= 0
@@ -77,7 +71,7 @@ abstract class Vulnerability extends string {
bindingset[name, version]
private Version getUltimateFix(string name, Version version) {
result = max(Version fix | any(Vulnerability v).isVulnerable(name, version, fix))
result = max(Version fix | any(Vulnerability v).isVulnerable(name, version, fix))
}
/**
@@ -86,9 +80,7 @@ private Version getUltimateFix(string name, Version version) {
class VulnerablePackage extends Package {
Vulnerability vuln;
VulnerablePackage() {
vuln.isVulnerable(this.getPackageName(), this.getVersion(), _)
}
VulnerablePackage() { vuln.isVulnerable(this.getPackageName(), this.getVersion(), _) }
/** Gets the vulnerability of this package. */
Vulnerability getVulnerability() { result = vuln }

View File

@@ -14,16 +14,13 @@
import csharp
/** An element that should be in the generated code. */
abstract class GeneratedElement extends Element {
}
abstract class GeneratedElement extends Element { }
/** A member that should be in the generated code. */
abstract class GeneratedMember extends Member, GeneratedElement {
}
abstract class GeneratedMember extends Member, GeneratedElement { }
/** A type that should be in the generated code. */
private abstract class GeneratedType extends ValueOrRefType, GeneratedElement {
abstract private class GeneratedType extends ValueOrRefType, GeneratedElement {
GeneratedType() {
(
this instanceof Interface
@@ -35,12 +32,9 @@ private abstract class GeneratedType extends ValueOrRefType, GeneratedElement {
this instanceof Enum
or
this instanceof DelegateType
)
and
not this instanceof ConstructedType
and
not this.getALocation() instanceof ExcludedAssembly
and
) and
not this instanceof ConstructedType and
not this.getALocation() instanceof ExcludedAssembly and
this.fromLibrary()
}
@@ -66,53 +60,37 @@ private abstract class GeneratedType extends ValueOrRefType, GeneratedElement {
}
private string stubAbstractModifier() {
if this.(Class).isAbstract() then
result = "abstract "
else
result = ""
if this.(Class).isAbstract() then result = "abstract " else result = ""
}
private string stubStaticModifier() {
if this.isStatic() then result = "static "
else result = ""
if this.isStatic() then result = "static " else result = ""
}
private string stubAttributes() {
if this.getAnAttribute().getType().getQualifiedName() = "System.FlagsAttribute" then
result = "[System.Flags]\n"
else
result = ""
if this.getAnAttribute().getType().getQualifiedName() = "System.FlagsAttribute"
then result = "[System.Flags]\n"
else result = ""
}
private string stubComment() {
result = "// Generated from `" + this.getQualifiedName() + "` in `" +
min(this.getLocation().toString()) + "`\n"
min(this.getLocation().toString()) + "`\n"
}
private string stubAccessibilityModifier() {
if this.isPublic() then
result = "public "
else
result = ""
if this.isPublic() then result = "public " else result = ""
}
/** Gets the entire C# stub code for this type. */
final string getStub() {
if this.isDuplicate() then
result = ""
if this.isDuplicate()
then result = ""
else
result = this.stubComment() +
this.stubAttributes() +
this.stubAbstractModifier() +
this.stubStaticModifier() +
this.stubAccessibilityModifier() +
this.stubKeyword() + " " +
this.getUndecoratedName() +
stubGenericArguments(this) +
stubBaseTypesString() +
"\n{\n" +
stubMembers() +
"}\n\n"
result = this.stubComment() + this.stubAttributes() + this.stubAbstractModifier() +
this.stubStaticModifier() + this.stubAccessibilityModifier() + this.stubKeyword() + " " +
this.getUndecoratedName() + stubGenericArguments(this) + stubBaseTypesString() + "\n{\n" +
stubMembers() + "}\n\n"
}
private ValueOrRefType getAnInterestingBaseType() {
@@ -122,25 +100,26 @@ private abstract class GeneratedType extends ValueOrRefType, GeneratedElement {
}
private string stubBaseTypesString() {
if this instanceof Enum then
result = ""
else if exists(getAnInterestingBaseType()) then
result = " : " +
concat(int i, ValueOrRefType t |
t = this.getAnInterestingBaseType() and (if t instanceof Class then i=0 else i=1) |
stubClassName(t), ", " order by i
)
if this instanceof Enum
then result = ""
else
result = ""
if exists(getAnInterestingBaseType())
then
result = " : " +
concat(int i, ValueOrRefType t |
t = this.getAnInterestingBaseType() and
(if t instanceof Class then i = 0 else i = 1)
|
stubClassName(t), ", "
order by
i
)
else result = ""
}
private string stubMembers() {
result = concat(stubMember(this.getAGeneratedMember()))
}
private string stubMembers() { result = concat(stubMember(this.getAGeneratedMember())) }
private GeneratedMember getAGeneratedMember() {
result.getDeclaringType() = this
}
private GeneratedMember getAGeneratedMember() { result.getDeclaringType() = this }
final Type getAGeneratedType() {
result = getAnInterestingBaseType()
@@ -160,11 +139,9 @@ private abstract class GeneratedType extends ValueOrRefType, GeneratedElement {
* This is extended in client code to identify the actual
* declarations that should be generated.
*/
abstract class GeneratedDeclaration extends Declaration {
}
abstract class GeneratedDeclaration extends Declaration { }
private class IndirectType extends GeneratedType {
IndirectType() {
this.getASubType() instanceof GeneratedType
or
@@ -174,14 +151,14 @@ private class IndirectType extends GeneratedType {
or
exists(GeneratedType t | this = getAContainedType(t.getAGeneratedType()).getSourceDeclaration())
or
exists(GeneratedDeclaration decl | decl.(Member).getDeclaringType().getSourceDeclaration() = this)
exists(GeneratedDeclaration decl |
decl.(Member).getDeclaringType().getSourceDeclaration() = this
)
}
}
private class RootGeneratedType extends GeneratedType {
RootGeneratedType() {
this = any(GeneratedDeclaration decl).getSourceDeclaration()
}
RootGeneratedType() { this = any(GeneratedDeclaration decl).getSourceDeclaration() }
}
private Type getAContainedType(Type t) {
@@ -191,9 +168,7 @@ private Type getAContainedType(Type t) {
}
private class RootGeneratedMember extends GeneratedMember {
RootGeneratedMember() {
this = any(GeneratedDeclaration d).getSourceDeclaration()
}
RootGeneratedMember() { this = any(GeneratedDeclaration d).getSourceDeclaration() }
}
private predicate declarationExists(Virtualizable m) {
@@ -223,31 +198,26 @@ private class GeneratedNamespace extends Namespace, GeneratedElement {
}
private string getPreamble() {
if this.isGlobalNamespace() then
result = ""
else
result = "namespace " + this.getName() + "\n{\n"
if this.isGlobalNamespace()
then result = ""
else result = "namespace " + this.getName() + "\n{\n"
}
private string getPostAmble() {
if this.isGlobalNamespace() then
result = ""
else
result = "}\n"
}
private string getPostAmble() { if this.isGlobalNamespace() then result = "" else result = "}\n" }
final string getStubs() {
result = getPreamble() +
getTypeStubs() +
getSubNamespaces() +
getPostAmble()
result = getPreamble() + getTypeStubs() + getSubNamespaces() + getPostAmble()
}
/** Gets the `n`th generated child namespace, indexed from 0. */
pragma[nomagic]
final GeneratedNamespace getChildNamespace(int n) {
result.getParentNamespace() = this and
result.getName() = rank[n+1](GeneratedNamespace g | g.getParentNamespace() = this | g.getName())
result.getName() = rank[n + 1](GeneratedNamespace g |
g.getParentNamespace() = this
|
g.getName()
)
}
final int getChildNamespaceCount() {
@@ -260,7 +230,9 @@ private class GeneratedNamespace extends Namespace, GeneratedElement {
}
private string getTypeStubs() {
result = concat(string s | s = any(GeneratedType gt | gt.getDeclaringNamespace() = this).getStub())
result = concat(string s |
s = any(GeneratedType gt | gt.getDeclaringNamespace() = this).getStub()
)
}
}
@@ -268,25 +240,32 @@ private class GeneratedNamespace extends Namespace, GeneratedElement {
* Specify assemblies to exclude.
* Do not generate any types from these assemblies.
*/
abstract class ExcludedAssembly extends Assembly {
}
abstract class ExcludedAssembly extends Assembly { }
/** Exclude types from these standard assemblies. */
private class DefaultLibs extends ExcludedAssembly {
DefaultLibs() {
this.getName() = "System.Private.CoreLib"
or this.getName() = "mscorlib"
or this.getName() = "System.Runtime"
this.getName() = "System.Private.CoreLib" or
this.getName() = "mscorlib" or
this.getName() = "System.Runtime"
}
}
private string stubAccessibility(Member m) {
if m.getDeclaringType() instanceof Interface or exists(m.(Virtualizable).getExplicitlyImplementedInterface()) then result = ""
else if m.isPublic() then result = "public "
else if m.isProtected() then result = "protected "
else if m.isPrivate() then result = "private "
else if m.isInternal() then result = "internal "
else result = "unknown-accessibility"
if
m.getDeclaringType() instanceof Interface or
exists(m.(Virtualizable).getExplicitlyImplementedInterface())
then result = ""
else
if m.isPublic()
then result = "public "
else
if m.isProtected()
then result = "protected "
else
if m.isPrivate()
then result = "private "
else if m.isInternal() then result = "internal " else result = "unknown-accessibility"
}
private string stubModifiers(Member m) {
@@ -294,71 +273,121 @@ private string stubModifiers(Member m) {
}
private string stubStatic(Member m) {
if m.(Modifiable).isStatic() then result = "static "
else result = ""
if m.(Modifiable).isStatic() then result = "static " else result = ""
}
private string stubOverride(Member m) {
if m.getDeclaringType() instanceof Interface then result = ""
else if m.(Virtualizable).isVirtual() then result = "virtual "
else if m.(Virtualizable).isAbstract() then result = "abstract "
else if m.(Virtualizable).isOverride() then result = "override "
else result = ""
if m.getDeclaringType() instanceof Interface
then result = ""
else
if m.(Virtualizable).isVirtual()
then result = "virtual "
else
if m.(Virtualizable).isAbstract()
then result = "abstract "
else if m.(Virtualizable).isOverride() then result = "override " else result = ""
}
private string stubQualifiedNamePrefix(ValueOrRefType t) {
if t.getParent() instanceof GlobalNamespace then result=""
else if t.getParent() instanceof Namespace then result = t.getParent().(Namespace).getQualifiedName() + "."
else result = stubQualifiedNamePrefix(t.getParent()) + "."
if t.getParent() instanceof GlobalNamespace
then result = ""
else
if t.getParent() instanceof Namespace
then result = t.getParent().(Namespace).getQualifiedName() + "."
else result = stubQualifiedNamePrefix(t.getParent()) + "."
}
language[monotonicAggregates]
private string stubClassName(Type t) {
if t instanceof ObjectType then
result = "object"
else if t instanceof StringType then
result = "string"
else if t instanceof IntType then
result = "int"
else if t instanceof BoolType then
result = "bool"
else if t instanceof VoidType then
result = "void"
else if t instanceof FloatType then
result = "float"
else if t instanceof DoubleType then
result = "double"
else if t instanceof NullableType then
result = stubClassName(t.(NullableType).getUnderlyingType()) + "?"
else if t instanceof TypeParameter then
result = t.getName()
else if t instanceof ArrayType then
result = stubClassName(t.(ArrayType).getElementType()) + "[]"
else if t instanceof PointerType then
result = stubClassName(t.(PointerType).getReferentType()) + "*"
else if t instanceof TupleType then
result = "(" + concat(int i, Type element | element = t.(TupleType).getElementType(i) | stubClassName(element), "," order by i) + ")"
else if t instanceof ValueOrRefType then
result = stubQualifiedNamePrefix(t) + t.getUndecoratedName() + stubGenericArguments(t)
if t instanceof ObjectType
then result = "object"
else
result = "<error>"
if t instanceof StringType
then result = "string"
else
if t instanceof IntType
then result = "int"
else
if t instanceof BoolType
then result = "bool"
else
if t instanceof VoidType
then result = "void"
else
if t instanceof FloatType
then result = "float"
else
if t instanceof DoubleType
then result = "double"
else
if t instanceof NullableType
then result = stubClassName(t.(NullableType).getUnderlyingType()) + "?"
else
if t instanceof TypeParameter
then result = t.getName()
else
if t instanceof ArrayType
then result = stubClassName(t.(ArrayType).getElementType()) + "[]"
else
if t instanceof PointerType
then result = stubClassName(t.(PointerType).getReferentType()) + "*"
else
if t instanceof TupleType
then
result = "(" +
concat(int i, Type element |
element = t.(TupleType).getElementType(i)
|
stubClassName(element), ","
order by
i
) + ")"
else
if t instanceof ValueOrRefType
then
result = stubQualifiedNamePrefix(t) + t.getUndecoratedName() +
stubGenericArguments(t)
else result = "<error>"
}
language[monotonicAggregates]
private string stubGenericArguments(ValueOrRefType t) {
if t instanceof UnboundGenericType then
result = "<" + concat(int n | exists(t.(UnboundGenericType).getTypeParameter(n)) | t.(UnboundGenericType).getTypeParameter(n).getName(),"," order by n) + ">"
else if t instanceof ConstructedType then
result = "<" + concat(int n | exists(t.(ConstructedType).getTypeArgument(n)) | stubClassName(t.(ConstructedType).getTypeArgument(n)),"," order by n) + ">"
if t instanceof UnboundGenericType
then
result = "<" +
concat(int n |
exists(t.(UnboundGenericType).getTypeParameter(n))
|
t.(UnboundGenericType).getTypeParameter(n).getName(), ","
order by
n
) + ">"
else
result = ""
if t instanceof ConstructedType
then
result = "<" +
concat(int n |
exists(t.(ConstructedType).getTypeArgument(n))
|
stubClassName(t.(ConstructedType).getTypeArgument(n)), ","
order by
n
) + ">"
else result = ""
}
private string stubGenericMethodParams(Method m) {
if m instanceof UnboundGenericMethod then
result = "<" + concat(int n, TypeParameter param | param = m.(UnboundGenericMethod).getTypeParameter(n) | param.getName(), "," order by n) + ">"
else
result = ""
if m instanceof UnboundGenericMethod
then
result = "<" +
concat(int n, TypeParameter param |
param = m.(UnboundGenericMethod).getTypeParameter(n)
|
param.getName(), ","
order by
n
) + ">"
else result = ""
}
private string stubImplementation(Virtualizable c) {
@@ -368,17 +397,29 @@ private string stubImplementation(Virtualizable c) {
}
private string stubParameters(Parameterizable p) {
result = concat(int i, Parameter param | param = p.getParameter(i) and not param.getType() instanceof ArglistType |
stubParameterModifiers(param) + stubClassName(param.getType()) + " " + param.getName() + stubDefaultValue(param), ", " order by i)
result = concat(int i, Parameter param |
param = p.getParameter(i) and not param.getType() instanceof ArglistType
|
stubParameterModifiers(param) + stubClassName(param.getType()) + " " + param.getName() +
stubDefaultValue(param), ", "
order by
i
)
}
private string stubParameterModifiers(Parameter p) {
if p.isOut() then result = "out "
else if p.isRef() then result = "ref "
else if p.isParams() then result = "params "
else if p.isIn() then result = "" // Only C# 7.1 so ignore
else if p.hasExtensionMethodModifier() then result = "this "
else result = ""
if p.isOut()
then result = "out "
else
if p.isRef()
then result = "ref "
else
if p.isParams()
then result = "params "
else
if p.isIn()
then result = "" // Only C# 7.1 so ignore
else if p.hasExtensionMethodModifier() then result = "this " else result = ""
}
private string stubDefaultValue(Parameter p) {
@@ -395,37 +436,41 @@ private string stubExplicitImplementation(Member c) {
private string stubMember(Member m) {
exists(Method c | m = c and not m.getDeclaringType() instanceof Enum |
result = " " + stubModifiers(c) + stubClassName(c.getReturnType()) + " " +
stubExplicitImplementation(c) + c.getName() + stubGenericMethodParams(c) +
"(" + stubParameters(c) + ")" + stubImplementation(c) + ";\n"
result = " " + stubModifiers(c) + stubClassName(c.getReturnType()) + " " +
stubExplicitImplementation(c) + c.getName() + stubGenericMethodParams(c) + "(" +
stubParameters(c) + ")" + stubImplementation(c) + ";\n"
)
or
exists(Operator op | m = op and not m.getDeclaringType() instanceof Enum and not op instanceof ConversionOperator |
exists(Operator op |
m = op and not m.getDeclaringType() instanceof Enum and not op instanceof ConversionOperator
|
result = " " + stubModifiers(op) + stubClassName(op.getReturnType()) + " operator " +
op.getName() +"(" + stubParameters(op) + ") => throw null;\n"
op.getName() + "(" + stubParameters(op) + ") => throw null;\n"
)
or
exists(ConversionOperator op | m = op |
result = " " + stubModifiers(op) + stubExplicit(op) + "operator " +
stubClassName(op.getReturnType()) + "(" + stubParameters(op) +
") => throw null;\n"
stubClassName(op.getReturnType()) + "(" + stubParameters(op) + ") => throw null;\n"
)
or
result = " " + m.(EnumConstant).getName() + ",\n"
or
exists(Property p | m = p |
result = " " + stubModifiers(m) + stubClassName(p.getType()) + " " +
stubExplicitImplementation(p) + p.getName() + " { " + stubGetter(p) + stubSetter(p) + "}\n"
stubExplicitImplementation(p) + p.getName() + " { " + stubGetter(p) + stubSetter(p) + "}\n"
)
or exists(Constructor c | m = c and not c.getDeclaringType() instanceof Enum |
or
exists(Constructor c | m = c and not c.getDeclaringType() instanceof Enum |
result = " " + stubModifiers(m) + c.getName() + "(" + stubParameters(c) +
") => throw null;\n"
") => throw null;\n"
)
or exists(Indexer i | m = i |
or
exists(Indexer i | m = i |
result = " " + stubModifiers(m) + stubClassName(i.getType()) + " this[" + stubParameters(i) +
"] { " + stubGetter(i) + stubSetter(i) + "}\n"
"] { " + stubGetter(i) + stubSetter(i) + "}\n"
)
or exists(Field f | f = m and not f instanceof EnumConstant |
or
exists(Field f | f = m and not f instanceof EnumConstant |
result = " " + stubModifiers(m) + stubClassName(f.getType()) + " " + f.getName() + ";\n"
)
}
@@ -437,36 +482,34 @@ private string stubExplicit(ConversionOperator op) {
}
private string stubGetter(DeclarationWithGetSetAccessors p) {
if exists(p.getGetter()) then (
if p.isAbstract() or p.getDeclaringType() instanceof Interface then
result = "get; "
else
result = "get => throw null; "
) else
result = ""
if exists(p.getGetter())
then
if p.isAbstract() or p.getDeclaringType() instanceof Interface
then result = "get; "
else result = "get => throw null; "
else result = ""
}
private string stubSetter(DeclarationWithGetSetAccessors p) {
if exists(p.getSetter()) then (
if p.isAbstract() or p.getDeclaringType() instanceof Interface then
result = "set; "
else
result = "set => throw null; "
) else
result = ""
if exists(p.getSetter())
then
if p.isAbstract() or p.getDeclaringType() instanceof Interface
then result = "set; "
else result = "set => throw null; "
else result = ""
}
private string stubSemmleExtractorOptions() {
result = concat(string s |
exists(CommentLine comment |
s = "// original-extractor-options:" + comment.getText().regexpCapture("\\w*semmle-extractor-options:(.*)", 1) + "\n"
exists(CommentLine comment |
s = "// original-extractor-options:" +
comment.getText().regexpCapture("\\w*semmle-extractor-options:(.*)", 1) + "\n"
)
)
)
}
/** Gets the generated C# code. */
string generatedCode() {
result = "// This file contains auto-generated code.\n" +
stubSemmleExtractorOptions() + "\n" +
any(GeneratedNamespace ns | ns.isGlobalNamespace()).getStubs()
result = "// This file contains auto-generated code.\n" + stubSemmleExtractorOptions() + "\n" +
any(GeneratedNamespace ns | ns.isGlobalNamespace()).getStubs()
}

View File

@@ -1,2 +1 @@
import semmle.code.cil.CIL as CIL

View File

@@ -35,13 +35,10 @@ import semmle.code.csharp.dataflow.TaintTracking
import semmle.code.csharp.dataflow.SSA
/** DEPRECATED: Use `ControlFlow` instead. */
deprecated
module ControlFlowGraph {
deprecated module ControlFlowGraph {
import semmle.code.csharp.controlflow.ControlFlowGraph
import ControlFlow
}
/** Whether the source was extracted without a build command. */
predicate extractionIsStandalone() {
exists(SourceFile f | f.extractedStandalone())
}
predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) }

View File

@@ -1,9 +1,6 @@
import csharp
private
string relativePath(File file) {
result = file.getRelativePath().replaceAll("\\", "/")
}
private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") }
/**
* Holds if the `index`-th token of block `copy` is in file `file`, spanning
@@ -17,111 +14,86 @@ predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, in
tokens(copy, index, sl, sc, ec, el)
}
class Copy extends @duplication_or_similarity
{
private
int lastToken() {
result = max(int i | tokens(this, i, _, _, _, _) | i)
}
class Copy extends @duplication_or_similarity {
private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) }
int tokenStartingAt(Location loc) {
tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(),
_, _, this, result)
tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(), _, _, this, result)
}
int tokenEndingAt(Location loc) {
tokenLocation(loc.getFile(), _, _,
loc.getEndLine(), loc.getEndColumn(), this, result)
tokenLocation(loc.getFile(), _, _, loc.getEndLine(), loc.getEndColumn(), this, result)
}
int sourceStartLine() {
tokens(this, 0, result, _, _, _)
}
int sourceStartLine() { tokens(this, 0, result, _, _, _) }
int sourceStartColumn() {
tokens(this, 0, _, result, _, _)
}
int sourceStartColumn() { tokens(this, 0, _, result, _, _) }
int sourceEndLine() {
tokens(this, lastToken(), _, _, result, _)
}
int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) }
int sourceEndColumn() {
tokens(this, lastToken(), _, _, _, result)
}
int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) }
int sourceLines() {
result = this.sourceEndLine() + 1 - this.sourceStartLine()
}
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
int getEquivalenceClass() {
duplicateCode(this, _, result) or similarCode(this, _, result)
}
int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) }
File sourceFile() {
exists(string name |
duplicateCode(this, name, _) or similarCode(this, name, _) |
name.replaceAll("\\", "/") = relativePath(result))
exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) |
name.replaceAll("\\", "/") = relativePath(result)
)
}
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
sourceFile().getAbsolutePath() = filepath and
startline = sourceStartLine() and
startcolumn = sourceStartColumn() and
endline = sourceEndLine() and
endcolumn = sourceEndColumn()
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
sourceFile().getAbsolutePath() = filepath and
startline = sourceStartLine() and
startcolumn = sourceStartColumn() and
endline = sourceEndLine() and
endcolumn = sourceEndColumn()
}
string toString() { none() }
}
class DuplicateBlock extends Copy, @duplication
{
override string toString() {
result = "Duplicate code: " + sourceLines() + " duplicated lines."
}
class DuplicateBlock extends Copy, @duplication {
override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." }
}
class SimilarBlock extends Copy, @similarity
{
class SimilarBlock extends Copy, @similarity {
override string toString() {
result = "Similar code: " + sourceLines() + " almost duplicated lines."
}
}
Method sourceMethod() {
method_location(result, _) and numlines(result, _, _, _)
}
Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) }
int numberOfSourceMethods(Class c) {
result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c)
}
private
predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
exists(DuplicateBlock b, Location loc |
stmt.getLocation() = loc and
first = b.tokenStartingAt(loc) and
last = b.tokenEndingAt(loc) and
b.getEquivalenceClass() = equivClass)
b.getEquivalenceClass() = equivClass
)
}
private
Stmt statementInMethod(Method m) {
private Stmt statementInMethod(Method m) {
result.getEnclosingCallable() = m and
not result instanceof BlockStmt
}
private
predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) {
private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) {
exists(int equivClass, int first, int last |
s1 = statementInMethod(m1) and
s2 = statementInMethod(m2) and
blockCoversStatement(equivClass, first, last, s1) and
blockCoversStatement(equivClass, first, last, s2) and
s1 != s2 and m1 != m2
s1 != s2 and
m1 != m2
)
}
@@ -138,37 +110,38 @@ predicate duplicateMethod(Method m, Method other) {
}
predicate similarLines(File f, int line) {
exists(SimilarBlock b |
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
)
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
}
private
predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f)
{
lines = strictsum(SimilarBlock b, int toSum | (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and (toSum = b.sourceLines()) | toSum)
private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines = strictsum(SimilarBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
toSum = b.sourceLines()
|
toSum
)
}
private pragma[noopt]
predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
pragma[noopt]
private predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getNumberOfLines() |
exists(int coveredApprox |
coveredApprox = strictsum(int num |
exists(int equivClass |
similarLinesPerEquivalenceClass(equivClass, num, f) and
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
exists(int coveredApprox |
coveredApprox = strictsum(int num |
exists(int equivClass |
similarLinesPerEquivalenceClass(equivClass, num, f) and
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
) and
exists (int n, int product| product = coveredApprox * 100 and n = product / numLines | n > 75)
) and
exists(int notCovered |
notCovered = count(int j |
j in [1 .. numLines] and
not similarLines(f, j)
) and
coveredLines = numLines - notCovered
)
exists(int notCovered |
notCovered = count(int j |
j in [1 .. numLines] and
not similarLines(f, j)
) and
coveredLines = numLines - notCovered
)
)
}
@@ -178,32 +151,35 @@ predicate duplicateLines(File f, int line) {
)
}
private
predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f)
{
lines = strictsum(DuplicateBlock b, int toSum | (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and (toSum = b.sourceLines()) | toSum)
private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines = strictsum(DuplicateBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
toSum = b.sourceLines()
|
toSum
)
}
private pragma[noopt]
predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
pragma[noopt]
private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getNumberOfLines() |
exists(int coveredApprox |
coveredApprox = strictsum(int num |
exists(int equivClass |
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
exists(int coveredApprox |
coveredApprox = strictsum(int num |
exists(int equivClass |
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
) and
exists (int n, int product| product = coveredApprox * 100 and n = product / numLines | n > 75)
) and
exists(int notCovered |
notCovered = count(int j |
j in [1 .. numLines] and
not duplicateLines(f, j)
) and
coveredLines = numLines - notCovered
)
exists(int notCovered |
notCovered = count(int j |
j in [1 .. numLines] and
not duplicateLines(f, j)
) and
coveredLines = numLines - notCovered
)
)
}
@@ -230,54 +206,59 @@ pragma[noopt]
predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) {
exists(int numDup |
numDup = strictcount(Method m1 |
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
c instanceof AnonymousClass and
m2.getDeclaringType() = other and
other instanceof AnonymousClass and
c != other
)
) and
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
c instanceof AnonymousClass and
m2.getDeclaringType() = other and
other instanceof AnonymousClass and
c != other
)
) and
numDup = numberOfSourceMethods(c) and
numDup = numberOfSourceMethods(other) and
forall(Type t | c.getABaseType() = t | t = other.getABaseType())
)
}
private pragma[noopt]
predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
pragma[noopt]
private predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
numDup = strictcount(Method m1 |
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
m2.getDeclaringType() = other and
other instanceof Class and
c != other
)
) and
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
m2.getDeclaringType() = other and
other instanceof Class and
c != other
)
) and
total = numberOfSourceMethods(c) and
exists (int n, int product | product = 100 * numDup and n = product / total | n > 80) and
exists(int n, int product | product = 100 * numDup and n = product / total | n > 80) and
not c instanceof AnonymousClass and
not other instanceof AnonymousClass
}
predicate mostlyDuplicateClass(Class c, Class other, string message) {
exists(int numDup, int total |
mostlyDuplicateClassBase(c,other,numDup,total) and
mostlyDuplicateClassBase(c, other, numDup, total) and
(
(total != numDup
and exists(string s1, string s2, string s3, string name | s1 = " out of " and s2 = " methods in " and s3 = " are duplicated in $@." and name = c.getName() |
message = numDup + s1 + total + s2 + name + s3
)
total != numDup and
exists(string s1, string s2, string s3, string name |
s1 = " out of " and
s2 = " methods in " and
s3 = " are duplicated in $@." and
name = c.getName()
|
message = numDup + s1 + total + s2 + name + s3
)
or
(total = numDup
and exists(string s1, string s2, string name | s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName() |
message = s1 + name + s2
)
total = numDup and
exists(string s1, string s2, string name |
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
message = s1 + name + s2
)
)
)
@@ -291,15 +272,13 @@ predicate classLevelDuplication(Class c, Class other) {
duplicateAnonymousClass(c, other) or mostlyDuplicateClass(c, other, _)
}
Element whitelistedDuplicateElement()
{
Element whitelistedDuplicateElement() {
result instanceof UsingNamespaceDirective or
result instanceof UsingStaticDirective
}
predicate whitelistedLineForDuplication(File file, int line) {
exists(Location loc |
loc = whitelistedDuplicateElement().getLocation() |
exists(Location loc | loc = whitelistedDuplicateElement().getLocation() |
line = loc.getStartLine() and file = loc.getFile()
)
)
}

View File

@@ -1,14 +1,20 @@
import csharp
external predicate defectResults(int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, string message);
external predicate defectResults(
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
string message
);
class DefectResult extends int {
DefectResult() { defectResults(this, _, _, _, _, _, _, _) }
string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) }
File getFile() { exists(string path | defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path) }
File getFile() {
exists(string path |
defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
)
}
int getStartLine() { defectResults(this, _, _, result, _, _, _, _) }
@@ -21,7 +27,7 @@ class DefectResult extends int {
string getMessage() { defectResults(this, _, _, _, _, _, _, result) }
string getURL() {
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + getEndLine() + ":" + getEndColumn()
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn()
+ ":" + getEndLine() + ":" + getEndColumn()
}
}

View File

@@ -1,15 +1,18 @@
import csharp
class ExternalDefect extends @externalDefect, Element {
string getQueryPath() { exists(string path | externalDefects(this, path, _, _, _) and
result = path.replaceAll("\\", "/")) }
string getQueryPath() {
exists(string path |
externalDefects(this, path, _, _, _) and
result = path.replaceAll("\\", "/")
)
}
string getMessage() { externalDefects(this, _, _, result, _) }
float getSeverity() { externalDefects(this, _, _, _, result) }
override Location getLocation() { externalDefects(this,_,result,_,_) }
override Location getLocation() { externalDefects(this, _, result, _, _) }
override string toString() {
result = getQueryPath() + ": " + getLocation() + " - " + getMessage()
@@ -17,20 +20,16 @@ class ExternalDefect extends @externalDefect, Element {
}
class ExternalMetric extends @externalMetric, Element {
string getQueryPath() { externalMetrics(this, result, _, _) }
float getValue() { externalMetrics(this, _, _, result) }
override Location getLocation() { externalMetrics(this,_,result,_) }
override Location getLocation() { externalMetrics(this, _, result, _) }
override string toString() {
result = getQueryPath() + ": " + getLocation() + " - " + getValue()
}
override string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getValue() }
}
class ExternalData extends @externalDataElement {
string getDataPath() { externalData(this, result, _, _) }
string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
@@ -45,16 +44,13 @@ class ExternalData extends @externalDataElement {
date getFieldAsDate(int index) { result = getField(index).toDate() }
string toString() {
result = getQueryPath() + ": " + buildTupleString(0)
}
string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
private string buildTupleString(int start) {
(start = getNumFields() - 1 and result = getField(start))
start = getNumFields() - 1 and result = getField(start)
or
(start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start+1))
start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1)
}
}
/**
@@ -70,4 +66,3 @@ class DefectExternalData extends ExternalData {
string getMessage() { result = getField(1) }
}

View File

@@ -1,14 +1,20 @@
import csharp
external predicate metricResults(int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, float value);
external predicate metricResults(
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
float value
);
class MetricResult extends int {
MetricResult() { metricResults(this, _, _, _, _, _, _, _) }
string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) }
File getFile() { exists(string path | metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path) }
File getFile() {
exists(string path |
metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
)
}
int getStartLine() { metricResults(this, _, _, result, _, _, _, _) }
@@ -31,7 +37,7 @@ class MetricResult extends int {
float getValue() { metricResults(this, _, _, _, _, _, _, result) }
string getURL() {
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + getEndLine() + ":" + getEndColumn()
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn()
+ ":" + getEndLine() + ":" + getEndColumn()
}
}

View File

@@ -1,7 +1,6 @@
import csharp
class Commit extends @svnentry {
Commit() {
svnaffectedfiles(this, _, _) and
exists(date svnDate, date snapshotDate |
@@ -31,41 +30,31 @@ class Commit extends @svnentry {
string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) }
File getAnAffectedFile(string action) {
svnaffectedfiles(this,result,action)
}
File getAnAffectedFile(string action) { svnaffectedfiles(this, result, action) }
File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) }
predicate isRecent() { recentCommit(this) }
int daysToNow() {
exists(date now | snapshotDate(now) |
result = getDate().daysTo(now) and result >= 0
)
exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0)
}
int getRecentAdditionsForFile(File f) {
svnchurn(this, f, result, _)
}
int getRecentAdditionsForFile(File f) { svnchurn(this, f, result, _) }
int getRecentDeletionsForFile(File f) {
svnchurn(this, f, _, result)
}
int getRecentDeletionsForFile(File f) { svnchurn(this, f, _, result) }
int getRecentChurnForFile(File f) {
exists (int added, int deleted | svnchurn(this,f,added,deleted) and result = added + deleted)
exists(int added, int deleted | svnchurn(this, f, added, deleted) and result = added + deleted)
}
}
class Author extends string {
Author() { exists(Commit e | this = e.getAuthor()) }
Author() { exists(Commit e | this = e.getAuthor()) }
Commit getACommit() { result.getAuthor() = this }
File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() }
Commit getACommit() { result.getAuthor() = this }
File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() }
}
predicate recentCommit(Commit e) {
@@ -73,20 +62,17 @@ predicate recentCommit(Commit e) {
snapshotDate(snapshotDate) and
e.getDate() = commitDate and
days = commitDate.daysTo(snapshotDate) and
days >= 0 and days <= 60
days >= 0 and
days <= 60
)
}
date firstChange(File f) {
result = min(Commit e, date toMin | (f = e.getAnAffectedFile()) and (toMin = e.getDate()) | toMin)
result = min(Commit e, date toMin | f = e.getAnAffectedFile() and toMin = e.getDate() | toMin)
}
predicate firstCommit(Commit e) {
not exists(File f | f = e.getAnAffectedFile() |
firstChange(f) < e.getDate()
)
not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate())
}
predicate artificialChange(Commit e) {
firstCommit(e) or e.getChangeSize() >= 50000
}
predicate artificialChange(Commit e) { firstCommit(e) or e.getChangeSize() >= 50000 }

View File

@@ -40,36 +40,22 @@ class AspAttribute extends AspElement, @asp_attribute { }
*/
class AspOpenTag extends AspElement, @asp_open_tag {
/** Either `>` or `/>`, depending on whether it's an empty tag. */
private string closeAngle() {
if isEmpty()
then result = "/>"
else result = ">"
}
private string closeAngle() { if isEmpty() then result = "/>" else result = ">" }
/** Gets the `i`th attribute of this open tag. */
AspAttribute getAttribute(int i) {
asp_tag_attribute(this, i, _, result)
}
AspAttribute getAttribute(int i) { asp_tag_attribute(this, i, _, result) }
/** Gets the attribute named `name`, if any. */
AspAttribute getAttributeByName(string name) {
asp_tag_attribute(this, _, name, result)
}
AspAttribute getAttributeByName(string name) { asp_tag_attribute(this, _, name, result) }
/** Gets the name of this open tag. */
string getName() {
asp_tag_name(this, result)
}
string getName() { asp_tag_name(this, result) }
/** Holds if this open tag has an attribute. */
predicate hasAttribute() {
asp_tag_attribute(this, _, _, _)
}
predicate hasAttribute() { asp_tag_attribute(this, _, _, _) }
/** Holds if this open tag is empty. */
predicate isEmpty() {
asp_tag_isempty(this)
}
predicate isEmpty() { asp_tag_isempty(this) }
override string toString() {
if hasAttribute()
@@ -89,13 +75,9 @@ class AspOpenTag extends AspElement, @asp_open_tag {
*/
class AspCloseTag extends AspElement, @asp_close_tag {
/** Gets the name of this close tag. */
string getName() {
result = getBody()
}
string getName() { result = getBody() }
override string toString() {
result = "</" + getName() + ">"
}
override string toString() { result = "</" + getName() + ">" }
}
/**
@@ -111,7 +93,7 @@ class AspCode extends AspAttribute, @asp_code { }
class AspBlockCode extends AspCode {
AspBlockCode() { not asp_code_inline(this) }
override string toString() { result="<% ... %>" }
override string toString() { result = "<% ... %>" }
}
/**
@@ -120,7 +102,7 @@ class AspBlockCode extends AspCode {
class AspInlineCode extends AspCode {
AspInlineCode() { asp_code_inline(this) }
override string toString() { result="<%= ... %>" }
override string toString() { result = "<%= ... %>" }
}
/** A comment, for example `<!-- TODO -->`. */
@@ -146,33 +128,25 @@ class AspServerComment extends AspComment {
* ```
*/
class AspDataBinding extends AspAttribute, @asp_data_binding {
override string toString() { result="<%# ... %>" }
override string toString() { result = "<%# ... %>" }
}
/** A directive, for example `<%@ Page Language="C#" %>`. */
class AspDirective extends AspElement, @asp_directive {
/** Gets the `i`th attribute of this directive. */
AspAttribute getAttribute(int i) {
asp_directive_attribute(this, i, _, result)
}
AspAttribute getAttribute(int i) { asp_directive_attribute(this, i, _, result) }
/** Gets the attribute named `name`, if any. */
AspAttribute getAttributeByName(string name) {
asp_directive_attribute(this, _, name, result)
}
AspAttribute getAttributeByName(string name) { asp_directive_attribute(this, _, name, result) }
/**
* Gets the name of this directive, for example `Page` in
* `<%@ Page Language="C#" %>`.
*/
string getName() {
asp_directive_name(this, result)
}
string getName() { asp_directive_name(this, result) }
/** Holds if this directive has an attribute. */
predicate hasAttribute() {
exists(getAttribute(_))
}
predicate hasAttribute() { exists(getAttribute(_)) }
override string toString() {
if hasAttribute()
@@ -191,9 +165,7 @@ class AspQuotedString extends AspAttribute, @asp_quoted_string {
}
/** Arbitrary text. It will be inserted into the document as is. */
class AspText extends AspElement, @asp_text {
override string toString() { result=getBody() }
}
class AspText extends AspElement, @asp_text { override string toString() { result = getBody() } }
/** An XML directive, such as a `DOCTYPE` declaration. */
class AspXmlDirective extends AspElement, @asp_xml_directive {
@@ -209,9 +181,7 @@ class PageDirective extends AspDirective {
/**
* Gets the 'CodeBehind' class from which this page inherits.
*/
ValueOrRefType getInheritedType() {
result.getQualifiedName() = getInheritedTypeQualifiedName()
}
ValueOrRefType getInheritedType() { result.getQualifiedName() = getInheritedTypeQualifiedName() }
private string getInheritedTypeQualifiedName() {
/*
@@ -222,15 +192,17 @@ class PageDirective extends AspDirective {
* - `CodeBehindFile`/`CodeFile`: used by tooling, but not semantically
* relevant at runtime
*/
exists(string inherits | inherits = getAttributeByName("Inherits").getBody() |
if inherits.indexOf(".") != -1
then result = inherits
else exists(string className | className = getAttributeByName("ClassName").getBody() |
// take everything up to and including the last .
className.prefix(className.indexOf(".", count(className.indexOf("."))-1, 0)+1) + inherits = result
)
else
exists(string className | className = getAttributeByName("ClassName").getBody() |
// take everything up to and including the last .
className.prefix(className.indexOf(".", count(className.indexOf(".")) - 1, 0) + 1) +
inherits = result
)
)
}
}
@@ -239,22 +211,17 @@ class PageDirective extends AspDirective {
*/
class CodeBehindFile extends File {
CodeBehindFile() {
getExtension() = "aspx"
and
getExtension() = "aspx" and
exists(PageDirective pageDir | pageDir.getLocation().getFile() = this)
}
/**
* Gets the `PageDirective` that defines this page.
*/
PageDirective getPageDirective() {
result.getLocation().getFile() = this
}
PageDirective getPageDirective() { result.getLocation().getFile() = this }
/**
* Gets the 'CodeBehind' class from which this page inherits.
*/
ValueOrRefType getInheritedType() {
result = getPageDirective().getInheritedType()
}
ValueOrRefType getInheritedType() { result = getPageDirective().getInheritedType() }
}

View File

@@ -1,39 +1,29 @@
/**
* Provides classes and predicates related to ASP.NET Web.config files.
*/
import csharp
/**
* A `Web.config` file.
*/
class WebConfigXML extends XMLFile {
WebConfigXML() {
getName().matches("%Web.config")
}
}
class WebConfigXML extends XMLFile { WebConfigXML() { getName().matches("%Web.config") } }
/** A `<configuration>` tag in an ASP.NET configuration file. */
class ConfigurationXMLElement extends XMLElement {
ConfigurationXMLElement() {
this.getName().toLowerCase() = "configuration"
}
ConfigurationXMLElement() { this.getName().toLowerCase() = "configuration" }
}
/** A `<location>` tag in an ASP.NET configuration file. */
class LocationXMLElement extends XMLElement {
LocationXMLElement() {
this.getParent() instanceof ConfigurationXMLElement and
this.getName().toLowerCase() = "location"
}
}
/** A `<system.web>` tag in an ASP.NET configuration file. */
class SystemWebXMLElement extends XMLElement {
SystemWebXMLElement() {
(
this.getParent() instanceof ConfigurationXMLElement
@@ -42,12 +32,10 @@ class SystemWebXMLElement extends XMLElement {
) and
this.getName().toLowerCase() = "system.web"
}
}
/** A `<system.webServer>` tag in an ASP.NET configuration file. */
class SystemWebServerXMLElement extends XMLElement {
SystemWebServerXMLElement() {
(
this.getParent() instanceof ConfigurationXMLElement
@@ -56,26 +44,20 @@ class SystemWebServerXMLElement extends XMLElement {
) and
this.getName().toLowerCase() = "system.webserver"
}
}
/** A `<customErrors>` tag in an ASP.NET configuration file. */
class CustomErrorsXMLElement extends XMLElement {
CustomErrorsXMLElement() {
this.getParent() instanceof SystemWebXMLElement and
this.getName().toLowerCase() = "customerrors"
}
}
/** A `<httpRuntime>` tag in an ASP.NET configuration file. */
class HttpRuntimeXMLElement extends XMLElement {
HttpRuntimeXMLElement() {
this.getParent() instanceof SystemWebXMLElement and
this.getName().toLowerCase() = "httpruntime"
}
}

View File

@@ -8,95 +8,88 @@ private import CIL
/** An instruction that accesses a variable. */
class Access extends Instruction, @cil_access {
/** Gets the declaration referenced by this instruction. */
Variable getTarget() { cil_access(this,result) }
Variable getTarget() { cil_access(this, result) }
}
/**
* An instruction that accesses a variable.
* This class is provided for consistency with the C# data model.
*/
class VariableAccess extends Access, @cil_access {
}
class VariableAccess extends Access, @cil_access { }
/** An instruction that reads a variable. */
class ReadAccess extends VariableAccess, Expr, @cil_read_access {
override Type getType() { result=getTarget().getType() }
override Type getType() { result = getTarget().getType() }
}
/** An instruction yielding an address. */
class ReadRef extends Expr, @cil_read_ref {
}
class ReadRef extends Expr, @cil_read_ref { }
/** An instruction that reads the address of a variable. */
class ReadRefAccess extends ReadAccess, ReadRef {
}
class ReadRefAccess extends ReadAccess, ReadRef { }
/** An instruction that writes a variable. */
class WriteAccess extends VariableAccess, @cil_write_access {
Expr getExpr() { none() }
}
class WriteAccess extends VariableAccess, @cil_write_access { Expr getExpr() { none() } }
/** An instruction that accesses a parameter. */
class ParameterAccess extends StackVariableAccess, @cil_arg_access {
override Parameter getTarget() { result=StackVariableAccess.super.getTarget() }
override Parameter getTarget() { result = StackVariableAccess.super.getTarget() }
}
/** An instruction that reads a parameter. */
class ParameterReadAccess extends ParameterAccess, ReadAccess {
override int getPopCount() { result=0 }
override int getPopCount() { result = 0 }
}
/** An instruction that writes to a parameter. */
class ParameterWriteAccess extends ParameterAccess, WriteAccess {
override int getPopCount() { result=1 }
override Expr getExpr() { result=getOperand(0) }
override int getPopCount() { result = 1 }
override Expr getExpr() { result = getOperand(0) }
}
/** An access to the `this` parameter. */
class ThisAccess extends ParameterReadAccess {
ThisAccess() {
this.getTarget() instanceof ThisParameter
}
ThisAccess() { this.getTarget() instanceof ThisParameter }
}
/** An instruction that accesses a stack variable. */
class StackVariableAccess extends VariableAccess, @cil_stack_access {
override StackVariable getTarget() { result=VariableAccess.super.getTarget() }
override StackVariable getTarget() { result = VariableAccess.super.getTarget() }
}
/** An instruction that accesses a local variable. */
class LocalVariableAccess extends StackVariableAccess, @cil_local_access {
override LocalVariable getTarget() { result=StackVariableAccess.super.getTarget() }
override LocalVariable getTarget() { result = StackVariableAccess.super.getTarget() }
}
/** An instruction that writes to a local variable. */
class LocalVariableWriteAccess extends LocalVariableAccess, WriteAccess {
override int getPopCount() { result=1 }
override Expr getExpr() { result=getOperand(0) }
override string getExtra() { result="L" + getTarget().getIndex() }
override int getPopCount() { result = 1 }
override Expr getExpr() { result = getOperand(0) }
override string getExtra() { result = "L" + getTarget().getIndex() }
}
/** An instruction that reads a local variable. */
class LocalVariableReadAccess extends LocalVariableAccess, ReadAccess {
override int getPopCount() { result=0 }
override int getPopCount() { result = 0 }
}
/** An instruction that accesses a field. */
class FieldAccess extends VariableAccess, @cil_field_access {
override Field getTarget() { result=VariableAccess.super.getTarget() }
override string getExtra() { result=getTarget().getName() }
override Field getTarget() { result = VariableAccess.super.getTarget() }
override string getExtra() { result = getTarget().getName() }
/** Gets the qualifier of the access, if any. */
abstract Expr getQualifier();
}
/** An instruction that reads a field. */
abstract class FieldReadAccess extends FieldAccess, ReadAccess {
}
abstract class FieldReadAccess extends FieldAccess, ReadAccess { }
/** An instruction that writes a field. */
abstract class FieldWriteAccess extends FieldAccess, WriteAccess {
}
abstract class FieldWriteAccess extends FieldAccess, WriteAccess { }

View File

@@ -5,12 +5,11 @@ private import semmle.code.csharp.Location as CS
/** An attribute to a declaration, such as a method, field, type or parameter. */
class Attribute extends Element, @cil_attribute {
/** Gets the declaration this attribute is attached to. */
Declaration getDeclaration() { cil_attribute(this,result,_) }
Declaration getDeclaration() { cil_attribute(this, result, _) }
/** Gets the constructor used to construct this attribute. */
Method getConstructor() { cil_attribute(this,_,result) }
Method getConstructor() { cil_attribute(this, _, result) }
/** Gets the type of this attribute. */
Type getType() { result = getConstructor().getDeclaringType() }
@@ -24,7 +23,7 @@ class Attribute extends Element, @cil_attribute {
string getNamedArgument(string name) { cil_attribute_named_argument(this, name, result) }
/** Gets an argument of this attribute, if any. */
string getAnArgument() { result=getArgument(_) or result=getNamedArgument(_) }
string getAnArgument() { result = getArgument(_) or result = getNamedArgument(_) }
override CS::Location getLocation() { result=getDeclaration().getLocation() }
override CS::Location getLocation() { result = getDeclaration().getLocation() }
}

View File

@@ -10,14 +10,10 @@ private import CIL
*/
class BasicBlock extends Internal::TBasicBlockStart {
/** Gets an immediate successor of this basic block, if any. */
BasicBlock getASuccessor() {
result.getFirstNode() = getLastNode().getASuccessor()
}
BasicBlock getASuccessor() { result.getFirstNode() = getLastNode().getASuccessor() }
/** Gets an immediate predecessor of this basic block, if any. */
BasicBlock getAPredecessor() {
result.getASuccessor() = this
}
BasicBlock getAPredecessor() { result.getASuccessor() = this }
/**
* Gets an immediate `true` successor, if any.
@@ -35,9 +31,7 @@ class BasicBlock extends Internal::TBasicBlockStart {
* The basic block on line 2 is an immediate `true` successor of the
* basic block on line 1.
*/
BasicBlock getATrueSuccessor() {
result.getFirstNode() = getLastNode().getTrueSuccessor()
}
BasicBlock getATrueSuccessor() { result.getFirstNode() = getLastNode().getTrueSuccessor() }
/**
* Gets an immediate `false` successor, if any.
@@ -55,32 +49,22 @@ class BasicBlock extends Internal::TBasicBlockStart {
* The basic block on line 2 is an immediate `false` successor of the
* basic block on line 1.
*/
BasicBlock getAFalseSuccessor() {
result.getFirstNode() = getLastNode().getFalseSuccessor()
}
BasicBlock getAFalseSuccessor() { result.getFirstNode() = getLastNode().getFalseSuccessor() }
/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
ControlFlowNode getNode(int pos) { Internal::bbIndex(getFirstNode(), result, pos) }
/** Gets a control flow node in this basic block. */
ControlFlowNode getANode() {
result = getNode(_)
}
ControlFlowNode getANode() { result = getNode(_) }
/** Gets the first control flow node in this basic block. */
ControlFlowNode getFirstNode() {
this = Internal::TBasicBlockStart(result)
}
ControlFlowNode getFirstNode() { this = Internal::TBasicBlockStart(result) }
/** Gets the last control flow node in this basic block. */
ControlFlowNode getLastNode() {
result = getNode(length() - 1)
}
ControlFlowNode getLastNode() { result = getNode(length() - 1) }
/** Gets the length of this basic block. */
int length() {
result = strictcount(getANode())
}
int length() { result = strictcount(getANode()) }
/**
* Holds if this basic block strictly dominates basic block `bb`.
@@ -103,9 +87,7 @@ class BasicBlock extends Internal::TBasicBlockStart {
* basic block on line 4 (all paths from the entry point of `M`
* to `return s.Length;` must go through the null check).
*/
predicate strictlyDominates(BasicBlock bb) {
bbIDominates+(this, bb)
}
predicate strictlyDominates(BasicBlock bb) { bbIDominates+(this, bb) }
/**
* Holds if this basic block dominates basic block `bb`.
@@ -165,10 +147,7 @@ class BasicBlock extends Internal::TBasicBlockStart {
/**
* Holds if this basic block dominates a predecessor of `df`.
*/
private
predicate dominatesPredecessor(BasicBlock df) {
dominates(df.getAPredecessor())
}
private predicate dominatesPredecessor(BasicBlock df) { dominates(df.getAPredecessor()) }
/**
* Gets the basic block that immediately dominates this basic block, if any.
@@ -192,9 +171,7 @@ class BasicBlock extends Internal::TBasicBlockStart {
* to `return s.Length;` must go through the null check, and the null check
* is an immediate predecessor of `return s.Length;`).
*/
BasicBlock getImmediateDominator() {
bbIDominates(result, this)
}
BasicBlock getImmediateDominator() { bbIDominates(result, this) }
/**
* Holds if this basic block strictly post-dominates basic block `bb`.
@@ -220,9 +197,7 @@ class BasicBlock extends Internal::TBasicBlockStart {
* line 3 (all paths to the exit point of `M` from `return s.Length;`
* must go through the `WriteLine` call).
*/
predicate strictlyPostDominates(BasicBlock bb) {
bbIPostDominates+(this, bb)
}
predicate strictlyPostDominates(BasicBlock bb) { bbIPostDominates+(this, bb) }
/**
* Holds if this basic block post-dominates basic block `bb`.
@@ -261,23 +236,20 @@ class BasicBlock extends Internal::TBasicBlockStart {
* even if this basic block is syntactically inside a `while` loop if the
* necessary back edges are unreachable.
*/
predicate inLoop() {
this.getASuccessor+() = this
}
predicate inLoop() { this.getASuccessor+() = this }
/** Gets a textual representation of this basic block. */
string toString() {
result = getFirstNode().toString()
}
string toString() { result = getFirstNode().toString() }
}
/**
* Internal implementation details.
*/
private cached module Internal {
cached
private module Internal {
/** Internal representation of basic blocks. */
cached newtype TBasicBlock =
TBasicBlockStart(ControlFlowNode cfn) { startsBB(cfn) }
cached
newtype TBasicBlock = TBasicBlockStart(ControlFlowNode cfn) { startsBB(cfn) }
/** Holds if `cfn` starts a new basic block. */
private predicate startsBB(ControlFlowNode cfn) {
@@ -285,7 +257,9 @@ private cached module Internal {
or
cfn.isJoin()
or
exists(ControlFlowNode pred | pred = cfn.getAPredecessor() | strictcount(pred.getASuccessor()) > 1)
exists(ControlFlowNode pred | pred = cfn.getAPredecessor() |
strictcount(pred.getASuccessor()) > 1
)
}
/**
@@ -312,18 +286,13 @@ private cached module Internal {
* Holds if the first node of basic block `succ` is a control flow
* successor of the last node of basic block `pred`.
*/
private predicate succBB(BasicBlock pred, BasicBlock succ) {
succ = pred.getASuccessor()
}
private predicate succBB(BasicBlock pred, BasicBlock succ) { succ = pred.getASuccessor() }
/** Holds if `dom` is an immediate dominator of `bb`. */
predicate bbIDominates(BasicBlock dom, BasicBlock bb) =
idominance(entryBB/1, succBB/2)(_, dom, bb)
predicate bbIDominates(BasicBlock dom, BasicBlock bb) = idominance(entryBB/1, succBB/2)(_, dom, bb)
/** Holds if `pred` is a basic block predecessor of `succ`. */
private predicate predBB(BasicBlock succ, BasicBlock pred) {
succBB(pred, succ)
}
private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) }
/** Holds if `dom` is an immediate post-dominator of `bb`. */
predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
@@ -333,34 +302,24 @@ predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
* An entry basic block, that is, a basic block whose first node is
* the entry node of a callable.
*/
class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
}
class EntryBasicBlock extends BasicBlock { EntryBasicBlock() { entryBB(this) } }
/** Holds if `bb` is an entry basic block. */
private predicate entryBB(BasicBlock bb) {
bb.getFirstNode() instanceof EntryPoint
}
private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof EntryPoint }
/**
* An exit basic block, that is, a basic block whose last node is
* an exit node.
*/
class ExitBasicBlock extends BasicBlock {
ExitBasicBlock() { exitBB(this) }
}
class ExitBasicBlock extends BasicBlock { ExitBasicBlock() { exitBB(this) } }
/** Holds if `bb` is an exit basic block. */
private predicate exitBB(BasicBlock bb) {
not exists(bb.getLastNode().getASuccessor())
}
private predicate exitBB(BasicBlock bb) { not exists(bb.getLastNode().getASuccessor()) }
/**
* A basic block with more than one predecessor.
*/
class JoinBlock extends BasicBlock {
JoinBlock() { getFirstNode().isJoin() }
}
class JoinBlock extends BasicBlock { JoinBlock() { getFirstNode().isJoin() } }
/** A basic block that terminates in a condition, splitting the subsequent control flow. */
class ConditionBlock extends BasicBlock {
@@ -412,9 +371,9 @@ class ConditionBlock extends BasicBlock {
* that `this` strictly dominates `controlled` so that isn't necessary to check
* directly.
*/
exists(BasicBlock succ |
isCandidateSuccessor(succ, testIsTrue)
and
isCandidateSuccessor(succ, testIsTrue) and
succ.dominates(controlled)
)
}
@@ -424,11 +383,7 @@ class ConditionBlock extends BasicBlock {
testIsTrue = true and succ = getATrueSuccessor()
or
testIsTrue = false and succ = getAFalseSuccessor()
)
and
forall(BasicBlock pred |
pred = succ.getAPredecessor() and pred != this |
succ.dominates(pred)
)
) and
forall(BasicBlock pred | pred = succ.getAPredecessor() and pred != this | succ.dominates(pred))
}
}

View File

@@ -6,14 +6,10 @@ private import CIL
private import csharp as CS
private newtype ConsistencyCheck =
MissingEntityCheck()
or
TypeCheck(Type t)
or
CfgCheck(ControlFlowNode n)
or
DeclarationCheck(Declaration d)
or
MissingEntityCheck() or
TypeCheck(Type t) or
CfgCheck(ControlFlowNode n) or
DeclarationCheck(Declaration d) or
MissingCSharpCheck(CS::Declaration d)
/**
@@ -21,6 +17,7 @@ private newtype ConsistencyCheck =
*/
abstract class ConsistencyViolation extends ConsistencyCheck {
abstract string toString();
abstract string getMessage();
}
@@ -29,6 +26,7 @@ abstract class ConsistencyViolation extends ConsistencyCheck {
*/
abstract class DisabledCheck extends ConsistencyCheck {
DisabledCheck() { none() }
abstract string toString();
}
@@ -37,40 +35,45 @@ abstract class DisabledCheck extends ConsistencyCheck {
*/
class CfgViolation extends ConsistencyViolation, CfgCheck {
ControlFlowNode getNode() { this = CfgCheck(result) }
override string toString() { result = getNode().toString() }
override abstract string getMessage();
abstract override string getMessage();
}
/**
* A consistency violation in a specific instruction.
*/
class InstructionViolation extends CfgViolation, CfgCheck {
InstructionViolation() { exists(Instruction i | this=CfgCheck(i)) }
InstructionViolation() { exists(Instruction i | this = CfgCheck(i)) }
/** Gets the instruction containing the violation. */
Instruction getInstruction() { this = CfgCheck(result) }
private string getInstructionsUpTo() {
result = concat(Instruction i |
i.getIndex() <= this.getInstruction().getIndex() and
i.getImplementation() = this.getInstruction().getImplementation() |
i.toString() + " [push: " + i.getPushCount() + ", pop: " + i.getPopCount() + "]", "; " order by i.getIndex()
)
i.getIndex() <= this.getInstruction().getIndex() and
i.getImplementation() = this.getInstruction().getImplementation()
|
i.toString() + " [push: " + i.getPushCount() + ", pop: " + i.getPopCount() + "]", "; "
order by
i.getIndex()
)
}
override string toString() {
result = getInstruction().getImplementation().getMethod().toStringWithTypes() + ": " + getInstruction().toString() + ", " + getInstructionsUpTo()
result = getInstruction().getImplementation().getMethod().toStringWithTypes() + ": " +
getInstruction().toString() + ", " + getInstructionsUpTo()
}
override abstract string getMessage();
abstract override string getMessage();
}
/**
* A literal that does not have exactly one `getValue()`.
*/
class MissingValue extends InstructionViolation {
MissingValue() {
exists(Literal l | l = this.getInstruction() | count(l.getValue()) != 1)
}
MissingValue() { exists(Literal l | l = this.getInstruction() | count(l.getValue()) != 1) }
override string getMessage() { result = "Literal has invalid getValue()" }
}
@@ -79,23 +82,25 @@ class MissingValue extends InstructionViolation {
* A call that does not have exactly one `getTarget()`.
*/
class MissingCallTarget extends InstructionViolation {
MissingCallTarget() {
exists(Call c | c = this.getInstruction() | count(c.getTarget())!=1)
}
MissingCallTarget() { exists(Call c | c = this.getInstruction() | count(c.getTarget()) != 1) }
override string getMessage() { result = "Call has invalid target" }
}
/**
* An instruction that has not been assigned a specific QL class.
*/
class MissingOpCode extends InstructionViolation {
MissingOpCode() { not exists(this.getInstruction().getOpcodeName()) }
override string getMessage() { result = "Opcode " + this.getInstruction().getOpcode() + " is missing a QL class" }
override string toString() { result = "Unknown instruction in " + getInstruction().getImplementation().getMethod().toString() }
}
override string getMessage() {
result = "Opcode " + this.getInstruction().getOpcode() + " is missing a QL class"
}
override string toString() {
result = "Unknown instruction in " + getInstruction().getImplementation().getMethod().toString()
}
}
/**
* An instruction that is missing an operand. It means that there is no instruction which pushes
@@ -107,15 +112,19 @@ class MissingOpCode extends InstructionViolation {
*/
class MissingOperand extends InstructionViolation {
MissingOperand() {
exists(Instruction i, int op | i=getInstruction() and op in [0..i.getPopCount()-1] |
not exists(i.getOperand(op)) and not i instanceof DeadInstruction)
exists(Instruction i, int op | i = getInstruction() and op in [0 .. i.getPopCount() - 1] |
not exists(i.getOperand(op)) and not i instanceof DeadInstruction
)
}
int getMissingOperand() {
result in [0..getInstruction().getPopCount()-1] and not exists(getInstruction().getOperand(result))
result in [0 .. getInstruction().getPopCount() - 1] and
not exists(getInstruction().getOperand(result))
}
override string getMessage() { result = "This instruction is missing operand " + getMissingOperand() }
override string getMessage() {
result = "This instruction is missing operand " + getMissingOperand()
}
}
/**
@@ -123,11 +132,8 @@ class MissingOperand extends InstructionViolation {
* These should not exist, however it turns out that the Mono compiler sometimes
* emits them.
*/
class DeadInstruction extends Instruction
{
DeadInstruction() {
not exists(EntryPoint e | e.getASuccessor+() = this)
}
class DeadInstruction extends Instruction {
DeadInstruction() { not exists(EntryPoint e | e.getASuccessor+() = this) }
}
/**
@@ -137,11 +143,10 @@ class DeadInstruction extends Instruction
* Disabled, because Mono compiler sometimes emits dead instructions.
*/
class DeadInstructionViolation extends InstructionViolation, DisabledCheck {
DeadInstructionViolation() {
getInstruction() instanceof DeadInstruction
}
DeadInstructionViolation() { getInstruction() instanceof DeadInstruction }
override string getMessage() { result = "This instruction is not reachable" }
override string getMessage() { result="This instruction is not reachable" }
override string toString() { result = InstructionViolation.super.toString() }
}
@@ -156,11 +161,12 @@ class InvalidBranchSuccessors extends InstructionViolation {
InvalidBranchSuccessors() {
// Mono compiler sometimes generates branches to the next instruction, which is just wrong.
// However it is valid CIL.
exists(YesNoBranch i | i = getInstruction() | not count(i.getASuccessor()) in [1..2])
exists(YesNoBranch i | i = getInstruction() | not count(i.getASuccessor()) in [1 .. 2])
}
override string getMessage() {
result = "Conditional branch has " + count(this.getInstruction().getASuccessor()) + " successors"
result = "Conditional branch has " + count(this.getInstruction().getASuccessor()) +
" successors"
}
}
@@ -170,7 +176,8 @@ class InvalidBranchSuccessors extends InstructionViolation {
class OnlyYesNoBranchHasTrueFalseSuccessors extends InstructionViolation {
OnlyYesNoBranchHasTrueFalseSuccessors() {
exists(Instruction i | i = getInstruction() |
(exists(i.getTrueSuccessor()) or exists(i.getFalseSuccessor())) and not i instanceof YesNoBranch
(exists(i.getTrueSuccessor()) or exists(i.getFalseSuccessor())) and
not i instanceof YesNoBranch
)
}
@@ -185,7 +192,9 @@ class UnconditionalBranchSuccessors extends InstructionViolation {
exists(UnconditionalBranch i | i = getInstruction() | count(i.getASuccessor()) != 1)
}
override string getMessage() { result = "Unconditional branch has " + count(getInstruction().getASuccessor()) + " successors" }
override string getMessage() {
result = "Unconditional branch has " + count(getInstruction().getASuccessor()) + " successors"
}
}
/**
@@ -206,6 +215,7 @@ class NoFalseSuccessor extends InstructionViolation {
NoFalseSuccessor() {
exists(YesNoBranch i | i = getInstruction() | not exists(i.getFalseSuccessor()))
}
override string getMessage() { result = "Missing a false successor" }
}
@@ -214,7 +224,9 @@ class NoFalseSuccessor extends InstructionViolation {
*/
class TrueSuccessorIsSuccessor extends InstructionViolation {
TrueSuccessorIsSuccessor() {
exists(Instruction i | i = getInstruction() | exists(i.getTrueSuccessor()) and not i.getTrueSuccessor() = i.getASuccessor())
exists(Instruction i | i = getInstruction() |
exists(i.getTrueSuccessor()) and not i.getTrueSuccessor() = i.getASuccessor()
)
}
override string getMessage() { result = "True successor isn't a successor" }
@@ -225,7 +237,9 @@ class TrueSuccessorIsSuccessor extends InstructionViolation {
*/
class FalseSuccessorIsSuccessor extends InstructionViolation {
FalseSuccessorIsSuccessor() {
exists(Instruction i | i = getInstruction() | exists(i.getTrueSuccessor()) and not i.getTrueSuccessor() = i.getASuccessor())
exists(Instruction i | i = getInstruction() |
exists(i.getTrueSuccessor()) and not i.getTrueSuccessor() = i.getASuccessor()
)
}
override string getMessage() { result = "True successor isn't a successor" }
@@ -235,9 +249,7 @@ class FalseSuccessorIsSuccessor extends InstructionViolation {
* An access that does not have exactly one target.
*/
class AccessMissingTarget extends InstructionViolation {
AccessMissingTarget() {
exists(Access i | i = getInstruction() | count(i.getTarget()) != 1)
}
AccessMissingTarget() { exists(Access i | i = getInstruction() | count(i.getTarget()) != 1) }
override string getMessage() { result = "Access has invalid getTarget()" }
}
@@ -250,7 +262,7 @@ class CatchHandlerMissingType extends CfgViolation {
exists(CatchHandler h | h = getNode() | not exists(h.getCaughtType()))
}
override string getMessage () { result = "Catch handler missing caught type" }
override string getMessage() { result = "Catch handler missing caught type" }
}
/**
@@ -258,31 +270,33 @@ class CatchHandlerMissingType extends CfgViolation {
*/
class MissingStackSize extends CfgViolation {
MissingStackSize() {
exists(ControlFlowNode node | node=getNode() |
not exists(node.getStackSizeAfter())
or not exists(node.getStackSizeBefore())
)
and not getNode() instanceof DeadInstruction
exists(ControlFlowNode node | node = getNode() |
not exists(node.getStackSizeAfter()) or
not exists(node.getStackSizeBefore())
) and
not getNode() instanceof DeadInstruction
}
override string getMessage() { result = "Inconsistent stack size" }
}
/**
* A CFG node that does not have exactly one stack size.
* Disabled because inconsistent stack sizes have been observed.
*/
class InvalidStackSize extends CfgViolation, DisabledCheck {
InvalidStackSize() {
exists(ControlFlowNode node | node=getNode() |
count(node.getStackSizeAfter()) != 1
or count(node.getStackSizeBefore()) != 1
)
and not getNode() instanceof DeadInstruction
exists(ControlFlowNode node | node = getNode() |
count(node.getStackSizeAfter()) != 1 or
count(node.getStackSizeBefore()) != 1
) and
not getNode() instanceof DeadInstruction
}
override string getMessage() { result = "Inconsistent stack sizes " + count(getNode().getStackSizeBefore()) + " before and " + count(getNode().getStackSizeAfter()) + " after" }
override string getMessage() {
result = "Inconsistent stack sizes " + count(getNode().getStackSizeBefore()) + " before and " +
count(getNode().getStackSizeAfter()) + " after"
}
override string toString() { result = CfgViolation.super.toString() }
}
@@ -292,10 +306,12 @@ class InvalidStackSize extends CfgViolation, DisabledCheck {
*/
class InconsistentPopCount extends CfgViolation {
InconsistentPopCount() {
exists(ControlFlowNode node | node = getNode() | count(node.getPopCount()) !=1 )
exists(ControlFlowNode node | node = getNode() | count(node.getPopCount()) != 1)
}
override string getMessage() { result = "Cfg node has " + count(getNode().getPopCount()) + " pop counts" }
override string getMessage() {
result = "Cfg node has " + count(getNode().getPopCount()) + " pop counts"
}
}
/**
@@ -306,14 +322,17 @@ class InconsistentPushCount extends CfgViolation {
exists(ControlFlowNode node | node = getNode() | count(node.getPushCount()) != 1)
}
override string getMessage() { result = "Cfg node has " + count(getNode().getPushCount()) + " push counts" }
override string getMessage() {
result = "Cfg node has " + count(getNode().getPushCount()) + " push counts"
}
}
/**
* A return instruction that does not have a stack size of 0 after it.
*/
class InvalidReturn extends CfgViolation {
InvalidReturn() { getNode() instanceof Return and getNode().getStackSizeAfter()!=0 }
InvalidReturn() { getNode() instanceof Return and getNode().getStackSizeAfter() != 0 }
override string getMessage() { result = "Return has invalid stack size" }
}
@@ -321,7 +340,8 @@ class InvalidReturn extends CfgViolation {
* A throw instruction that does not have a stack size of 0 after it.
*/
class InvalidThrow extends CfgViolation {
InvalidThrow() { getNode() instanceof Throw and getNode().getStackSizeAfter()!=0 }
InvalidThrow() { getNode() instanceof Throw and getNode().getStackSizeAfter() != 0 }
override string getMessage() { result = "Throw has invalid stack size" }
}
@@ -330,9 +350,10 @@ class InvalidThrow extends CfgViolation {
*/
class StaticFieldTarget extends InstructionViolation {
StaticFieldTarget() {
exists(FieldAccess i | i=getInstruction() |
(i instanceof Opcodes::Stfld or i instanceof Opcodes::Stfld) and i.getTarget().isStatic()
)
exists(FieldAccess i | i = getInstruction() |
(i instanceof Opcodes::Stfld or i instanceof Opcodes::Stfld) and
i.getTarget().isStatic()
)
}
override string getMessage() { result = "Inconsistent static field" }
@@ -353,12 +374,12 @@ class BranchWithoutTarget extends InstructionViolation {
* A consistency violation in a type.
*/
class TypeViolation extends ConsistencyViolation, TypeCheck {
/** Gets the type containing the violation. */
Type getType() { this=TypeCheck(result) }
Type getType() { this = TypeCheck(result) }
override string toString() { result = getType().toString() }
override abstract string getMessage();
abstract override string getMessage();
}
/**
@@ -377,14 +398,18 @@ class TypeIsBothConstructedAndUnbound extends TypeViolation {
*/
class TypeParameterMismatch extends TypeViolation {
TypeParameterMismatch() {
getType().(ConstructedGeneric).getNumberOfTypeArguments() != getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters()
getType().(ConstructedGeneric).getNumberOfTypeArguments() != getType()
.getUnboundType()
.(UnboundGeneric)
.getNumberOfTypeParameters()
}
override string getMessage() {
result = "Constructed type (" + getType().toStringWithTypes() + ") has " +
getType().(ConstructedGeneric).getNumberOfTypeArguments() + " type arguments and unbound type (" +
getType().getUnboundType().toStringWithTypes() + ") has " +
getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() + " type parameters"
getType().(ConstructedGeneric).getNumberOfTypeArguments() +
" type arguments and unbound type (" + getType().getUnboundType().toStringWithTypes() +
") has " + getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() +
" type parameters"
}
}
@@ -392,11 +417,11 @@ class TypeParameterMismatch extends TypeViolation {
* A consistency violation in a method.
*/
class MethodViolation extends ConsistencyViolation, DeclarationCheck {
/** Gets the method containing the violation. */
Method getMethod() { this = DeclarationCheck(result) }
override string toString() { result = getMethod().toString() }
override string getMessage() { none() }
}
@@ -404,11 +429,16 @@ class MethodViolation extends ConsistencyViolation, DeclarationCheck {
* A constructed method that does not match its unbound method.
*/
class ConstructedMethodTypeParams extends MethodViolation {
ConstructedMethodTypeParams() { getMethod().(ConstructedGeneric).getNumberOfTypeArguments() != getMethod().getSourceDeclaration().(UnboundGeneric).getNumberOfTypeParameters() }
ConstructedMethodTypeParams() {
getMethod().(ConstructedGeneric).getNumberOfTypeArguments() != getMethod()
.getSourceDeclaration()
.(UnboundGeneric)
.getNumberOfTypeParameters()
}
override string getMessage() {
result = "The constructed method " + getMethod().toStringWithTypes() + " does not match unbound method " + getMethod().getSourceDeclaration().toStringWithTypes()
result = "The constructed method " + getMethod().toStringWithTypes() +
" does not match unbound method " + getMethod().getSourceDeclaration().toStringWithTypes()
}
}
@@ -424,6 +454,7 @@ abstract class MissingEntityViolation extends ConsistencyViolation, MissingEntit
*/
class MissingObjectViolation extends MissingEntityViolation {
MissingObjectViolation() { not exists(ObjectType o) }
override string getMessage() { result = "Object missing" }
}
@@ -433,7 +464,10 @@ class MissingObjectViolation extends MissingEntityViolation {
class InvalidOverride extends MethodViolation {
InvalidOverride() {
exists(Method base | base = getMethod().getOverriddenMethod() |
not getMethod().getDeclaringType().getABaseType+() = getMethod().getOverriddenMethod().getDeclaringType())
not getMethod().getDeclaringType().getABaseType+() = getMethod()
.getOverriddenMethod()
.getDeclaringType()
)
}
override string getMessage() { result = "Overridden method is not in a base type" }
@@ -443,9 +477,7 @@ class InvalidOverride extends MethodViolation {
* A pointer type that does not have a pointee type.
*/
class InvalidPointerType extends TypeViolation {
InvalidPointerType() {
exists(PointerType p | p = getType() | count(p.getReferentType()) != 1)
}
InvalidPointerType() { exists(PointerType p | p = getType() | count(p.getReferentType()) != 1) }
override string getMessage() { result = "Invalid Pointertype.getPointeeType()" }
}
@@ -454,9 +486,8 @@ class InvalidPointerType extends TypeViolation {
* An array with an invalid `getElementType`.
*/
class ArrayTypeMissingElement extends TypeViolation {
ArrayTypeMissingElement() {
exists(ArrayType t | t = getType() | count(t.getElementType())!=1)
}
ArrayTypeMissingElement() { exists(ArrayType t | t = getType() | count(t.getElementType()) != 1) }
override string getMessage() { result = "Invalid ArrayType.getElementType()" }
}
@@ -464,9 +495,8 @@ class ArrayTypeMissingElement extends TypeViolation {
* An array with an invalid `getRank`.
*/
class ArrayTypeInvalidRank extends TypeViolation {
ArrayTypeInvalidRank() {
exists(ArrayType t | t = getType() | not t.getRank() > 0)
}
ArrayTypeInvalidRank() { exists(ArrayType t | t = getType() | not t.getRank() > 0) }
override string getMessage() { result = "Invalid ArrayType.getRank()" }
}
@@ -474,7 +504,7 @@ class ArrayTypeInvalidRank extends TypeViolation {
* A violation in a `Member`.
*/
abstract class DeclarationViolation extends ConsistencyViolation, DeclarationCheck {
override abstract string getMessage();
abstract override string getMessage();
/** Gets the member containing the potential violation. */
Declaration getDeclaration() { this = DeclarationCheck(result) }
@@ -487,7 +517,7 @@ abstract class DeclarationViolation extends ConsistencyViolation, DeclarationChe
*/
class PropertyWithNoAccessors extends DeclarationViolation {
PropertyWithNoAccessors() {
exists(Property p | p=getDeclaration() | not exists(p.getAnAccessor()))
exists(Property p | p = getDeclaration() | not exists(p.getAnAccessor()))
}
override string getMessage() { result = "Property has no accessors" }
@@ -500,15 +530,14 @@ class ExprPushCount extends InstructionViolation {
ExprPushCount() {
this.getInstruction() instanceof Expr and
not this.getInstruction() instanceof Opcodes::Dup and
if
this.getInstruction() instanceof Call
then
not this.getInstruction().getPushCount() in [0..1]
else
this.getInstruction().(Expr).getPushCount() != 1
if this.getInstruction() instanceof Call
then not this.getInstruction().getPushCount() in [0 .. 1]
else this.getInstruction().(Expr).getPushCount() != 1
}
override string getMessage() { result = "Instruction has unexpected push count " + this.getInstruction().getPushCount() }
override string getMessage() {
result = "Instruction has unexpected push count " + this.getInstruction().getPushCount()
}
}
/**
@@ -518,12 +547,13 @@ class ExprPushCount extends InstructionViolation {
class ExprMissingType extends InstructionViolation {
ExprMissingType() {
// Don't have types for the following op codes:
not getInstruction() instanceof Opcodes::Ldftn
and not getInstruction() instanceof Opcodes::Localloc
and not getInstruction() instanceof Opcodes::Ldvirtftn
and not getInstruction() instanceof Opcodes::Arglist
and not getInstruction() instanceof Opcodes::Refanytype
and this.getInstruction().getPushCount() = 1 and count(this.getInstruction().getType()) != 1
not getInstruction() instanceof Opcodes::Ldftn and
not getInstruction() instanceof Opcodes::Localloc and
not getInstruction() instanceof Opcodes::Ldvirtftn and
not getInstruction() instanceof Opcodes::Arglist and
not getInstruction() instanceof Opcodes::Refanytype and
this.getInstruction().getPushCount() = 1 and
count(this.getInstruction().getType()) != 1
}
override string getMessage() { result = "Expression is missing getType()" }
@@ -533,8 +563,14 @@ class ExprMissingType extends InstructionViolation {
* An instruction that has a push count of 0, yet is still used as an operand
*/
class InvalidExpressionViolation extends InstructionViolation {
InvalidExpressionViolation() { getInstruction().getPushCount()=0 and exists(Instruction expr | getInstruction() = expr.getAnOperand()) }
override string getMessage() { result = "This instruction is used as an operand but pushes no values" }
InvalidExpressionViolation() {
getInstruction().getPushCount() = 0 and
exists(Instruction expr | getInstruction() = expr.getAnOperand())
}
override string getMessage() {
result = "This instruction is used as an operand but pushes no values"
}
}
/**
@@ -543,21 +579,22 @@ class InvalidExpressionViolation extends InstructionViolation {
*/
class TypeMultiplyDefined extends TypeViolation, DisabledCheck {
TypeMultiplyDefined() {
this.getType().getParent().getName()="System"
and
not this.getType() instanceof ConstructedGeneric
and
not this.getType() instanceof ArrayType
and
this.getType().isPublic()
and
count(Type t | not t instanceof ConstructedGeneric and t.toStringWithTypes() = this.getType().toStringWithTypes()) != 1
this.getType().getParent().getName() = "System" and
not this.getType() instanceof ConstructedGeneric and
not this.getType() instanceof ArrayType and
this.getType().isPublic() and
count(Type t |
not t instanceof ConstructedGeneric and
t.toStringWithTypes() = this.getType().toStringWithTypes()
) != 1
}
override string getMessage() {
result="This type (" + getType().toStringWithTypes() + ") has " +
count(Type t | not t instanceof ConstructedGeneric and t.toStringWithTypes() = this.getType().toStringWithTypes()) +
" entities"
result = "This type (" + getType().toStringWithTypes() + ") has " +
count(Type t |
not t instanceof ConstructedGeneric and
t.toStringWithTypes() = this.getType().toStringWithTypes()
) + " entities"
}
override string toString() { result = TypeViolation.super.toString() }
@@ -567,18 +604,19 @@ class TypeMultiplyDefined extends TypeViolation, DisabledCheck {
* A C# declaration which is expected to have a corresponding CIL declaration, but for some reason does not.
*/
class MissingCilDeclaration extends ConsistencyViolation, MissingCSharpCheck {
MissingCilDeclaration()
{
MissingCilDeclaration() {
exists(CS::Declaration decl | this = MissingCSharpCheck(decl) |
expectedCilDeclaration(decl)
and not exists(Declaration d | decl = d.getCSharpDeclaration())
)
expectedCilDeclaration(decl) and
not exists(Declaration d | decl = d.getCSharpDeclaration())
)
}
CS::Declaration getDeclaration() { this=MissingCSharpCheck(result) }
CS::Declaration getDeclaration() { this = MissingCSharpCheck(result) }
override string getMessage() { result = "Cannot locate CIL for " + getDeclaration().toStringWithTypes() + " of class " + getDeclaration().getAQlClass() }
override string getMessage() {
result = "Cannot locate CIL for " + getDeclaration().toStringWithTypes() + " of class " +
getDeclaration().getAQlClass()
}
override string toString() { result = getDeclaration().toStringWithTypes() }
}
@@ -586,20 +624,20 @@ class MissingCilDeclaration extends ConsistencyViolation, MissingCSharpCheck {
/**
* Holds if the C# declaration is expected to have a CIl declaration.
*/
private predicate expectedCilDeclaration(CS::Declaration decl)
{
decl=decl.getSourceDeclaration()
and not decl instanceof CS::ArrayType
and decl.getALocation() instanceof CS::Assembly
and not decl.(CS::Modifiable).isInternal()
and not decl.(CS::Constructor).getNumberOfParameters() = 0 // These are sometimes implicit
and not decl.(CS::Method).getReturnType() instanceof CS::UnknownType
and not exists(CS::Parameter p | p = decl.(CS::Parameterizable).getAParameter() | not expectedCilDeclaration(p))
and not decl instanceof CS::AnonymousClass
and (decl instanceof CS::Parameter implies expectedCilDeclaration(decl.(CS::Parameter).getType()))
and (decl instanceof CS::Parameter implies expectedCilDeclaration(decl.getParent()))
and (decl instanceof CS::Member implies expectedCilDeclaration(decl.getParent()))
and
private predicate expectedCilDeclaration(CS::Declaration decl) {
decl = decl.getSourceDeclaration() and
not decl instanceof CS::ArrayType and
decl.getALocation() instanceof CS::Assembly and
not decl.(CS::Modifiable).isInternal() and
not decl.(CS::Constructor).getNumberOfParameters() = 0 and // These are sometimes implicit
not decl.(CS::Method).getReturnType() instanceof CS::UnknownType and
not exists(CS::Parameter p | p = decl.(CS::Parameterizable).getAParameter() |
not expectedCilDeclaration(p)
) and
not decl instanceof CS::AnonymousClass and
(decl instanceof CS::Parameter implies expectedCilDeclaration(decl.(CS::Parameter).getType())) and
(decl instanceof CS::Parameter implies expectedCilDeclaration(decl.getParent())) and
(decl instanceof CS::Member implies expectedCilDeclaration(decl.getParent())) and
(
decl instanceof CS::Field
or
@@ -625,10 +663,10 @@ private predicate expectedCilDeclaration(CS::Declaration decl)
class MemberWithInvalidName extends DeclarationViolation {
MemberWithInvalidName() {
exists(string name | name = getDeclaration().(Member).getName() |
exists(name.indexOf("."))
and not name = ".ctor"
and not name = ".cctor"
)
exists(name.indexOf(".")) and
not name = ".ctor" and
not name = ".cctor"
)
}
override string getMessage() { result = "Invalid name " + getDeclaration().(Member).getName() }
@@ -638,31 +676,34 @@ class ConstructedSourceDeclarationMethod extends MethodViolation {
Method method;
ConstructedSourceDeclarationMethod() {
method = getMethod()
and method = method.getSourceDeclaration()
and (method instanceof ConstructedGeneric or method.getDeclaringType() instanceof ConstructedGeneric)
method = getMethod() and
method = method.getSourceDeclaration() and
(
method instanceof ConstructedGeneric or
method.getDeclaringType() instanceof ConstructedGeneric
)
}
override string getMessage() { result= "Source declaration " + method.toStringWithTypes() + " is constructed" }
override string getMessage() {
result = "Source declaration " + method.toStringWithTypes() + " is constructed"
}
}
/** A declaration with multiple labels. */
class DeclarationWithMultipleLabels extends DeclarationViolation {
DeclarationWithMultipleLabels() {
exists(Declaration d |
this = DeclarationCheck(d) |
strictcount(d.getLabel()) > 1
)
exists(Declaration d | this = DeclarationCheck(d) | strictcount(d.getLabel()) > 1)
}
override string getMessage() { result = "Multiple labels " + concat(getDeclaration().getLabel(), ", ") }
override string getMessage() {
result = "Multiple labels " + concat(getDeclaration().getLabel(), ", ")
}
}
/** A declaration without a label. */
class DeclarationWithoutLabel extends DeclarationViolation {
DeclarationWithoutLabel() {
exists(Declaration d |
this = DeclarationCheck(d) |
exists(Declaration d | this = DeclarationCheck(d) |
d.isSourceDeclaration() and
not d instanceof TypeParameter and
not exists(d.getLabel()) and

View File

@@ -5,8 +5,7 @@
private import CIL
/** A node in the control flow graph. */
class ControlFlowNode extends @cil_controlflow_node
{
class ControlFlowNode extends @cil_controlflow_node {
/** Gets a textual representation of this control flow node. */
string toString() { none() }
@@ -15,22 +14,23 @@ class ControlFlowNode extends @cil_controlflow_node
* This value is either 0 or 1, except for the instruction `dup`
* which pushes 2 values onto the stack.
*/
int getPushCount() { result=0 }
int getPushCount() { result = 0 }
/** Gets the number of items this node pops from the stack. */
int getPopCount() { result=0 }
int getPopCount() { result = 0 }
/** Gets a successor of this node, if any. */
final Instruction getASuccessor() { result=getASuccessorType(_) }
final Instruction getASuccessor() { result = getASuccessorType(_) }
/** Gets a true successor of this node, if any. */
final Instruction getTrueSuccessor() { result=getASuccessorType(any(TrueFlow f)) }
final Instruction getTrueSuccessor() { result = getASuccessorType(any(TrueFlow f)) }
/** Gets a false successor of this node, if any. */
final Instruction getFalseSuccessor() { result=getASuccessorType(any(FalseFlow f)) }
final Instruction getFalseSuccessor() { result = getASuccessorType(any(FalseFlow f)) }
/** Gets a successor to this node, of type `type`, if any. */
cached Instruction getASuccessorType(FlowType t) { none() }
cached
Instruction getASuccessorType(FlowType t) { none() }
/** Gets a predecessor of this node, if any. */
ControlFlowNode getAPredecessor() { result.getASuccessor() = this }
@@ -47,20 +47,17 @@ class ControlFlowNode extends @cil_controlflow_node
i < result.getPushCount()
or
// Transitive predecessor pushes the operand
exists(ControlFlowNode mid, int pushes |
this.getOperandRec(mid, i, pushes) |
exists(ControlFlowNode mid, int pushes | this.getOperandRec(mid, i, pushes) |
pushes - mid.getStackDelta() < result.getPushCount() and
result = mid.getAPredecessor()
)
}
/** Gets an operand of this instruction, if any. */
ControlFlowNode getAnOperand() { result=getOperand(_) }
ControlFlowNode getAnOperand() { result = getOperand(_) }
/** Gets an expression that consumes the output of this instruction on the stack. */
Instruction getParentExpr() {
this=result.getAnOperand()
}
Instruction getParentExpr() { this = result.getAnOperand() }
/**
* Holds if `pred` is a transitive predecessor of this instruction, this
@@ -70,15 +67,13 @@ class ControlFlowNode extends @cil_controlflow_node
*/
private predicate getOperandRec(ControlFlowNode pred, int i, int pushes) {
// Invariant: no node is a push for operand `i`
pushes >= pred.getPushCount()
and
pushes >= pred.getPushCount() and
(
i in [0 .. this.getPopCount() - 1] and
pred = this.getAPredecessor() and
pushes = i
or
exists(ControlFlowNode mid, int pushes0 |
this.getOperandRec(mid, i, pushes0) |
exists(ControlFlowNode mid, int pushes0 | this.getOperandRec(mid, i, pushes0) |
pushes = pushes0 - mid.getStackDelta() and
// This is a guard to prevent ill formed programs
// and other logic errors going into an infinite loop.
@@ -88,21 +83,16 @@ class ControlFlowNode extends @cil_controlflow_node
)
}
private int getStackDelta() { result = getPushCount()-getPopCount() }
private int getStackDelta() { result = getPushCount() - getPopCount() }
/** Gets the stack size before this instruction. */
int getStackSizeBefore()
{
result = getAPredecessor().getStackSizeAfter()
}
int getStackSizeBefore() { result = getAPredecessor().getStackSizeAfter() }
/** Gets the stack size after this instruction. */
final int getStackSizeAfter()
{
final int getStackSizeAfter() {
// This is a guard to prevent ill formed programs
// and other logic errors going into an infinite loop.
result in [0..getImplementation().getStackSize()]
and
result in [0 .. getImplementation().getStackSize()] and
result = getStackSizeBefore() + getStackDelta()
}
@@ -110,10 +100,11 @@ class ControlFlowNode extends @cil_controlflow_node
MethodImplementation getImplementation() { none() }
/** Gets the type of the item pushed onto the stack, if any. */
cached Type getType() { none() }
cached
Type getType() { none() }
/** Holds if this control flow node has more than one predecessor. */
predicate isJoin() { count(getAPredecessor())>1 }
predicate isJoin() { count(getAPredecessor()) > 1 }
}
/**
@@ -122,27 +113,22 @@ class ControlFlowNode extends @cil_controlflow_node
* Handlers are control flow nodes because they push the handled exception onto the stack.
*/
class EntryPoint extends ControlFlowNode, @cil_entry_point {
override int getStackSizeBefore() { result=0 }
override int getStackSizeBefore() { result = 0 }
}
private newtype TFlowType = TNormalFlow() or TTrueFlow() or TFalseFlow()
private newtype TFlowType =
TNormalFlow() or
TTrueFlow() or
TFalseFlow()
/** A type of control flow. Either normal flow (`NormalFlow`), true flow (`TrueFlow`) or false flow (`FalseFlow`). */
abstract class FlowType extends TFlowType {
abstract string toString();
}
abstract class FlowType extends TFlowType { abstract string toString(); }
/** Normal control flow. */
class NormalFlow extends FlowType, TNormalFlow {
override string toString() { result="" }
}
class NormalFlow extends FlowType, TNormalFlow { override string toString() { result = "" } }
/** True control flow. */
class TrueFlow extends FlowType, TTrueFlow {
override string toString() { result="true" }
}
class TrueFlow extends FlowType, TTrueFlow { override string toString() { result = "true" } }
/** False control flow. */
class FalseFlow extends FlowType, TTrueFlow {
override string toString() { result="false" }
}
class FalseFlow extends FlowType, TTrueFlow { override string toString() { result = "false" } }

View File

@@ -21,19 +21,15 @@ class DataFlowNode extends @cil_dataflow_node {
* `tt` is the tainting that occurs during this step.
*/
predicate getALocalFlowSucc(DataFlowNode sink, TaintType tt) {
localExactStep(this, sink) and tt=TExactValue()
localExactStep(this, sink) and tt = TExactValue()
or
localTaintStep(this, sink) and tt=TTaintedValue()
localTaintStep(this, sink) and tt = TTaintedValue()
}
private predicate flowsToStep(DataFlowNode sink) {
this.getALocalFlowSucc(sink, TExactValue())
}
private predicate flowsToStep(DataFlowNode sink) { this.getALocalFlowSucc(sink, TExactValue()) }
/** Holds if this node flows to `sink` in zero or more steps. */
predicate flowsTo(DataFlowNode sink) {
this.flowsToStep*(sink)
}
predicate flowsTo(DataFlowNode sink) { this.flowsToStep*(sink) }
/** Gets the method that contains this dataflow node. */
Method getMethod() { none() }
@@ -49,57 +45,68 @@ private newtype TTaintType =
/** Describes how data is tainted. */
class TaintType extends TTaintType {
string toString() {
this=TExactValue() and result = "exact"
or this=TTaintedValue() and result = "tainted"
this = TExactValue() and result = "exact"
or
this = TTaintedValue() and result = "tainted"
}
}
/** A taint type where the data is untainted. */
class Untainted extends TaintType, TExactValue {
}
class Untainted extends TaintType, TExactValue { }
/** A taint type where the data is tainted. */
class Tainted extends TaintType, TTaintedValue {
}
class Tainted extends TaintType, TTaintedValue { }
private predicate localExactStep(DataFlowNode src, DataFlowNode sink) {
src = sink.(Opcodes::Dup).getAnOperand()
or DefUse::defUse(_, src, sink)
or src=sink.(ParameterReadAccess).getTarget()
or src=sink.(Conversion).getExpr()
or src=sink.(WriteAccess).getExpr()
or src=sink.(Method).getAnImplementation().getAnInstruction().(Return)
or src=sink.(Return).getExpr()
or src=sink.(ConditionalBranch).getAnOperand()
or src=sink.(Parameter).getAWrite()
or exists(VariableUpdate update | update.getVariable().(Parameter)=sink and src=update.getSource())
or
DefUse::defUse(_, src, sink)
or
src = sink.(ParameterReadAccess).getTarget()
or
src = sink.(Conversion).getExpr()
or
src = sink.(WriteAccess).getExpr()
or
src = sink.(Method).getAnImplementation().getAnInstruction().(Return)
or
src = sink.(Return).getExpr()
or
src = sink.(ConditionalBranch).getAnOperand()
or
src = sink.(Parameter).getAWrite()
or
exists(VariableUpdate update |
update.getVariable().(Parameter) = sink and src = update.getSource()
)
}
private predicate localTaintStep(DataFlowNode src, DataFlowNode sink) {
src=sink.(BinaryArithmeticExpr).getAnOperand()
or src=sink.(Opcodes::Neg).getOperand()
or src=sink.(UnaryBitwiseOperation).getOperand()
src = sink.(BinaryArithmeticExpr).getAnOperand() or
src = sink.(Opcodes::Neg).getOperand() or
src = sink.(UnaryBitwiseOperation).getOperand()
}
private cached module DefUse {
cached
private module DefUse {
/**
* A classification of variable references into reads and writes.
*/
private newtype RefKind = Read() or Write()
private newtype RefKind =
Read() or
Write()
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
* either a read (when `k` is `Read()`) or a write (when `k` is `Write()`).
*/
private predicate ref(BasicBlock bb, int i, StackVariable v, RefKind k) {
exists(ReadAccess ra |
bb.getNode(i) = ra |
exists(ReadAccess ra | bb.getNode(i) = ra |
ra.getTarget() = v and
k = Read()
)
or
exists(VariableUpdate vu |
bb.getNode(i) = vu |
exists(VariableUpdate vu | bb.getNode(i) = vu |
vu.getVariable() = v and
k = Write()
)
@@ -156,10 +163,7 @@ private cached module DefUse {
private predicate defReachesEndOfBlock(BasicBlock bb, VariableUpdate vu, StackVariable v) {
liveAtExit(bb, v) and
(
exists(int last |
last = max(refRank(bb, _, v, _)) |
defReachesRank(bb, vu, last, v)
)
exists(int last | last = max(refRank(bb, _, v, _)) | defReachesRank(bb, vu, last, v))
or
exists(BasicBlock pred |
pred = bb.getAPredecessor() and
@@ -184,8 +188,7 @@ private cached module DefUse {
/** Holds if the update `def` can be used at the read `use`. */
cached
predicate defUse(StackVariable target, DataFlowNode def, ReadAccess use) {
exists(VariableUpdate vu |
def = vu.getSource() |
exists(VariableUpdate vu | def = vu.getSource() |
defReachesReadWithinBlock(target, vu, use)
or
exists(BasicBlock bb, int i |
@@ -198,26 +201,26 @@ private cached module DefUse {
}
}
library abstract class VariableUpdate extends Instruction {
abstract library class VariableUpdate extends Instruction {
abstract Expr getSource();
abstract Variable getVariable();
}
private class VariableWrite extends VariableUpdate, WriteAccess {
override Expr getSource() { result=getExpr() }
override Variable getVariable() { result=getTarget() }
override Expr getSource() { result = getExpr() }
override Variable getVariable() { result = getTarget() }
}
private class MethodOutOrRefTarget extends VariableUpdate, Call {
int parameterIndex;
MethodOutOrRefTarget() {
this.getTarget().getRawParameter(parameterIndex).hasOutFlag()
}
MethodOutOrRefTarget() { this.getTarget().getRawParameter(parameterIndex).hasOutFlag() }
override Variable getVariable() {
result=this.getRawArgument(parameterIndex).(ReadAccess).getTarget()
result = this.getRawArgument(parameterIndex).(ReadAccess).getTarget()
}
override Expr getSource() { result=this }
override Expr getSource() { result = this }
}

View File

@@ -10,9 +10,8 @@ private import semmle.code.csharp.Member as CS
* A declaration. Either a member (`Member`) or a variable (`Variable`).
*/
class Declaration extends DotNet::Declaration, Element, @cil_declaration {
/** Gets an attribute (for example `[Obsolete]`) of this declaration, if any. */
Attribute getAnAttribute() { result.getDeclaration()=this }
Attribute getAnAttribute() { result.getDeclaration() = this }
/**
* Gets the C# declaration corresponding to this CIL declaration, if any.
@@ -23,21 +22,19 @@ class Declaration extends DotNet::Declaration, Element, @cil_declaration {
result = toCSharpTypeParameter(this)
}
override Declaration getSourceDeclaration() { result=this }
override Declaration getSourceDeclaration() { result = this }
/** Holds if this declaration is a source declaration. */
final predicate isSourceDeclaration() { this=getSourceDeclaration() }
final predicate isSourceDeclaration() { this = getSourceDeclaration() }
}
private CS::Declaration toCSharpNonTypeParameter(Declaration d) {
result.getLabel() = d.getLabel()
}
private CS::Declaration toCSharpNonTypeParameter(Declaration d) { result.getLabel() = d.getLabel() }
private CS::TypeParameter toCSharpTypeParameter(TypeParameter tp) {
toCSharpTypeParameterJoin(tp, result.getIndex(), result.getGeneric())
}
pragma [noinline, nomagic]
pragma[noinline, nomagic]
private predicate toCSharpTypeParameterJoin(TypeParameter tp, int i, CS::UnboundGeneric ug) {
exists(TypeContainer tc |
tp.getIndex() = i and
@@ -87,17 +84,20 @@ class Property extends DotNet::Property, Member, @cil_property {
override ValueOrRefType getDeclaringType() { cil_property(this, result, _, _) }
/** Gets the getter of this property, if any. */
override Getter getGetter() { this=result.getProperty() }
override Getter getGetter() { this = result.getProperty() }
/** Gets the setter of this property, if any. */
override Setter getSetter() { this=result.getProperty() }
override Setter getSetter() { this = result.getProperty() }
/** Gets an accessor of this property. */
Accessor getAnAccessor() { result=getGetter() or result=getSetter() }
Accessor getAnAccessor() { result = getGetter() or result = getSetter() }
override string toString() { result="property " + getName() }
override string toString() { result = "property " + getName() }
override string toStringWithTypes() { result=getType().toStringWithTypes() + " " + getDeclaringType().toStringWithTypes() + "." + getName() }
override string toStringWithTypes() {
result = getType().toStringWithTypes() + " " + getDeclaringType().toStringWithTypes() + "." +
getName()
}
}
/** A property that is trivial (wraps a field). */
@@ -107,16 +107,16 @@ class TrivialProperty extends Property {
}
/** Gets the underlying field of this property. */
Field getField() { result=getGetter().(TrivialGetter).getField() }
Field getField() { result = getGetter().(TrivialGetter).getField() }
}
/** An event. */
class Event extends DotNet::Event, Member, @cil_event
{
class Event extends DotNet::Event, Member, @cil_event {
override string getName() { cil_event(this, _, result, _) }
/** Gets the type of this event. */
Type getType() { cil_event(this, _, _, result) }
override ValueOrRefType getDeclaringType() { cil_event(this, result, _, _) }
/** Gets the add event accessor. */
@@ -128,7 +128,9 @@ class Event extends DotNet::Event, Member, @cil_event
/** Gets the raiser. */
Method getRaiser() { cil_raiser(this, result) }
override string toString() { result="event " + getName() }
override string toString() { result = "event " + getName() }
override string toStringWithTypes() { result=getDeclaringType().toStringWithTypes() + "." + getName() }
override string toStringWithTypes() {
result = getDeclaringType().toStringWithTypes() + "." + getName()
}
}

View File

@@ -1,4 +1,5 @@
/** Provides classes for generic types and methods. */
private import CIL
private import dotnet
@@ -15,24 +16,16 @@ class Generic extends DotNet::Generic, Declaration, TypeContainer {
/** An unbound generic type or method. */
class UnboundGeneric extends Generic, DotNet::UnboundGeneric {
UnboundGeneric() {
cil_type_parameter(this, _, _)
}
UnboundGeneric() { cil_type_parameter(this, _, _) }
final override TypeParameter getTypeParameter(int n) {
cil_type_parameter(this, n, result)
}
final override TypeParameter getTypeParameter(int n) { cil_type_parameter(this, n, result) }
}
/** A constructed generic type or method. */
class ConstructedGeneric extends Generic, DotNet::ConstructedGeneric {
ConstructedGeneric() {
cil_type_argument(this, _, _)
}
ConstructedGeneric() { cil_type_argument(this, _, _) }
final override Type getTypeArgument(int n) {
cil_type_argument(this, n, result)
}
final override Type getTypeArgument(int n) { cil_type_argument(this, n, result) }
}
/** An unbound generic type. */
@@ -48,7 +41,5 @@ class ConstructedType extends ConstructedGeneric, Type { }
class ConstructedMethod extends ConstructedGeneric, Method {
final override UnboundGenericMethod getUnboundGeneric() { result = getUnboundMethod() }
final override Location getLocation() {
result = getUnboundGeneric().getLocation()
}
final override Location getLocation() { result = getUnboundGeneric().getLocation() }
}

View File

@@ -19,70 +19,65 @@ private import CIL
* Either a finally handler (`FinallyHandler`), filter handler (`FilterHandler`),
* catch handler (`CatchHandler`), or a fault handler (`FaultHandler`).
*/
class Handler extends Element, EntryPoint, @cil_handler
{
override MethodImplementation getImplementation() { cil_handler(this,result,_,_,_,_,_) }
class Handler extends Element, EntryPoint, @cil_handler {
override MethodImplementation getImplementation() { cil_handler(this, result, _, _, _, _, _) }
/** Gets the 0-based index of this handler. Handlers are evaluated in this sequence. */
int getIndex() { cil_handler(this, _, result, _, _, _, _) }
/** Gets the first instruction in the `try` block of this handler. */
Instruction getTryStart() { cil_handler(this,_,_,_,result,_,_) }
Instruction getTryStart() { cil_handler(this, _, _, _, result, _, _) }
/** Gets the last instruction in the `try` block of this handler. */
Instruction getTryEnd() { cil_handler(this,_,_,_,_,result,_) }
Instruction getTryEnd() { cil_handler(this, _, _, _, _, result, _) }
/** Gets the first instruction in the `catch`/`finally` block. */
Instruction getHandlerStart() { cil_handler(this,_,_,_,_,_,result) }
Instruction getHandlerStart() { cil_handler(this, _, _, _, _, _, result) }
/**
* Holds if the instruction `i` is in the scope of this handler.
*/
predicate isInScope(Instruction i) {
i.getImplementation() = getImplementation()
and
i.getIndex() in [getTryStart().getIndex()..getTryEnd().getIndex()]
i.getImplementation() = getImplementation() and
i.getIndex() in [getTryStart().getIndex() .. getTryEnd().getIndex()]
}
override string toString() { none() }
override Instruction getASuccessorType(FlowType t) {
result = getHandlerStart()
and
result = getHandlerStart() and
t instanceof NormalFlow
}
/** Gets the type of the caught exception, if any. */
Type getCaughtType() { cil_handler_type(this,result) }
Type getCaughtType() { cil_handler_type(this, result) }
override Location getLocation() { result=getTryStart().getLocation() }
override Location getLocation() { result = getTryStart().getLocation() }
}
/** A handler corresponding to a `finally` block. */
class FinallyHandler extends Handler, @cil_finally_handler
{
class FinallyHandler extends Handler, @cil_finally_handler {
override string toString() { result = "finally {...}" }
}
/** A handler corresponding to a `where()` clause. */
class FilterHandler extends Handler, @cil_filter_handler
{
override string toString() { result="where (...)" }
class FilterHandler extends Handler, @cil_filter_handler {
override string toString() { result = "where (...)" }
/** Gets the filter clause - the start of a sequence of instructions to evaluate the filter function. */
Instruction getFilterClause() { cil_handler_filter(this, result) }
override int getPushCount() { result=1 }
override int getPushCount() { result = 1 }
}
/** A handler corresponding to a `catch` clause. */
class CatchHandler extends Handler, @cil_catch_handler
{
override string toString() { result="catch(" + getCaughtType().getName() + ") {...}" }
override int getPushCount() { result=1 }
class CatchHandler extends Handler, @cil_catch_handler {
override string toString() { result = "catch(" + getCaughtType().getName() + ") {...}" }
override int getPushCount() { result = 1 }
}
/** A handler for memory faults. */
class FaultHandler extends Handler, @cil_fault_handler
{
override string toString() { result="fault {...}" }
class FaultHandler extends Handler, @cil_fault_handler {
override string toString() { result = "fault {...}" }
}

View File

@@ -3,16 +3,13 @@
private import CIL
/** An instruction. */
class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instruction
{
override string toString() { result=getIndex() + ": " + getOpcodeName() + getExtraStr() }
class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instruction {
override string toString() { result = getIndex() + ": " + getOpcodeName() + getExtraStr() }
/** Gets the method containing this instruction. */
override MethodImplementation getImplementation() {
cil_instruction(this, _, _, result)
}
override MethodImplementation getImplementation() { cil_instruction(this, _, _, result) }
override Method getMethod() { result=getImplementation().getMethod() }
override Method getMethod() { result = getImplementation().getMethod() }
/**
* Gets the index of this instruction.
@@ -21,7 +18,7 @@ class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instructi
int getIndex() { cil_instruction(this, _, result, _) }
/** Gets the opcode of this instruction. */
final int getOpcode() { cil_instruction(this,result,_,_) }
final int getOpcode() { cil_instruction(this, result, _, _) }
/** Gets the opcode name of this instruction, for example `ldnull`. */
string getOpcodeName() { none() }
@@ -30,9 +27,7 @@ class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instructi
string getExtra() { none() }
private string getExtraStr() {
if exists(getExtra())
then result = " " + getExtra()
else result = ""
if exists(getExtra()) then result = " " + getExtra() else result = ""
}
/** Gets the declaration accessed by this instruction, if any. */
@@ -40,11 +35,9 @@ class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instructi
/** Gets a successor instruction to this instruction. */
override Instruction getASuccessorType(FlowType t) {
t instanceof NormalFlow
and
canFlowNext()
and
result = this.getImplementation().getInstruction(getIndex()+1)
t instanceof NormalFlow and
canFlowNext() and
result = this.getImplementation().getInstruction(getIndex() + 1)
}
/** Holds if this instruction passes control flow into the next instruction. */
@@ -54,22 +47,20 @@ class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instructi
* Gets the `i`th handler that applies to this instruction.
* Indexed from 0.
*/
Handler getHandler(int i)
{
result.isInScope(this)
and
result.getIndex() = rank[i+1](int hi | exists(Handler h | h.isInScope(this) and hi=h.getIndex()))
Handler getHandler(int i) {
result.isInScope(this) and
result.getIndex() = rank[i + 1](int hi |
exists(Handler h | h.isInScope(this) and hi = h.getIndex())
)
}
override Type getType() { result=ControlFlowNode.super.getType() }
override Type getType() { result = ControlFlowNode.super.getType() }
override Location getALocation() {
cil_instruction_location(this, result) // The source code, if available
cil_instruction_location(this, result) // The source code, if available
or
result = getImplementation().getLocation() // The containing assembly
result = getImplementation().getLocation() // The containing assembly
}
override Location getLocation() {
result = Element.super.getLocation()
}
override Location getLocation() { result = Element.super.getLocation() }
}

View File

@@ -10,49 +10,56 @@ private import dotnet
* An instruction that pushes a value onto the stack.
*/
class Expr extends DotNet::Expr, Instruction, @cil_expr {
override int getPushCount() { result=1 }
override Type getType() { result=Instruction.super.getType() }
override Method getEnclosingCallable() { result=getImplementation().getMethod() }
override int getPushCount() { result = 1 }
override Type getType() { result = Instruction.super.getType() }
override Method getEnclosingCallable() { result = getImplementation().getMethod() }
/**
* The "parent" of a CIL expression is taken to be the instruction
* that consumes the value pushed by this instruction.
*/
override Expr getParent() { this=result.getAnOperand() }
override Expr getParent() { this = result.getAnOperand() }
}
/** An instruction that changes control flow. */
class Branch extends Instruction, @cil_jump {
/** Gets the instruction that is jumped to. */
Instruction getTarget() { cil_jump(this, result) }
override string getExtra() { result=getTarget().getIndex() + ":" }
override string getExtra() { result = getTarget().getIndex() + ":" }
}
/** An instruction that unconditionally jumps to another instruction. */
class UnconditionalBranch extends Branch, @cil_unconditional_jump {
override Instruction getASuccessorType(FlowType t) { t instanceof NormalFlow and result=getTarget() }
override Instruction getASuccessorType(FlowType t) {
t instanceof NormalFlow and result = getTarget()
}
override predicate canFlowNext() { none() }
}
/** An instruction that jumps to a target based on a condition. */
class ConditionalBranch extends Branch, @cil_conditional_jump {
override Instruction getASuccessorType(FlowType t) {
t instanceof TrueFlow and result = getTarget() or
t instanceof FalseFlow and result = getImplementation().getInstruction(getIndex()+1)
t instanceof TrueFlow and result = getTarget()
or
t instanceof FalseFlow and result = getImplementation().getInstruction(getIndex() + 1)
}
override int getPushCount() { result=0 }
override int getPushCount() { result = 0 }
}
/** An expression with two operands. */
class BinaryExpr extends Expr, @cil_binary_expr {
override int getPopCount() { result=2 }
}
class BinaryExpr extends Expr, @cil_binary_expr { override int getPopCount() { result = 2 } }
/** An expression with one operand. */
class UnaryExpr extends Expr, @cil_unary_expr {
override int getPopCount() { result=1 }
override int getPopCount() { result = 1 }
/** Gets the operand of this unary expression. */
Expr getOperand() { result=getOperand(0) }
Expr getOperand() { result = getOperand(0) }
}
/** A binary expression that compares two values. */
@@ -63,10 +70,16 @@ class ComparisonOperation extends BinaryExpr, @cil_comparison_operation {
/** A binary arithmetic expression. */
class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation {
override Type getType() {
exists(Type t0, Type t1 | t0=getOperand(0).getType().getUnderlyingType() and t1=getOperand(1).getType().getUnderlyingType() |
t0=t1 and result=t0 or
t0.getConversionIndex() < t1.getConversionIndex() and result=t1 or
t0.getConversionIndex() > t1.getConversionIndex() and result=t0)
exists(Type t0, Type t1 |
t0 = getOperand(0).getType().getUnderlyingType() and
t1 = getOperand(1).getType().getUnderlyingType()
|
t0 = t1 and result = t0
or
t0.getConversionIndex() < t1.getConversionIndex() and result = t1
or
t0.getConversionIndex() > t1.getConversionIndex() and result = t0
)
}
}
@@ -85,16 +98,14 @@ class UnaryBitwiseOperation extends UnaryExpr, @cil_unary_bitwise_operation {
/** A unary expression that converts a value from one primitive type to another. */
class Conversion extends UnaryExpr, @cil_conversion_operation {
/** Gets the expression being converted. */
Expr getExpr() { result=getOperand(0) }
Expr getExpr() { result = getOperand(0) }
}
/** A branch that leaves the scope of a `Handler`. */
class Leave extends UnconditionalBranch, @cil_leave_any {
}
class Leave extends UnconditionalBranch, @cil_leave_any { }
/** An expression that pushes a literal value onto the stack. */
class Literal extends DotNet::Literal, Expr, @cil_literal
{
class Literal extends DotNet::Literal, Expr, @cil_literal {
/** Gets the pushed value. */
override string getValue() { cil_value(this, result) }
@@ -104,73 +115,74 @@ class Literal extends DotNet::Literal, Expr, @cil_literal
/** An integer literal. */
class IntLiteral extends Literal, @cil_ldc_i {
override string getExtra() { none() }
override IntType getType() { exists(result) }
}
/** An expression that pushes a `float`/`Single`. */
class FloatLiteral extends Literal, @cil_ldc_r {
}
class FloatLiteral extends Literal, @cil_ldc_r { }
/** An expression that pushes a `null` value onto the stack. */
class NullLiteral extends Literal, @cil_ldnull {
}
class NullLiteral extends Literal, @cil_ldnull { }
/** A branch with one operand. */
class UnaryBranch extends ConditionalBranch, @cil_unary_jump {
override int getPopCount() { result=1 }
override int getPushCount() { result=0 }
override int getPopCount() { result = 1 }
override int getPushCount() { result = 0 }
}
/** A branch with two operands. */
class BinaryBranch extends ConditionalBranch, @cil_binary_jump {
override int getPopCount() { result=2 }
override int getPushCount() { result=0 }
override int getPopCount() { result = 2 }
override int getPushCount() { result = 0 }
}
/** A call. */
class Call extends Expr, DotNet::Call, @cil_call_any {
/** Gets the method that is called. */
override Method getTarget() { cil_access(this, result) }
override Method getARuntimeTarget() {
result = getTarget().getAnOverrider*()
}
override Method getARuntimeTarget() { result = getTarget().getAnOverrider*() }
override string getExtra() { result=getTarget().getQualifiedName() }
override string getExtra() { result = getTarget().getQualifiedName() }
/**
* Gets the return type of the call. Methods that do not return a value
* return the `void` type, `System.Void`, although the value of `getPushCount` is
* 0 in this case.
*/
override Type getType() { result=getTarget().getReturnType() }
override Type getType() { result = getTarget().getReturnType() }
// The number of items popped/pushed from the stack
// depends on the target of the call.
override int getPopCount() { result=getTarget().getCallPopCount() }
override int getPushCount() { result=getTarget().getCallPushCount() }
override int getPopCount() { result = getTarget().getCallPopCount() }
override int getPushCount() { result = getTarget().getCallPushCount() }
/**
* Holds if this is a "tail call", meaning that control does not return to the
* calling method.
*/
predicate isTailCall() {
getImplementation().getInstruction(getIndex()-1) instanceof Opcodes::Tail
getImplementation().getInstruction(getIndex() - 1) instanceof Opcodes::Tail
}
/** Holds if this call is virtual and could go to an overriding method. */
predicate isVirtual() { none() }
override Expr getRawArgument(int i) { result=getOperand(getPopCount() - i - 1) }
override Expr getRawArgument(int i) { result = getOperand(getPopCount() - i - 1) }
/** Gets the qualifier of this call, if any. */
Expr getQualifier() { result=getRawArgument(0) and not getTarget().isStatic() }
Expr getQualifier() { result = getRawArgument(0) and not getTarget().isStatic() }
override Expr getArgument(int i) {
if getTarget().isStatic()
then result=getRawArgument(i)
else (result=getRawArgument(i+1) and i>=0)
then result = getRawArgument(i)
else (
result = getRawArgument(i + 1) and i >= 0
)
}
override Expr getArgumentForParameter(DotNet::Parameter param) {
@@ -183,24 +195,20 @@ class Call extends Expr, DotNet::Call, @cil_call_any {
/** A tail call. */
class TailCall extends Call {
TailCall() { this.isTailCall() }
override predicate canFlowNext() { none() }
}
/** A call to a static target. */
class StaticCall extends Call {
StaticCall() { not this.isVirtual() }
}
class StaticCall extends Call { StaticCall() { not this.isVirtual() } }
/** A call to a virtual target. */
class VirtualCall extends Call {
VirtualCall() { this.isVirtual() }
}
class VirtualCall extends Call { VirtualCall() { this.isVirtual() } }
/** A read of an array element. */
class ReadArrayElement extends BinaryExpr, @cil_read_array {
/** Gets the array being read. */
Expr getArray() { result=getOperand(1) }
Expr getArray() { result = getOperand(1) }
/** Gets the index into the array. */
Expr getArrayIndex() { result = getOperand(0) }
@@ -208,34 +216,36 @@ class ReadArrayElement extends BinaryExpr, @cil_read_array {
/** A write of an array element. */
class WriteArrayElement extends Instruction, @cil_write_array {
override int getPushCount() { result=0 }
override int getPopCount() { result=3 }
override int getPushCount() { result = 0 }
override int getPopCount() { result = 3 }
}
/** A `return` statement. */
class Return extends Instruction, @cil_ret {
/** Gets the expression being returned, if any. */
Expr getExpr() { result=getOperand(0) }
Expr getExpr() { result = getOperand(0) }
override predicate canFlowNext() { none() }
}
/** A `throw` statement. */
class Throw extends Instruction, DotNet::Throw, @cil_throw_any {
override Expr getExpr() { result=getOperand(0) }
override Expr getExpr() { result = getOperand(0) }
override predicate canFlowNext() { none() }
}
/** Stores a value at an address/location. */
class StoreIndirect extends Instruction, @cil_stind {
override int getPopCount() { result=2 }
override int getPopCount() { result = 2 }
/** Gets the location to store the value at. */
Expr getAddress() { result=getOperand(1) }
Expr getAddress() { result = getOperand(1) }
/** Gets the value to store. */
Expr getExpr() { result=getOperand(0) }
Expr getExpr() { result = getOperand(0) }
}
/** Loads a value from an address/location. */
class LoadIndirect extends UnaryExpr, @cil_ldind {
}
class LoadIndirect extends UnaryExpr, @cil_ldind { }

File diff suppressed because it is too large Load Diff

View File

@@ -13,53 +13,45 @@ private import dotnet
* An implementation of a method in an assembly.
*/
class MethodImplementation extends EntryPoint, @cil_method_implementation {
/** Gets the method of this implementation. */
Method getMethod() { cil_method_implementation(this,result,_) }
Method getMethod() { cil_method_implementation(this, result, _) }
override MethodImplementation getImplementation() { result=this }
override MethodImplementation getImplementation() { result = this }
/** Gets the location of this implementation. */
Assembly getLocation() { cil_method_implementation(this,_,result) }
Assembly getLocation() { cil_method_implementation(this, _, result) }
/** Gets the instruction at index `index`. */
Instruction getInstruction(int index) {
cil_instruction(result,_,index,this)
}
Instruction getInstruction(int index) { cil_instruction(result, _, index, this) }
/** Gets the `n`th local variable of this implementation. */
LocalVariable getLocalVariable(int n) { cil_local_variable(result, this, n, _) }
/** Gets a local variable of this implementation, if any. */
LocalVariable getALocalVariable() { result=getLocalVariable(_) }
LocalVariable getALocalVariable() { result = getLocalVariable(_) }
/** Gets an instruction in this implementation, if any. */
Instruction getAnInstruction() {
result = getInstruction(_)
}
Instruction getAnInstruction() { result = getInstruction(_) }
/** Gets the total number of instructions in this implementation. */
int getNumberOfInstructions() {
result = count(getAnInstruction())
}
int getNumberOfInstructions() { result = count(getAnInstruction()) }
/** Gets the `i`th handler in this implementation. */
Handler getHandler(int i) {
result.getImplementation()=this and result.getIndex()=i
}
Handler getHandler(int i) { result.getImplementation() = this and result.getIndex() = i }
/** Gets a handler in this implementation, if any. */
Handler getAHandler() { result.getImplementation()=this }
Handler getAHandler() { result.getImplementation() = this }
override Instruction getASuccessorType(FlowType t) { t instanceof NormalFlow and result.getImplementation()=this and result.getIndex()=0 }
override Instruction getASuccessorType(FlowType t) {
t instanceof NormalFlow and result.getImplementation() = this and result.getIndex() = 0
}
/** Gets the maximum stack size of this implementation. */
int getStackSize() { cil_method_stack_size(this, result) }
override string toString() { result=getMethod().toString() }
override string toString() { result = getMethod().toString() }
}
/**
* A method, which corresponds to any callable in C#, including constructors,
* destructors, operators, accessors and so on.
@@ -69,7 +61,7 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
* Gets a method implementation, if any. Note that there can
* be several implementations in different assemblies.
*/
MethodImplementation getAnImplementation() { result.getMethod()=this }
MethodImplementation getAnImplementation() { result.getMethod() = this }
override Method getMethod() { result = this }
@@ -92,12 +84,10 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
override Parameter getRawParameter(int n) { cil_parameter(result, this, n, _) }
override Parameter getParameter(int n) {
if isStatic()
then result=getRawParameter(n)
else (result=getRawParameter(n+1) and n>=0)
}
if isStatic() then result = getRawParameter(n) else (result = getRawParameter(n + 1) and n >= 0)
}
override Type getType() { result=getReturnType() }
override Type getType() { result = getReturnType() }
/** Gets the return type of this method. */
override Type getReturnType() { cil_method(this, _, _, result) }
@@ -106,15 +96,13 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
predicate returnsVoid() { getReturnType() instanceof VoidType }
/** Gets the number of stack items pushed in a call to this method. */
int getCallPushCount() { if returnsVoid() then result=0 else result=1 }
int getCallPushCount() { if returnsVoid() then result = 0 else result = 1 }
/** Gets the number of stack items popped in a call to this method. */
int getCallPopCount() { result=count(getRawParameter(_)) }
int getCallPopCount() { result = count(getRawParameter(_)) }
/** Gets a method called by this method. */
Method getACallee() {
result = getAnImplementation().getAnInstruction().(Call).getTarget()
}
Method getACallee() { result = getAnImplementation().getAnInstruction().(Call).getTarget() }
/** Holds if this method is `virtual`. */
predicate isVirtual() { cil_virtual(this) }
@@ -136,16 +124,16 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
override Method getSourceDeclaration() { result = getUnboundMethod() }
/** Holds if this method is an instance constructor. */
predicate isInstanceConstructor() { isSpecial() and getName()=".ctor" }
predicate isInstanceConstructor() { isSpecial() and getName() = ".ctor" }
/** Holds if this method is a static class constructor. */
predicate isStaticConstructor() { isSpecial() and getName()=".cctor" }
predicate isStaticConstructor() { isSpecial() and getName() = ".cctor" }
/** Holds if this method is a constructor (static or instance). */
predicate isConstructor() { isStaticConstructor() or isInstanceConstructor() }
/** Holds if this method is a destructor/finalizer. */
predicate isFinalizer() { getOverriddenMethod*().getQualifiedName()="System.Object.Finalize" }
predicate isFinalizer() { getOverriddenMethod*().getQualifiedName() = "System.Object.Finalize" }
/** Holds if this method is an operator. */
predicate isOperator() { isSpecial() and getName().matches("op\\_%") }
@@ -163,10 +151,10 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
predicate isRemove() { isSpecial() and getName().matches("remove\\_%") }
/** Holds if this method is an implicit conversion operator. */
predicate isImplicitConversion() { isSpecial() and getName()="op_Implicit" }
predicate isImplicitConversion() { isSpecial() and getName() = "op_Implicit" }
/** Holds if this method is an explicit conversion operator. */
predicate isExplicitConversion() { isSpecial() and getName()="op_Explicit" }
predicate isExplicitConversion() { isSpecial() and getName() = "op_Explicit" }
/** Holds if this method is a conversion operator. */
predicate isConversion() { isImplicitConversion() or isExplicitConversion() }
@@ -175,14 +163,10 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
* Gets a method that is overridden, either in a base class
* or in an interface.
*/
Method getOverriddenMethod() {
cil_implements(this, result)
}
Method getOverriddenMethod() { cil_implements(this, result) }
/** Gets a method that overrides this method, if any. */
final Method getAnOverrider() {
result.getOverriddenMethod() = this
}
final Method getAnOverrider() { result.getOverriddenMethod() = this }
override predicate hasBody() { exists(getAnImplementation()) }
@@ -192,19 +176,13 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
}
/** A destructor/finalizer. */
class Destructor extends Method, DotNet::Destructor {
Destructor() { this.isFinalizer() }
}
class Destructor extends Method, DotNet::Destructor { Destructor() { this.isFinalizer() } }
/** A constructor. */
class Constructor extends Method, DotNet::Constructor {
Constructor() { this.isConstructor() }
}
class Constructor extends Method, DotNet::Constructor { Constructor() { this.isConstructor() } }
/** A static/class constructor. */
class StaticConstructor extends Constructor {
StaticConstructor() { this.isStaticConstructor() }
}
class StaticConstructor extends Constructor { StaticConstructor() { this.isStaticConstructor() } }
/** An instance constructor. */
class InstanceConstructor extends Constructor {
@@ -214,8 +192,7 @@ class InstanceConstructor extends Constructor {
/** A method that always returns the `this` parameter. */
class ChainingMethod extends Method {
ChainingMethod() {
forex(Return ret |
ret = getAnImplementation().getAnInstruction() |
forex(Return ret | ret = getAnImplementation().getAnInstruction() |
ret.getExpr() instanceof ThisAccess
)
}
@@ -229,8 +206,9 @@ abstract class Accessor extends Method {
/** A getter. */
class Getter extends Accessor {
Getter() { cil_getter(_,this) }
override Property getProperty() { cil_getter(result,this) }
Getter() { cil_getter(_, this) }
override Property getProperty() { cil_getter(result, this) }
}
/**
@@ -240,22 +218,23 @@ class Getter extends Accessor {
class TrivialGetter extends Method {
TrivialGetter() {
exists(MethodImplementation impl | impl = getAnImplementation() |
impl.getInstruction(0) instanceof ThisAccess
and impl.getInstruction(1) instanceof FieldReadAccess
and impl.getInstruction(2) instanceof Return
impl.getInstruction(0) instanceof ThisAccess and
impl.getInstruction(1) instanceof FieldReadAccess and
impl.getInstruction(2) instanceof Return
)
}
/** Gets the underlying field of this getter. */
Field getField() {
getAnImplementation().getAnInstruction().(FieldReadAccess).getTarget()=result
getAnImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result
}
}
/** A setter. */
class Setter extends Accessor {
Setter() { cil_setter(_,this) }
override Property getProperty() { cil_setter(result,this) }
Setter() { cil_setter(_, this) }
override Property getProperty() { cil_setter(result, this) }
}
/**
@@ -265,9 +244,9 @@ class Setter extends Accessor {
class TrivialSetter extends Method {
TrivialSetter() {
exists(MethodImplementation impl | impl = getAnImplementation() |
impl.getInstruction(0) instanceof ThisAccess
and impl.getInstruction(1).(ParameterReadAccess).getTarget().getIndex() = 1
and impl.getInstruction(2) instanceof FieldWriteAccess
impl.getInstruction(0) instanceof ThisAccess and
impl.getInstruction(1).(ParameterReadAccess).getTarget().getIndex() = 1 and
impl.getInstruction(2) instanceof FieldWriteAccess
)
}
@@ -285,5 +264,5 @@ class Operator extends Method {
Operator() { this.isOperator() }
/** Gets the name of the implementing method (for compatibility with C# data model). */
string getFunctionName() { result=getName() }
string getFunctionName() { result = getName() }
}

View File

@@ -19,10 +19,14 @@ class TypeContainer extends DotNet::NamedElement, @cil_type_container {
/** A namespace. */
class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
override string toString() { result=getQualifiedName() }
override string toString() { result = getQualifiedName() }
override Namespace getParent() { result = this.getParentNamespace() }
override Namespace getParentNamespace() { parent_namespace(this, result) }
override string getName() { namespaces(this,result) }
override string getName() { namespaces(this, result) }
override Location getLocation() { none() }
}
@@ -31,14 +35,16 @@ class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
*/
class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type {
override TypeContainer getParent() { cil_type(this, _, _, result, _) }
override string getName() { cil_type(this, result, _, _, _) }
override string toString() { result = getQualifiedName() }
/** Gets the containing type of this type, if any. */
override Type getDeclaringType() { result = getParent() }
/** Gets a member of this type, if any. */
Member getAMember() { result.getDeclaringType()=this }
Member getAMember() { result.getDeclaringType() = this }
/**
* Gets the unbound generic type of this type, or `this` if the type
@@ -69,8 +75,7 @@ class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type {
* faster to compute.
*/
predicate isSystemType(string name) {
exists(Namespace system |
this.getParent() = system |
exists(Namespace system | this.getParent() = system |
system.getName() = "System" and
system.getParentNamespace() instanceof DotNet::GlobalNamespace and
name = this.getName()
@@ -87,10 +92,9 @@ class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type {
predicate isPrivate() { cil_private(this) }
/** Gets the machine type used to store this type. */
Type getUnderlyingType() { result=this }
Type getUnderlyingType() { result = this }
// Class hierarchy
/** Gets the immediate base class of this class, if any. */
Type getBaseClass() { cil_base_class(this, result) }
@@ -101,14 +105,14 @@ class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type {
Type getABaseType() { result = getBaseClass() or result = getABaseInterface() }
/** Gets an immediate subtype of this type, if any. */
Type getASubtype() { result.getABaseType()=this }
Type getASubtype() { result.getABaseType() = this }
/** Gets the namespace directly containing this type, if any. */
Namespace getNamespace() { result=getParent() }
Namespace getNamespace() { result = getParent() }
/**
* Gets an index for implicit conversions. A type can be converted to another numeric type
* of a higher index.
*/
int getConversionIndex() { result=0 }
int getConversionIndex() { result = 0 }
}

View File

@@ -11,7 +11,8 @@ class TypeParameter extends DotNet::TypeParameter, Type, @cil_typeparameter {
/** Gets the generic type/method declaring this type parameter. */
TypeContainer getGeneric() { cil_type_parameter(result, _, this) }
override Location getLocation() { result=getParent().getLocation() }
override Location getLocation() { result = getParent().getLocation() }
/** Holds if this type parameter has the `new` constraint. */
predicate isDefaultConstructible() { cil_typeparam_new(this) }
@@ -28,14 +29,17 @@ class TypeParameter extends DotNet::TypeParameter, Type, @cil_typeparameter {
predicate isContravariant() { cil_typeparam_contravariant(this) }
/** Gets a type constraint on this type parameter, if any. */
Type getATypeConstraint() { cil_typeparam_constraint(this,result) }
Type getATypeConstraint() { cil_typeparam_constraint(this, result) }
}
/** A value or reference type. */
class ValueOrRefType extends DotNet::ValueOrRefType, Type, @cil_valueorreftype {
override ValueOrRefType getDeclaringType() { result = getParent() }
override string getUndecoratedName() { result = getName() }
override Namespace getDeclaringNamespace() { result = getNamespace() }
override ValueOrRefType getABaseType() { result = Type.super.getABaseType() }
}
@@ -48,31 +52,28 @@ class Enum extends ValueOrRefType {
}
/** A `class`. */
class Class extends ValueOrRefType {
Class() { this.isClass() }
}
class Class extends ValueOrRefType { Class() { this.isClass() } }
/** An `interface`. */
class Interface extends ValueOrRefType {
Interface() { this.isInterface() }
}
class Interface extends ValueOrRefType { Interface() { this.isInterface() } }
/** An array. */
class ArrayType extends DotNet::ArrayType, Type, @cil_array_type {
override Type getElementType() { cil_array_type(this,result,_) }
override Type getElementType() { cil_array_type(this, result, _) }
/** Gets the rank of this array. */
int getRank() { cil_array_type(this,_,result) }
int getRank() { cil_array_type(this, _, result) }
override string toStringWithTypes() { result = DotNet::ArrayType.super.toStringWithTypes() }
override Location getLocation() { result=getElementType().getLocation() }
override Location getLocation() { result = getElementType().getLocation() }
override ValueOrRefType getABaseType() { result = Type.super.getABaseType() }
}
/** A pointer type. */
class PointerType extends DotNet::PointerType, PrimitiveType, @cil_pointer_type {
override Type getReferentType() { cil_pointer_type(this,result) }
override Type getReferentType() { cil_pointer_type(this, result) }
override IntType getUnderlyingType() { any() }
@@ -86,164 +87,194 @@ class PointerType extends DotNet::PointerType, PrimitiveType, @cil_pointer_type
}
/** A primitive type, built into the runtime. */
abstract class PrimitiveType extends Type {
}
abstract class PrimitiveType extends Type { }
/**
* A primitive numeric type.
* Either an integral type (`IntegralType`) or a floating point type (`FloatingPointType`).
*/
abstract class NumericType extends PrimitiveType, ValueOrRefType {
}
abstract class NumericType extends PrimitiveType, ValueOrRefType { }
/** A floating point type. Either single precision (`FloatType`) or double precision (`DoubleType`). */
abstract class FloatingPointType extends NumericType {
}
abstract class FloatingPointType extends NumericType { }
/**
* An integral numeric type. Either a signed integral type (`SignedIntegralType`)
* or an unsigned integral type (`UnsignedIntegralType`).
*/
abstract class IntegralType extends NumericType {
}
abstract class IntegralType extends NumericType { }
/** A signed integral type. */
abstract class SignedIntegralType extends IntegralType {
}
abstract class SignedIntegralType extends IntegralType { }
/** An unsigned integral type. */
abstract class UnsignedIntegralType extends IntegralType {
}
abstract class UnsignedIntegralType extends IntegralType { }
/** The `void` type, `System.Void`. */
class VoidType extends PrimitiveType {
VoidType() { this.isSystemType("Void") }
override string toString() { result="void" }
override string toStringWithTypes() { result="void" }
override string toString() { result = "void" }
override string toStringWithTypes() { result = "void" }
}
/** The type `System.Int32`. */
class IntType extends SignedIntegralType {
IntType() { this.isSystemType("Int32") }
override string toStringWithTypes() { result="int" }
override string toStringWithTypes() { result = "int" }
override int getConversionIndex() { result = 8 }
override IntType getUnderlyingType() { result=this }
override IntType getUnderlyingType() { result = this }
}
/** The type `System.IntPtr`. */
class IntPtrType extends PrimitiveType {
IntPtrType() { this.isSystemType("IntPtr") }
override IntType getUnderlyingType() { any() }
}
/** The type `System.UIntPtr`. */
class UIntPtrType extends PrimitiveType {
UIntPtrType() { this.isSystemType("UIntPtr") }
override IntType getUnderlyingType() { any() }
}
/** The type `System.UInt32`. */
class UIntType extends UnsignedIntegralType {
UIntType() { this.isSystemType("UInt32") }
override string toStringWithTypes() { result="uint" }
override int getConversionIndex() { result=7 }
override string toStringWithTypes() { result = "uint" }
override int getConversionIndex() { result = 7 }
override IntType getUnderlyingType() { any() }
}
/** The type `System.SByte`. */
class SByteType extends SignedIntegralType {
SByteType() { this.isSystemType("SByte") }
override string toStringWithTypes() { result="sbyte" }
override int getConversionIndex() { result=2 }
override string toStringWithTypes() { result = "sbyte" }
override int getConversionIndex() { result = 2 }
}
/** The type `System.Byte`. */
class ByteType extends UnsignedIntegralType {
ByteType() { this.isSystemType("Byte") }
override string toStringWithTypes() { result="byte" }
override int getConversionIndex() { result=1 }
override string toStringWithTypes() { result = "byte" }
override int getConversionIndex() { result = 1 }
override SByteType getUnderlyingType() { any() }
}
/** The type `System.Int16`. */
class ShortType extends SignedIntegralType {
ShortType() { this.isSystemType("Int16") }
override string toStringWithTypes() { result="short" }
override int getConversionIndex() { result=4 }
override string toStringWithTypes() { result = "short" }
override int getConversionIndex() { result = 4 }
}
/** The type `System.UInt16`. */
class UShortType extends UnsignedIntegralType {
UShortType() { this.isSystemType("UInt16") }
override string toStringWithTypes() { result="ushort" }
override int getConversionIndex() { result=3 }
override string toStringWithTypes() { result = "ushort" }
override int getConversionIndex() { result = 3 }
override ShortType getUnderlyingType() { any() }
}
/** The type `System.Int64`. */
class LongType extends SignedIntegralType {
LongType() { this.isSystemType("Int64") }
override string toStringWithTypes() { result="long" }
override int getConversionIndex() { result=10 }
override string toStringWithTypes() { result = "long" }
override int getConversionIndex() { result = 10 }
}
/** The type `System.UInt64`. */
class ULongType extends UnsignedIntegralType {
ULongType() { this.isSystemType("UInt64") }
override string toStringWithTypes() { result="ulong" }
override int getConversionIndex() { result=9 }
override string toStringWithTypes() { result = "ulong" }
override int getConversionIndex() { result = 9 }
override LongType getUnderlyingType() { any() }
}
/** The type `System.Decimal`. */
class DecimalType extends SignedIntegralType {
DecimalType() { this.isSystemType("Decimal") }
override string toStringWithTypes() { result="decimal" }
override int getConversionIndex() { result=13 }
override string toStringWithTypes() { result = "decimal" }
override int getConversionIndex() { result = 13 }
}
/** The type `System.String`. */
class StringType extends PrimitiveType, ValueOrRefType {
StringType() { this.isSystemType("String") }
override string toStringWithTypes() { result="string" }
override string toStringWithTypes() { result = "string" }
}
/** The type `System.Object`. */
class ObjectType extends ValueOrRefType {
ObjectType() { this.isSystemType("Object") }
override string toStringWithTypes() { result="object" }
override string toStringWithTypes() { result = "object" }
}
/** The type `System.Boolean`. */
class BoolType extends PrimitiveType, ValueOrRefType {
BoolType() { this.isSystemType("Boolean") }
override string toStringWithTypes() { result="bool" }
override string toStringWithTypes() { result = "bool" }
override IntType getUnderlyingType() { any() }
}
/** The type `System.Double`. */
class DoubleType extends FloatingPointType {
DoubleType() { this.isSystemType("Double") }
override string toStringWithTypes() { result="double" }
override int getConversionIndex() { result=12 }
override string toStringWithTypes() { result = "double" }
override int getConversionIndex() { result = 12 }
}
/** The type `System.Single`. */
class FloatType extends FloatingPointType {
FloatType() { this.isSystemType("Single") }
override string toStringWithTypes() { result="float" }
override int getConversionIndex() { result=4 }
override string toStringWithTypes() { result = "float" }
override int getConversionIndex() { result = 4 }
}
/** The type `System.Char`. */
class CharType extends IntegralType {
CharType() { this.isSystemType("Char") }
override string toStringWithTypes() { result="char" }
override int getConversionIndex() { result=6 }
override string toStringWithTypes() { result = "char" }
override int getConversionIndex() { result = 6 }
override IntType getUnderlyingType() { any() }
}
/** The type `System.Type`. */
class SystemType extends ValueOrRefType {
SystemType() { this.isSystemType("Type") }
}
class SystemType extends ValueOrRefType { SystemType() { this.isSystemType("Type") } }

View File

@@ -14,13 +14,13 @@ class Variable extends DotNet::Variable, Declaration, DataFlowNode, @cil_variabl
override string toStringWithTypes() { none() }
/** Gets an access to this variable, if any. */
VariableAccess getAnAccess() { result.getTarget()=this }
VariableAccess getAnAccess() { result.getTarget() = this }
/** Gets a read access to this variable, if any. */
ReadAccess getARead() { result=getAnAccess() }
ReadAccess getARead() { result = getAnAccess() }
/** Gets a write access to this variable, if any. */
WriteAccess getAWrite() { result=getAnAccess() }
WriteAccess getAWrite() { result = getAnAccess() }
override string toString() { result = Declaration.super.toString() }
@@ -28,8 +28,7 @@ class Variable extends DotNet::Variable, Declaration, DataFlowNode, @cil_variabl
}
/** A stack variable. Either a local variable (`LocalVariable`) or a parameter (`Parameter`). */
class StackVariable extends Variable, @cil_stack_variable {
}
class StackVariable extends Variable, @cil_stack_variable { }
/**
* A local variable.
@@ -37,33 +36,35 @@ class StackVariable extends Variable, @cil_stack_variable {
* Each method in CIL has a number of typed local variables, in addition to the evaluation stack.
*/
class LocalVariable extends StackVariable, @cil_local_variable {
override string toString() { result="Local variable " + getIndex() + " of method " + getImplementation().getMethod() }
override string toString() {
result = "Local variable " + getIndex() + " of method " + getImplementation().getMethod()
}
/** Gets the method implementation defining this local variable. */
MethodImplementation getImplementation() { this=result.getALocalVariable() }
MethodImplementation getImplementation() { this = result.getALocalVariable() }
/** Gets the index number of this local variable. This is not usually significant. */
int getIndex() { this = getImplementation().getLocalVariable(result) }
override Type getType() { cil_local_variable(this, _, _, result) }
override Location getLocation() { result=getImplementation().getLocation() }
override Location getLocation() { result = getImplementation().getLocation() }
override Method getMethod() { result=getImplementation().getMethod() }
override Method getMethod() { result = getImplementation().getMethod() }
}
/** A method parameter. */
class Parameter extends DotNet::Parameter, StackVariable, @cil_parameter {
/** Gets the method declaring this parameter. */
override Method getMethod() { this=result.getARawParameter() }
override Method getMethod() { this = result.getARawParameter() }
override Method getCallable() { result=getMethod() }
override Method getCallable() { result = getMethod() }
/** Gets the index of this parameter. */
int getIndex() { cil_parameter(this, _, result, _) }
override string toString() { result="Parameter " + getIndex() + " of " + getMethod() }
override string toString() { result = "Parameter " + getIndex() + " of " + getMethod() }
override Type getType() { cil_parameter(this, _, _, result) }
/**
@@ -86,9 +87,11 @@ class Parameter extends DotNet::Parameter, StackVariable, @cil_parameter {
override string toStringWithTypes() { result = getPrefix() + getType().toStringWithTypes() }
private string getPrefix() { if isOut() then result="out " else if isRef() then result="ref " else result="" }
private string getPrefix() {
if isOut() then result = "out " else if isRef() then result = "ref " else result = ""
}
override Location getLocation() { result=getMethod().getLocation() }
override Location getLocation() { result = getMethod().getLocation() }
override ParameterAccess getAnAccess() { result.getTarget() = this }
@@ -105,17 +108,24 @@ class Parameter extends DotNet::Parameter, StackVariable, @cil_parameter {
/** A parameter corresponding to `this`. */
class ThisParameter extends Parameter {
ThisParameter() {
not this.getMethod().isStatic()
and this.getIndex()=0
not this.getMethod().isStatic() and
this.getIndex() = 0
}
}
/** A field. */
class Field extends DotNet::Field, Variable, Member, @cil_field {
override string toString() { result=getName() }
override string toStringWithTypes() { result=getDeclaringType().toStringWithTypes() + "." + getName() }
override string getName() { cil_field(this,_,result,_) }
override string toString() { result = getName() }
override string toStringWithTypes() {
result = getDeclaringType().toStringWithTypes() + "." + getName()
}
override string getName() { cil_field(this, _, result, _) }
override Type getType() { cil_field(this, _, _, result) }
override ValueOrRefType getDeclaringType() { cil_field(this, result, _, _) }
override Location getLocation() { result=getDeclaringType().getLocation() }
override Location getLocation() { result = getDeclaringType().getLocation() }
}

View File

@@ -27,9 +27,7 @@ class Assignable extends Declaration, @assignable {
* property (`Property`), an indexer (`Indexer`), or an event (`Event`).
*/
class AssignableMember extends Member, Assignable {
override AssignableMemberAccess getAnAccess() {
result = Assignable.super.getAnAccess()
}
override AssignableMemberAccess getAnAccess() { result = Assignable.super.getAnAccess() }
}
/**
@@ -38,9 +36,7 @@ class AssignableMember extends Member, Assignable {
* (`IndexerAccess`), or an event access (`EventAccess`).
*/
class AssignableMemberAccess extends MemberAccess, AssignableAccess {
override AssignableMember getTarget() {
result = AssignableAccess.super.getTarget()
}
override AssignableMember getTarget() { result = AssignableAccess.super.getTarget() }
}
/**
@@ -70,8 +66,7 @@ class AssignableRead extends AssignableAccess {
this.isRefArgument()
or
this = any(AssignableDefinitions::AddressOfDefinition def).getTargetAccess()
)
and
) and
not this = any(NameOfExpr noe).getAChildExpr*()
}
@@ -100,8 +95,7 @@ class AssignableRead extends AssignableAccess {
* - The read of `this.Field` on line 11 is next to the read on line 10.
*/
AssignableRead getANextRead() {
forex(ControlFlow::Node cfn |
cfn = result.getAControlFlowNode() |
forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() |
Ssa::Internal::adjacentReadPairSameVar(this.getAControlFlowNode(), cfn)
)
}
@@ -113,9 +107,7 @@ class AssignableRead extends AssignableAccess {
*
* This is the transitive closure of `getANextRead()`.
*/
AssignableRead getAReachableRead() {
result = this.getANextRead+()
}
AssignableRead getAReachableRead() { result = this.getANextRead+() }
}
/**
@@ -136,11 +128,7 @@ class AssignableRead extends AssignableAccess {
* ```
*/
class AssignableWrite extends AssignableAccess {
AssignableWrite() {
exists(AssignableDefinition def |
def.getTargetAccess() = this
)
}
AssignableWrite() { exists(AssignableDefinition def | def.getTargetAccess() = this) }
}
/** INTERNAL: Do not use. */
@@ -164,8 +152,7 @@ module AssignableInternal {
left = ae.getLValue() and
right = ae.getRValue()
or
exists(TupleExpr l, TupleExpr r, int i |
tupleAssignmentPair(ae, l, r) |
exists(TupleExpr l, TupleExpr r, int i | tupleAssignmentPair(ae, l, r) |
left = l.getArgument(i) and
right = r.getArgument(i)
)
@@ -196,12 +183,10 @@ module AssignableInternal {
* recursion error).
*/
private Expr getArgumentForParameter(Call c, Parameter p) {
exists(Callable callable |
p = callable.getAParameter() |
exists(Callable callable | p = callable.getAParameter() |
callable = c.(MethodCall).getTarget() or
callable = c.(ObjectCreation).getTarget()
)
and
) and
(
// Appears in the positional part of the call
result = c.getArgument(p.getPosition()) and
@@ -212,7 +197,8 @@ module AssignableInternal {
)
}
pragma [noinline] // predicate folding to get proper join-order
// predicate folding to get proper join-order
pragma[noinline]
private Expr getExplicitArgument(Call c, string name) {
result = c.getAnArgument() and
result.getExplicitArgumentName() = name
@@ -223,8 +209,7 @@ module AssignableInternal {
* the target callable is non-overridable and from source.
*/
private predicate isAnalyzableRefCall(Call c, AssignableAccess aa, Parameter p) {
exists(Callable callable |
callable = getRefCallTarget(c, aa, p) |
exists(Callable callable | callable = getRefCallTarget(c, aa, p) |
not callable.(Virtualizable).isOverridableOrImplementable() and
callable.hasBody()
)
@@ -236,8 +221,7 @@ module AssignableInternal {
* recursion.
*/
private predicate isNonAnalyzableRefCall(Call c, AssignableAccess aa, Parameter p) {
exists(Callable callable |
callable = getRefCallTarget(c, aa, p) |
exists(Callable callable | callable = getRefCallTarget(c, aa, p) |
callable.(Virtualizable).isOverridableOrImplementable() or
not callable.hasBody()
)
@@ -259,14 +243,12 @@ module AssignableInternal {
* any assignments to `p`.
*/
private predicate parameterReachesWithoutDef(Parameter p, ControlFlow::BasicBlock bb) {
not basicBlockRefParamDef(bb, p)
and
not basicBlockRefParamDef(bb, p) and
(
isAnalyzableRefCall(_, _, p) and
p.getCallable().getEntryPoint() = bb.getFirstNode()
or
exists(ControlFlow::BasicBlock mid |
parameterReachesWithoutDef(p, mid) |
exists(ControlFlow::BasicBlock mid | parameterReachesWithoutDef(p, mid) |
bb = mid.getASuccessor()
)
)
@@ -277,45 +259,33 @@ module AssignableInternal {
bb.getANode() = getAnAnalyzableRefDef(_, _, p).getAControlFlowNode()
}
private cached module Cached {
cached newtype TAssignableDefinition =
TAssignmentDefinition(Assignment a) {
not a.getLValue() instanceof TupleExpr
}
or
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) {
tupleAssignmentDefinition(ae, leaf)
}
or
cached
private module Cached {
cached
newtype TAssignableDefinition =
TAssignmentDefinition(Assignment a) { not a.getLValue() instanceof TupleExpr } or
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) { tupleAssignmentDefinition(ae, leaf) } or
TOutRefDefinition(AssignableAccess aa) {
aa.isOutArgument()
or
isRelevantRefCall(_, aa)
}
or
TMutationDefinition(MutatorOperation mo)
or
} or
TMutationDefinition(MutatorOperation mo) or
TLocalVariableDefinition(LocalVariableDeclExpr lvde) {
not lvde.hasInitializer() and
not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and
not lvde = any(IsPatternExpr ipe).getVariableDeclExpr() and
not lvde = any(TypeCase tc).getVariableDeclExpr()
}
or
} or
TImplicitParameterDefinition(Parameter p) {
exists(Callable c |
p = c.getAParameter() |
exists(Callable c | p = c.getAParameter() |
c.hasBody() or
c.(Constructor).hasInitializer()
)
}
or
TAddressOfDefinition(AddressOfExpr aoe)
or
TIsPatternDefinition(IsPatternExpr ipe)
or
TTypeCasePatternDefinition(TypeCase tc)
or
} or
TAddressOfDefinition(AddressOfExpr aoe) or
TIsPatternDefinition(IsPatternExpr ipe) or
TTypeCasePatternDefinition(TypeCase tc) or
TInitializer(Assignable a, Expr e) {
e = a.(Field).getInitializer() or
e = a.(Property).getInitializer()
@@ -324,9 +294,9 @@ module AssignableInternal {
/**
* Gets the source expression assigned in tuple definition `def`, if any.
*/
cached Expr getTupleSource(TTupleAssignmentDefinition def) {
exists(AssignExpr ae, Expr leaf |
def = TTupleAssignmentDefinition(ae, leaf) |
cached
Expr getTupleSource(TTupleAssignmentDefinition def) {
exists(AssignExpr ae, Expr leaf | def = TTupleAssignmentDefinition(ae, leaf) |
tupleAssignmentPair(ae, leaf, result)
)
}
@@ -334,48 +304,44 @@ module AssignableInternal {
/**
* Holds if the `ref` assignment to `aa` via call `c` is uncertain.
*/
cached predicate isUncertainRefCall(Call c, AssignableAccess aa) {
isRelevantRefCall(c, aa)
and
exists(ControlFlow::BasicBlock bb, Parameter p |
isAnalyzableRefCall(c, aa, p) |
cached
predicate isUncertainRefCall(Call c, AssignableAccess aa) {
isRelevantRefCall(c, aa) and
exists(ControlFlow::BasicBlock bb, Parameter p | isAnalyzableRefCall(c, aa, p) |
parameterReachesWithoutDef(p, bb) and
bb.getLastNode() = p.getCallable().getExitPoint()
)
}
// Not defined by dispatch in order to avoid too conservative negative recursion error
cached Assignable getTarget(AssignableDefinition def) {
cached
Assignable getTarget(AssignableDefinition def) {
result = def.getTargetAccess().getTarget()
or
exists(Expr leaf |
def = TTupleAssignmentDefinition(_, leaf) |
exists(Expr leaf | def = TTupleAssignmentDefinition(_, leaf) |
result = leaf.(LocalVariableDeclExpr).getVariable()
)
or
def = any(AssignableDefinitions::ImplicitParameterDefinition p |
result = p.getParameter()
)
def = any(AssignableDefinitions::ImplicitParameterDefinition p | result = p.getParameter())
or
def = any(AssignableDefinitions::LocalVariableDefinition decl |
result = decl.getDeclaration().getVariable()
)
result = decl.getDeclaration().getVariable()
)
or
def = any(AssignableDefinitions::IsPatternDefinition is |
result = is.getDeclaration().getVariable()
)
result = is.getDeclaration().getVariable()
)
or
def = any(AssignableDefinitions::TypeCasePatternDefinition case |
result = case.getDeclaration().getVariable()
)
result = case.getDeclaration().getVariable()
)
or
def = any(AssignableDefinitions::InitializerDefinition init |
result = init.getAssignable()
)
def = any(AssignableDefinitions::InitializerDefinition init | result = init.getAssignable())
}
// Not defined by dispatch in order to avoid too conservative negative recursion error
cached AssignableAccess getTargetAccess(AssignableDefinition def) {
cached
AssignableAccess getTargetAccess(AssignableDefinition def) {
def = TAssignmentDefinition(any(Assignment a | a.getLValue() = result))
or
def = TTupleAssignmentDefinition(_, result)
@@ -391,14 +357,13 @@ module AssignableInternal {
* Gets the argument for the implicit `value` parameter in the accessor call
* `ac`, if any.
*/
cached Expr getAccessorCallValueArgument(AccessorCall ac) {
exists(AssignExpr ae |
tupleAssignmentDefinition(ae, ac) |
cached
Expr getAccessorCallValueArgument(AccessorCall ac) {
exists(AssignExpr ae | tupleAssignmentDefinition(ae, ac) |
tupleAssignmentPair(ae, ac, result)
)
or
exists(Assignment a |
ac = a.getLValue() |
exists(Assignment a | ac = a.getLValue() |
result = a.getRValue() and
not a.(AssignOperation).hasExpandedAssignment()
)
@@ -406,7 +371,6 @@ module AssignableInternal {
}
import Cached
}
private import AssignableInternal
/**
@@ -431,9 +395,7 @@ class AssignableDefinition extends TAssignableDefinition {
* the definitions of `x` and `y` in `M(out x, out y)` and `(x, y) = (0, 1)`
* relate to the same call to `M` and assignment node, respectively.
*/
ControlFlow::Node getAControlFlowNode() {
result = this.getExpr().getAControlFlowNode()
}
ControlFlow::Node getAControlFlowNode() { result = this.getExpr().getAControlFlowNode() }
/**
* Gets the underlying expression that updates the targeted assignable when
@@ -505,10 +467,8 @@ class AssignableDefinition extends TAssignableDefinition {
* `AssignableRead.getANextRead()`.
*/
AssignableRead getAFirstRead() {
forex(ControlFlow::Node cfn |
cfn = result.getAControlFlowNode() |
exists(Ssa::ExplicitDefinition def |
result = def.getAFirstReadAtNode(cfn) |
forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() |
exists(Ssa::ExplicitDefinition def | result = def.getAFirstReadAtNode(cfn) |
this = def.getADefinition()
)
)
@@ -521,17 +481,13 @@ class AssignableDefinition extends TAssignableDefinition {
*
* This is the equivalent with `getAFirstRead().getANextRead*()`.
*/
AssignableRead getAReachableRead() {
result = this.getAFirstRead().getANextRead*()
}
AssignableRead getAReachableRead() { result = this.getAFirstRead().getANextRead*() }
/** Gets a textual representation of this assignable definition. */
string toString() { none() }
/** Gets the location of this assignable definition. */
Location getLocation() {
result = this.getExpr().getLocation()
}
Location getLocation() { result = this.getExpr().getLocation() }
}
/** Provides different types of `AssignableDefinition`s. */
@@ -542,14 +498,10 @@ module AssignableDefinitions {
class AssignmentDefinition extends AssignableDefinition, TAssignmentDefinition {
Assignment a;
AssignmentDefinition() {
this = TAssignmentDefinition(a)
}
AssignmentDefinition() { this = TAssignmentDefinition(a) }
/** Gets the underlying assignment. */
Assignment getAssignment() {
result = a
}
Assignment getAssignment() { result = a }
override Expr getExpr() { result = a }
@@ -558,9 +510,7 @@ module AssignableDefinitions {
not a instanceof AssignOperation
}
override string toString() {
result = a.toString()
}
override string toString() { result = a.toString() }
}
/**
@@ -569,16 +519,13 @@ module AssignableDefinitions {
*/
class TupleAssignmentDefinition extends AssignableDefinition, TTupleAssignmentDefinition {
AssignExpr ae;
Expr leaf;
TupleAssignmentDefinition() {
this = TTupleAssignmentDefinition(ae, leaf)
}
TupleAssignmentDefinition() { this = TTupleAssignmentDefinition(ae, leaf) }
/** Gets the underlying assignment. */
AssignExpr getAssignment() {
result = ae
}
AssignExpr getAssignment() { result = ae }
/**
* Gets the evaluation order of this definition among the other definitions
@@ -587,9 +534,12 @@ module AssignableDefinitions {
*/
int getEvaluationOrder() {
leaf = rank[result + 1](Expr leaf0 |
exists(TTupleAssignmentDefinition(ae, leaf0)) |
leaf0 order by leaf0.getLocation().getStartLine(), leaf0.getLocation().getStartColumn()
)
exists(TTupleAssignmentDefinition(ae, leaf0))
|
leaf0
order by
leaf0.getLocation().getStartLine(), leaf0.getLocation().getStartColumn()
)
}
override Expr getExpr() { result = ae }
@@ -598,9 +548,7 @@ module AssignableDefinitions {
result = getTupleSource(this) // need not exist
}
override string toString() {
result = ae.toString()
}
override string toString() { result = ae.toString() }
}
/**
@@ -610,14 +558,10 @@ module AssignableDefinitions {
class OutRefDefinition extends AssignableDefinition, TOutRefDefinition {
AssignableAccess aa;
OutRefDefinition() {
this = TOutRefDefinition(aa)
}
OutRefDefinition() { this = TOutRefDefinition(aa) }
/** Gets the underlying call. */
Call getCall() {
result.getAnArgument() = aa
}
Call getCall() { result.getAnArgument() = aa }
/**
* Gets the index of this definition among the other definitions in the
@@ -625,14 +569,13 @@ module AssignableDefinitions {
* the definitions of `x` and `y` are 0 and 1, respectively.
*/
int getIndex() {
exists(ControlFlow::BasicBlock bb, int i |
bb.getNode(i).getElement() = aa |
exists(ControlFlow::BasicBlock bb, int i | bb.getNode(i).getElement() = aa |
i = rank[result + 1](int j, OutRefDefinition def |
bb.getNode(j).getElement() = def.getTargetAccess() and
this.getCall() = def.getCall()
bb.getNode(j).getElement() = def.getTargetAccess() and
this.getCall() = def.getCall()
|
j
)
j
)
)
}
@@ -642,13 +585,9 @@ module AssignableDefinitions {
not isUncertainRefCall(this.getCall(), this.getTargetAccess())
}
override string toString() {
result = aa.toString()
}
override string toString() { result = aa.toString() }
override Location getLocation() {
result = aa.getLocation()
}
override Location getLocation() { result = aa.getLocation() }
}
/**
@@ -657,20 +596,14 @@ module AssignableDefinitions {
class MutationDefinition extends AssignableDefinition, TMutationDefinition {
MutatorOperation mo;
MutationDefinition() {
this = TMutationDefinition(mo)
}
MutationDefinition() { this = TMutationDefinition(mo) }
/** Gets the underlying mutator operation. */
MutatorOperation getMutatorOperation() {
result = mo
}
MutatorOperation getMutatorOperation() { result = mo }
override Expr getExpr() { result = mo }
override string toString() {
result = mo.toString()
}
override string toString() { result = mo.toString() }
}
/**
@@ -679,20 +612,14 @@ module AssignableDefinitions {
class LocalVariableDefinition extends AssignableDefinition, TLocalVariableDefinition {
LocalVariableDeclExpr lvde;
LocalVariableDefinition() {
this = TLocalVariableDefinition(lvde)
}
LocalVariableDefinition() { this = TLocalVariableDefinition(lvde) }
/** Gets the underlying local variable declaration. */
LocalVariableDeclExpr getDeclaration() {
result = lvde
}
LocalVariableDeclExpr getDeclaration() { result = lvde }
override Expr getExpr() { result = lvde }
override string toString() {
result = lvde.toString()
}
override string toString() { result = lvde.toString() }
}
/**
@@ -702,32 +629,20 @@ module AssignableDefinitions {
class ImplicitParameterDefinition extends AssignableDefinition, TImplicitParameterDefinition {
Parameter p;
ImplicitParameterDefinition() {
this = TImplicitParameterDefinition(p)
}
ImplicitParameterDefinition() { this = TImplicitParameterDefinition(p) }
/** Gets the underlying parameter. */
Parameter getParameter() {
result = p
}
Parameter getParameter() { result = p }
override ControlFlow::Node getAControlFlowNode() {
result = p.getCallable().getEntryPoint()
}
override ControlFlow::Node getAControlFlowNode() { result = p.getCallable().getEntryPoint() }
override Parameter getElement() { result = p }
override Callable getEnclosingCallable() {
result = p.getCallable()
}
override Callable getEnclosingCallable() { result = p.getCallable() }
override string toString() {
result = p.toString()
}
override string toString() { result = p.toString() }
override Location getLocation() {
result = this.getTarget().getLocation()
}
override Location getLocation() { result = this.getTarget().getLocation() }
}
/**
@@ -736,20 +651,14 @@ module AssignableDefinitions {
class AddressOfDefinition extends AssignableDefinition, TAddressOfDefinition {
AddressOfExpr aoe;
AddressOfDefinition() {
this = TAddressOfDefinition(aoe)
}
AddressOfDefinition() { this = TAddressOfDefinition(aoe) }
/** Gets the underlying address-of expression. */
AddressOfExpr getAddressOf() {
result = aoe
}
AddressOfExpr getAddressOf() { result = aoe }
override Expr getExpr() { result = aoe }
override string toString() {
result = aoe.toString()
}
override string toString() { result = aoe.toString() }
}
/**
@@ -758,24 +667,16 @@ module AssignableDefinitions {
class IsPatternDefinition extends AssignableDefinition, TIsPatternDefinition {
IsPatternExpr ipe;
IsPatternDefinition() {
this = TIsPatternDefinition(ipe)
}
IsPatternDefinition() { this = TIsPatternDefinition(ipe) }
/** Gets the underlying local variable declaration. */
LocalVariableDeclExpr getDeclaration() {
result = ipe.getVariableDeclExpr()
}
LocalVariableDeclExpr getDeclaration() { result = ipe.getVariableDeclExpr() }
override Expr getExpr() { result = this.getDeclaration() }
override Expr getSource() {
result = ipe.getExpr()
}
override Expr getSource() { result = ipe.getExpr() }
override string toString() {
result = this.getDeclaration().toString()
}
override string toString() { result = this.getDeclaration().toString() }
}
/**
@@ -793,14 +694,10 @@ module AssignableDefinitions {
class TypeCasePatternDefinition extends AssignableDefinition, TTypeCasePatternDefinition {
TypeCase tc;
TypeCasePatternDefinition() {
this = TTypeCasePatternDefinition(tc)
}
TypeCasePatternDefinition() { this = TTypeCasePatternDefinition(tc) }
/** Gets the underlying local variable declaration. */
LocalVariableDeclExpr getDeclaration() {
result = tc.getVariableDeclExpr()
}
LocalVariableDeclExpr getDeclaration() { result = tc.getVariableDeclExpr() }
override Expr getExpr() { result = this.getDeclaration() }
@@ -808,9 +705,7 @@ module AssignableDefinitions {
result = any(SwitchStmt ss | ss.getATypeCase() = tc).getCondition()
}
override string toString() {
result = this.getDeclaration().toString()
}
override string toString() { result = this.getDeclaration().toString() }
}
/**
@@ -825,27 +720,18 @@ module AssignableDefinitions {
*/
class InitializerDefinition extends AssignableDefinition, TInitializer {
Assignable a;
Expr e;
InitializerDefinition() {
this = TInitializer(a, e)
}
InitializerDefinition() { this = TInitializer(a, e) }
/** Gets the assignable (field or property) being initialized. */
Assignable getAssignable() {
result = a
}
Assignable getAssignable() { result = a }
override Expr getSource() {
result = e
}
override Expr getSource() { result = e }
override string toString() {
result = e.toString()
}
override string toString() { result = e.toString() }
override Location getLocation() {
result = e.getLocation()
}
override Location getLocation() { result = e.getLocation() }
}
}

View File

@@ -11,8 +11,7 @@ private import semmle.code.csharp.ExprOrStmtParent
* a destructor (`Destructor`), a callable accessor (`CallableAccessor`), a value or reference type
* (`ValueOrRefType`), or a declaration with accessors (`DeclarationWithAccessors`).
*/
class Attributable extends @attributable
{
class Attributable extends @attributable {
/** Gets an attribute attached to this element, if any. */
final Attribute getAnAttribute() { result.getTarget() = this }
@@ -36,7 +35,6 @@ class Attributable extends @attributable
* ```
*/
class Attribute extends TopLevelExprParent, @attribute {
/** Gets the type of this attribute. */
Class getType() { attributes(this, getTypeRef(result), _) }
@@ -49,13 +47,8 @@ class Attribute extends TopLevelExprParent, @attribute {
override Location getALocation() { attribute_location(this, result) }
override string toString() {
exists(string type, string name |
type = getType().toString() |
if type.matches("%Attribute") then
name = type.prefix(type.length() - 9)
else
name = type
and
exists(string type, string name | type = getType().toString() |
(if type.matches("%Attribute") then name = type.prefix(type.length() - 9) else name = type) and
result = "[" + name + "(...)]"
)
}

View File

@@ -28,9 +28,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
/** Holds if this callable returns a `ref readonly`. */
predicate returnsRefReadonly() { ref_readonly_returns(this) }
override Callable getSourceDeclaration() {
result = Parameterizable.super.getSourceDeclaration()
}
override Callable getSourceDeclaration() { result = Parameterizable.super.getSourceDeclaration() }
/**
* Gets the body of this callable, if any.
@@ -88,9 +86,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
}
/** Gets the statement body of this callable, if any. */
final BlockStmt getStatementBody() {
result = this.getAChildStmt()
}
final BlockStmt getStatementBody() { result = this.getAChildStmt() }
/**
* Gets a statement body of this callable, if any.
@@ -120,17 +116,13 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
* to the same assembly, then both `{ return 0; }` and `{ return 1; }` are
* statement bodies of `N.C.M()`.
*/
final BlockStmt getAStatementBody() {
stmt_parent_top_level(result, _, this)
}
final BlockStmt getAStatementBody() { stmt_parent_top_level(result, _, this) }
/** Holds if this callable has a statement body. */
final predicate hasStatementBody() { exists(getStatementBody()) }
/** Gets the expression body of this callable (if any), specified by `=>`. */
final Expr getExpressionBody() {
result = this.getChildExpr(0)
}
final Expr getExpressionBody() { result = this.getChildExpr(0) }
/**
* Gets an expression body of this callable (if any), specified by `=>`.
@@ -159,22 +151,16 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
*
* to the same assembly, then both `0` and `1` are expression bodies of `N.C.M()`.
*/
final Expr getAnExpressionBody() {
expr_parent_top_level_adjusted(result, 0, this)
}
final Expr getAnExpressionBody() { expr_parent_top_level_adjusted(result, 0, this) }
/** Holds if this callable has an expression body. */
final predicate hasExpressionBody() { exists(getExpressionBody()) }
/** Gets the entry point in the control graph for this callable. */
ControlFlow::Nodes::EntryNode getEntryPoint() {
result.getCallable() = this
}
ControlFlow::Nodes::EntryNode getEntryPoint() { result.getCallable() = this }
/** Gets the exit point in the control graph for this callable. */
ControlFlow::Nodes::ExitNode getExitPoint() {
result.getCallable() = this
}
ControlFlow::Nodes::ExitNode getExitPoint() { result.getCallable() = this }
/**
* Gets the enclosing callable of this callable, if any.
@@ -214,40 +200,26 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
}
override predicate canReturn(DotNet::Expr e) {
exists(ReturnStmt ret |
ret.getEnclosingCallable() = this |
e = ret.getExpr()
)
exists(ReturnStmt ret | ret.getEnclosingCallable() = this | e = ret.getExpr())
or
e = getExpressionBody()
}
/** Holds if this callable can yield return the expression `e`. */
predicate canYieldReturn(Expr e) {
exists(YieldReturnStmt yield |
yield.getEnclosingCallable() = this |
e = yield.getExpr()
)
exists(YieldReturnStmt yield | yield.getEnclosingCallable() = this | e = yield.getExpr())
}
override string toStringWithTypes() {
result = getName() + "(" + parameterTypesToString() + ")"
}
override string toStringWithTypes() { result = getName() + "(" + parameterTypesToString() + ")" }
/** Gets a `Call` that has this callable as a target. */
Call getACall() { this = result.getTarget() }
override Parameter getParameter(int n) {
result = Parameterizable.super.getParameter(n)
}
override Parameter getParameter(int n) { result = Parameterizable.super.getParameter(n) }
override Parameter getAParameter() {
result = Parameterizable.super.getAParameter()
}
override Parameter getAParameter() { result = Parameterizable.super.getAParameter() }
override int getNumberOfParameters() {
result = Parameterizable.super.getNumberOfParameters()
}
override int getNumberOfParameters() { result = Parameterizable.super.getNumberOfParameters() }
}
/**
@@ -260,31 +232,22 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
* ```
*/
class Method extends Callable, Virtualizable, Attributable, @method {
/** Gets the name of this method. */
override string getName() { methods(this,result,_,_,_) }
override string getName() { methods(this, result, _, _, _) }
override ValueOrRefType getDeclaringType() { methods(this,_,result,_,_) }
override ValueOrRefType getDeclaringType() { methods(this, _, result, _, _) }
override Type getReturnType() { methods(this,_,_,getTypeRef(result),_) }
override Type getReturnType() { methods(this, _, _, getTypeRef(result), _) }
override Method getSourceDeclaration() { methods(this,_,_,_,result) }
override Method getSourceDeclaration() { methods(this, _, _, _, result) }
override Method getOverridee() {
result = Virtualizable.super.getOverridee()
}
override Method getOverridee() { result = Virtualizable.super.getOverridee() }
override Method getAnOverrider() {
result = Virtualizable.super.getAnOverrider()
}
override Method getAnOverrider() { result = Virtualizable.super.getAnOverrider() }
override Method getImplementee() {
result = Virtualizable.super.getImplementee()
}
override Method getImplementee() { result = Virtualizable.super.getImplementee() }
override Method getAnImplementor() {
result = Virtualizable.super.getAnImplementor()
}
override Method getAnImplementor() { result = Virtualizable.super.getAnImplementor() }
override Method getAnUltimateImplementee() {
result = Virtualizable.super.getAnUltimateImplementee()
@@ -297,14 +260,11 @@ class Method extends Callable, Virtualizable, Attributable, @method {
override Location getALocation() { method_location(this, result) }
/** Holds if this method is an extension method. */
predicate isExtensionMethod() {
getParameter(0).hasExtensionMethodModifier()
}
predicate isExtensionMethod() { getParameter(0).hasExtensionMethodModifier() }
/** Gets the type of the `params` parameter of this method, if any. */
Type getParamsType() {
exists(Parameter last |
last = getParameter(getNumberOfParameters() - 1) |
exists(Parameter last | last = getParameter(getNumberOfParameters() - 1) |
last.isParams() and
result = last.getType().(ArrayType).getElementType()
)
@@ -314,9 +274,7 @@ class Method extends Callable, Virtualizable, Attributable, @method {
predicate hasParams() { exists(getParamsType()) }
// Remove when `Callable.isOverridden()` is removed
override predicate isOverridden() {
Virtualizable.super.isOverridden()
}
override predicate isOverridden() { Virtualizable.super.isOverridden() }
override predicate fromSource() {
Callable.super.fromSource() and
@@ -328,9 +286,7 @@ class Method extends Callable, Virtualizable, Attributable, @method {
override Location getLocation() { result = Callable.super.getLocation() }
override Parameter getRawParameter(int i) {
if this.isStatic()
then result = this.getParameter(i)
else result = this.getParameter(i-1)
if this.isStatic() then result = this.getParameter(i) else result = this.getParameter(i - 1)
}
}
@@ -344,13 +300,9 @@ class Method extends Callable, Virtualizable, Attributable, @method {
* ```
*/
class ExtensionMethod extends Method {
ExtensionMethod() {
this.isExtensionMethod()
}
ExtensionMethod() { this.isExtensionMethod() }
override predicate isStatic() {
any()
}
override predicate isStatic() { any() }
/** Gets the type being extended by this method. */
Type getExtendedType() { result = getParameter(0).getType() }
@@ -366,8 +318,7 @@ class ExtensionMethod extends Method {
* ```
*/
class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @constructor {
override string getName() { constructors(this,result,_,_) }
override string getName() { constructors(this, result, _, _) }
override Type getReturnType() {
exists(this) and // needed to avoid compiler warning
@@ -393,9 +344,9 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @
/** Holds if this constructor has an initializer. */
predicate hasInitializer() { exists(getInitializer()) }
override ValueOrRefType getDeclaringType() { constructors(this,_,result,_) }
override ValueOrRefType getDeclaringType() { constructors(this, _, result, _) }
override Constructor getSourceDeclaration() { constructors(this,_,_,result) }
override Constructor getSourceDeclaration() { constructors(this, _, _, result) }
override Location getALocation() { constructor_location(this, result) }
@@ -406,9 +357,7 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @
override Location getLocation() { result = Callable.super.getLocation() }
override Parameter getRawParameter(int i) {
if this.isStatic()
then result = this.getParameter(i)
else result = this.getParameter(i-1)
if this.isStatic() then result = this.getParameter(i) else result = this.getParameter(i - 1)
}
override string getUndecoratedName() { result = ".ctor" }
@@ -425,7 +374,6 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @
* ```
*/
class StaticConstructor extends Constructor {
StaticConstructor() { this.isStatic() }
override string getUndecoratedName() { result = ".cctor" }
@@ -441,10 +389,7 @@ class StaticConstructor extends Constructor {
* }
* ```
*/
class InstanceConstructor extends Constructor {
InstanceConstructor() { not this.isStatic() }
}
class InstanceConstructor extends Constructor { InstanceConstructor() { not this.isStatic() } }
/**
* A destructor, for example `~C() { }` on line 2 in
@@ -456,8 +401,7 @@ class InstanceConstructor extends Constructor {
* ```
*/
class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @destructor {
override string getName() { destructors(this,result,_,_) }
override string getName() { destructors(this, result, _, _) }
override Type getReturnType() {
exists(this) and // needed to avoid compiler warning
@@ -466,9 +410,9 @@ class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @de
override string getUndecoratedName() { result = "Finalize" }
override ValueOrRefType getDeclaringType() { destructors(this,_,result,_) }
override ValueOrRefType getDeclaringType() { destructors(this, _, result, _) }
override Destructor getSourceDeclaration() { destructors(this,_,_,result) }
override Destructor getSourceDeclaration() { destructors(this, _, _, result) }
override Location getALocation() { destructor_location(this, result) }
@@ -484,19 +428,18 @@ class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @de
* (`BinaryOperator`), or a conversion operator (`ConversionOperator`).
*/
class Operator extends Callable, Member, Attributable, @operator {
/** Gets the assembly name of this operator. */
string getAssemblyName() { operators(this,result,_,_,_,_) }
string getAssemblyName() { operators(this, result, _, _, _, _) }
override string getName() { operators(this,_,result,_,_,_) }
override string getName() { operators(this, _, result, _, _, _) }
string getFunctionName() { none() }
override ValueOrRefType getDeclaringType() { operators(this,_,_,result,_,_) }
override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) }
override Type getReturnType() { operators(this,_,_,_,getTypeRef(result),_) }
override Type getReturnType() { operators(this, _, _, _, getTypeRef(result), _) }
override Operator getSourceDeclaration() { operators(this,_,_,_,_,result) }
override Operator getSourceDeclaration() { operators(this, _, _, _, _, result) }
override Location getALocation() { operator_location(this, result) }
@@ -507,7 +450,6 @@ class Operator extends Callable, Member, Attributable, @operator {
override Parameter getRawParameter(int i) { result = getParameter(i) }
}
/**
* A user-defined unary operator - an operator taking one operand.
*
@@ -518,7 +460,6 @@ class Operator extends Callable, Member, Attributable, @operator {
* (`DecrementOperator`).
*/
class UnaryOperator extends Operator {
UnaryOperator() {
this.getNumberOfParameters() = 1 and
not this instanceof ConversionOperator
@@ -535,7 +476,6 @@ class UnaryOperator extends Operator {
* ```
*/
class PlusOperator extends UnaryOperator {
PlusOperator() { this.getName() = "+" }
override string getFunctionName() { result = "op_UnaryPlus" }
@@ -551,7 +491,6 @@ class PlusOperator extends UnaryOperator {
* ```
*/
class MinusOperator extends UnaryOperator {
MinusOperator() { this.getName() = "-" }
override string getFunctionName() { result = "op_UnaryNegation" }
@@ -567,7 +506,6 @@ class MinusOperator extends UnaryOperator {
* ```
*/
class NotOperator extends UnaryOperator {
NotOperator() { this.getName() = "!" }
override string getFunctionName() { result = "op_LogicalNot" }
@@ -583,7 +521,6 @@ class NotOperator extends UnaryOperator {
* ```
*/
class ComplementOperator extends UnaryOperator {
ComplementOperator() { this.getName() = "~" }
override string getFunctionName() { result = "op_OnesComplement" }
@@ -599,7 +536,6 @@ class ComplementOperator extends UnaryOperator {
* ```
*/
class IncrementOperator extends UnaryOperator {
IncrementOperator() { this.getName() = "++" }
override string getFunctionName() { result = "op_Increment" }
@@ -615,7 +551,6 @@ class IncrementOperator extends UnaryOperator {
* ```
*/
class DecrementOperator extends UnaryOperator {
DecrementOperator() { this.getName() = "--" }
override string getFunctionName() { result = "op_Decrement" }
@@ -631,7 +566,6 @@ class DecrementOperator extends UnaryOperator {
* ```
*/
class FalseOperator extends UnaryOperator {
FalseOperator() { this.getName() = "false" }
override string getFunctionName() { result = "op_False" }
@@ -647,7 +581,6 @@ class FalseOperator extends UnaryOperator {
* ```
*/
class TrueOperator extends UnaryOperator {
TrueOperator() { this.getName() = "true" }
override string getFunctionName() { result = "op_True" }
@@ -666,10 +599,7 @@ class TrueOperator extends UnaryOperator {
* a greater than operator (`GTOperator`), a less than or equals operator
* (`LEOperator`), or a greater than or equals operator (`GEOperator`).
*/
class BinaryOperator extends Operator {
BinaryOperator() { this.getNumberOfParameters() = 2 }
}
class BinaryOperator extends Operator { BinaryOperator() { this.getNumberOfParameters() = 2 } }
/**
* A user-defined addition operator (`+`), for example
@@ -681,7 +611,6 @@ class BinaryOperator extends Operator {
* ```
*/
class AddOperator extends BinaryOperator {
AddOperator() { this.getName() = "+" }
override string getFunctionName() { result = "op_Addition" }
@@ -697,7 +626,6 @@ class AddOperator extends BinaryOperator {
* ```
*/
class SubOperator extends BinaryOperator {
SubOperator() { this.getName() = "-" }
override string getFunctionName() { result = "op_Subtraction" }
@@ -713,7 +641,6 @@ class SubOperator extends BinaryOperator {
* ```
*/
class MulOperator extends BinaryOperator {
MulOperator() { this.getName() = "*" }
override string getFunctionName() { result = "op_Multiply" }
@@ -729,7 +656,6 @@ class MulOperator extends BinaryOperator {
* ```
*/
class DivOperator extends BinaryOperator {
DivOperator() { this.getName() = "/" }
override string getFunctionName() { result = "op_Division" }
@@ -745,7 +671,6 @@ class DivOperator extends BinaryOperator {
* ```
*/
class RemOperator extends BinaryOperator {
RemOperator() { this.getName() = "%" }
override string getFunctionName() { result = "op_Modulus" }
@@ -761,7 +686,6 @@ class RemOperator extends BinaryOperator {
* ```
*/
class AndOperator extends BinaryOperator {
AndOperator() { this.getName() = "&" }
override string getFunctionName() { result = "op_BitwiseAnd" }
@@ -777,7 +701,6 @@ class AndOperator extends BinaryOperator {
* ```
*/
class OrOperator extends BinaryOperator {
OrOperator() { this.getName() = "|" }
override string getFunctionName() { result = "op_BitwiseOr" }
@@ -793,7 +716,6 @@ class OrOperator extends BinaryOperator {
* ```
*/
class XorOperator extends BinaryOperator {
XorOperator() { this.getName() = "^" }
override string getFunctionName() { result = "op_ExclusiveOr" }
@@ -809,7 +731,6 @@ class XorOperator extends BinaryOperator {
* ```
*/
class LShiftOperator extends BinaryOperator {
LShiftOperator() { this.getName() = "<<" }
override string getFunctionName() { result = "op_LeftShift" }
@@ -825,7 +746,6 @@ class LShiftOperator extends BinaryOperator {
* ```
*/
class RShiftOperator extends BinaryOperator {
RShiftOperator() { this.getName() = ">>" }
override string getFunctionName() { result = "op_RightShift" }
@@ -841,7 +761,6 @@ class RShiftOperator extends BinaryOperator {
* ```
*/
class EQOperator extends BinaryOperator {
EQOperator() { this.getName() = "==" }
override string getFunctionName() { result = "op_Equality" }
@@ -857,7 +776,6 @@ class EQOperator extends BinaryOperator {
* ```
*/
class NEOperator extends BinaryOperator {
NEOperator() { this.getName() = "!=" }
override string getFunctionName() { result = "op_Inequality" }
@@ -873,7 +791,6 @@ class NEOperator extends BinaryOperator {
* ```
*/
class LTOperator extends BinaryOperator {
LTOperator() { this.getName() = "<" }
override string getFunctionName() { result = "op_LessThan" }
@@ -889,7 +806,6 @@ class LTOperator extends BinaryOperator {
* ```
*/
class GTOperator extends BinaryOperator {
GTOperator() { this.getName() = ">" }
override string getFunctionName() { result = "op_GreaterThan" }
@@ -905,7 +821,6 @@ class GTOperator extends BinaryOperator {
* ```
*/
class LEOperator extends BinaryOperator {
LEOperator() { this.getName() = "<=" }
override string getFunctionName() { result = "op_LessThanOrEqual" }
@@ -921,7 +836,6 @@ class LEOperator extends BinaryOperator {
* ```
*/
class GEOperator extends BinaryOperator {
GEOperator() { this.getName() = ">=" }
override string getFunctionName() { result = "op_GreaterThanOrEqual" }
@@ -937,7 +851,6 @@ class GEOperator extends BinaryOperator {
* ```
*/
class ConversionOperator extends Operator {
ConversionOperator() {
this.getName() = "implicit conversion" or
this.getName() = "explicit conversion"
@@ -960,10 +873,7 @@ class ConversionOperator extends Operator {
* ```
*/
class ImplicitConversionOperator extends ConversionOperator {
ImplicitConversionOperator() {
this.getName() = "implicit conversion"
}
ImplicitConversionOperator() { this.getName() = "implicit conversion" }
override string getFunctionName() { result = "op_Implicit" }
}
@@ -978,10 +888,7 @@ class ImplicitConversionOperator extends ConversionOperator {
* ```
*/
class ExplicitConversionOperator extends ConversionOperator {
ExplicitConversionOperator() {
this.getName() = "explicit conversion"
}
ExplicitConversionOperator() { this.getName() = "explicit conversion" }
override string getFunctionName() { result = "op_Explicit" }
}
@@ -1001,41 +908,25 @@ class ExplicitConversionOperator extends ConversionOperator {
* ```
*/
class LocalFunction extends Callable, @local_function {
override string getName() {
local_functions(this, result, _, _)
}
override string getName() { local_functions(this, result, _, _) }
override LocalFunction getSourceDeclaration() {
local_functions(this, _, _, result)
}
override LocalFunction getSourceDeclaration() { local_functions(this, _, _, result) }
override Type getReturnType() {
local_functions(this, _, result, _)
}
override Type getReturnType() { local_functions(this, _, result, _) }
override Element getParent() {
result = getStatement().getParent()
}
override Element getParent() { result = getStatement().getParent() }
/** Gets the local function statement defining this function. */
LocalFunctionStmt getStatement() {
result.getLocalFunction() = getSourceDeclaration()
}
LocalFunctionStmt getStatement() { result.getLocalFunction() = getSourceDeclaration() }
override Callable getEnclosingCallable() {
result = this.getStatement().getEnclosingCallable()
}
override Callable getEnclosingCallable() { result = this.getStatement().getEnclosingCallable() }
override predicate hasQualifiedName(string qualifier, string name) {
qualifier = this.getEnclosingCallable().getQualifiedName() and
name = this.getName()
}
override Location getALocation() {
result = getStatement().getALocation()
}
override Location getALocation() { result = getStatement().getALocation() }
override Parameter getRawParameter(int i) {
result = getParameter(i)
}
override Parameter getRawParameter(int i) { result = getParameter(i) }
}

View File

@@ -19,20 +19,14 @@ import csharp
* callable), the return type of `c` must be a subtype of `c`'s
* declaring type, and `c` must be non-static.
*/
predicate designedForChaining(Callable c) {
not nonChaining(c)
}
predicate designedForChaining(Callable c) { not nonChaining(c) }
private predicate nonChaining(Callable c) {
exists(Type t | t = c.getDeclaringType() | not t instanceof RefType)
or
exists(Method override |
override.getOverridee() = c |
nonChaining(override)
)
exists(Method override | override.getOverridee() = c | nonChaining(override))
or
exists(Getter override |
override.getDeclaration().getOverridee() = c.(Getter).getDeclaration() |
exists(Getter override | override.getDeclaration().getOverridee() = c.(Getter).getDeclaration() |
nonChaining(override)
)
or
@@ -47,25 +41,24 @@ private predicate nonChainingBody(Callable c) {
}
private Expr returnedValue(Callable c) {
exists(Expr e |
c.canReturn(e) |
if e instanceof ConditionalExpr then
exists(Expr e | c.canReturn(e) |
if e instanceof ConditionalExpr
then
result = e.(ConditionalExpr).getThen() or
result = e.(ConditionalExpr).getElse()
else
result = e
else result = e
)
}
/** Holds if `c` can return a non-`this` value. */
private predicate nonChainingReturn(Callable c) {
exists(Expr ret |
ret = returnedValue(c) |
exists(Expr ret | ret = returnedValue(c) |
// The result of a call is returned
exists(Callable other |
other = ret.(Call).getTarget() |
nonChaining(other) or
exists(MethodCall mc | mc = ret | not mc.hasThisQualifier()) or
exists(Callable other | other = ret.(Call).getTarget() |
nonChaining(other)
or
exists(MethodCall mc | mc = ret | not mc.hasThisQualifier())
or
exists(MemberAccess ma | ma = ret | not ma.hasThisQualifier())
)
or

View File

@@ -14,22 +14,21 @@ import Location
* Either a single line comment (`SingleLineComment`), an XML comment (`XmlComment`),
* or a line in a multi-line comment (`MultilineComment`).
*/
class CommentLine extends @commentline
{
class CommentLine extends @commentline {
/** Gets a textual representation of this comment line. */
string toString() { none() }
/** Gets the location of this comment line. */
Location getLocation() { commentline_location(this,result) }
Location getLocation() { commentline_location(this, result) }
/** Gets the containing comment block. */
CommentBlock getParent() { result.getAChild() = this }
/** Gets the text in the comment, trimmed to remove comment markers and leading and trailing whitespace. */
string getText() { commentline(this,_,result,_) }
string getText() { commentline(this, _, result, _) }
/** Gets the raw text of the comment, including the comment markers. */
string getRawText() { commentline(this,_,_,result) }
string getRawText() { commentline(this, _, _, result) }
}
/**
@@ -40,9 +39,8 @@ class CommentLine extends @commentline
* public int Succ(int x) => x + 1;
* ```
*/
class SinglelineComment extends CommentLine, @singlelinecomment
{
override string toString() { result="// ..." }
class SinglelineComment extends CommentLine, @singlelinecomment {
override string toString() { result = "// ..." }
}
/**
@@ -54,9 +52,8 @@ class SinglelineComment extends CommentLine, @singlelinecomment
* a comment * /
* ```
*/
class MultilineComment extends CommentLine, @multilinecomment
{
override string toString() { result="/* ... */" }
class MultilineComment extends CommentLine, @multilinecomment {
override string toString() { result = "/* ... */" }
}
/**
@@ -69,79 +66,79 @@ class MultilineComment extends CommentLine, @multilinecomment
* /// </summary>
* ```
*/
class XmlComment extends CommentLine, @xmldoccomment
{
override string toString() { result="/// ..." }
class XmlComment extends CommentLine, @xmldoccomment {
override string toString() { result = "/// ..." }
private string xmlAttributeRegex()
{ result = "(" + xmlIdentifierRegex() + ")(?:\\s*=\\s*[\"']([^\"']*)[\"'])" }
private string xmlAttributeRegex() {
result = "(" + xmlIdentifierRegex() + ")(?:\\s*=\\s*[\"']([^\"']*)[\"'])"
}
private string xmlIdentifierRegex()
{ result = "\\w+" }
private string xmlIdentifierRegex() { result = "\\w+" }
private string xmlTagOpenRegex()
{ result = "<\\s*" + xmlIdentifierRegex() }
private string xmlTagOpenRegex() { result = "<\\s*" + xmlIdentifierRegex() }
private string xmlTagIntroRegex()
{ result = xmlTagOpenRegex() + "(?:\\s*" + xmlAttributeRegex() +")*" }
private string xmlTagIntroRegex() {
result = xmlTagOpenRegex() + "(?:\\s*" + xmlAttributeRegex() + ")*"
}
private string xmlTagCloseRegex()
{ result = "</\\s*" + xmlIdentifierRegex() + "\\s*>" }
private string xmlTagCloseRegex() { result = "</\\s*" + xmlIdentifierRegex() + "\\s*>" }
/** Gets the text inside the XML element at character offset `offset`. */
private string getElement(int offset)
{
result = getText().regexpFind(xmlTagIntroRegex(),_,offset)
private string getElement(int offset) {
result = getText().regexpFind(xmlTagIntroRegex(), _, offset)
}
/** Gets the name of the opening tag at offset `offset`. */
string getOpenTag(int offset)
{
exists(int offset1,int offset2 |
result = getElement(offset1).regexpFind(xmlIdentifierRegex(),0,offset2)
and offset = offset1+offset2 )
string getOpenTag(int offset) {
exists(int offset1, int offset2 |
result = getElement(offset1).regexpFind(xmlIdentifierRegex(), 0, offset2) and
offset = offset1 + offset2
)
}
/** Gets the name of the closing tag at offset `offset`. */
string getCloseTag(int offset)
{
string getCloseTag(int offset) {
exists(int offset1, int offset2 |
result = getText().regexpFind(xmlTagCloseRegex(),_,offset1).
regexpFind(xmlIdentifierRegex(),0,offset2)
and offset = offset1+offset2 )
result = getText()
.regexpFind(xmlTagCloseRegex(), _, offset1)
.regexpFind(xmlIdentifierRegex(), 0, offset2) and
offset = offset1 + offset2
)
}
/** Gets the name of the empty tag at offset `offset`. */
string getEmptyTag(int offset)
{
string getEmptyTag(int offset) {
exists(int offset1, int offset2 |
(
result=getText().regexpFind(xmlTagIntroRegex() + "\\s*/>",_,offset1).
regexpFind(xmlIdentifierRegex(),0,offset2)
or result=getText().regexpFind(xmlTagIntroRegex() + "\\s*>\\s*</" + xmlIdentifierRegex() + "\\s*>",_,offset1).
regexpFind(xmlIdentifierRegex(),0,offset2)
) and offset=offset1+offset2 )
result = getText()
.regexpFind(xmlTagIntroRegex() + "\\s*/>", _, offset1)
.regexpFind(xmlIdentifierRegex(), 0, offset2) or
result = getText()
.regexpFind(xmlTagIntroRegex() + "\\s*>\\s*</" + xmlIdentifierRegex() + "\\s*>", _,
offset1)
.regexpFind(xmlIdentifierRegex(), 0, offset2)
) and
offset = offset1 + offset2
)
}
/**
* Gets the XML attribute value for an XML element,
* for a given XML attribute name `key` and element offset `offset`.
*/
string getAttribute(string element, string key, int offset)
{
exists(int offset1, int offset2, string elt, string pair |
elt = getElement(offset1) |
element = elt.regexpFind(xmlIdentifierRegex(),0,offset2)
and offset = offset1+offset2
and pair = elt.regexpFind(xmlAttributeRegex(),_,_)
and key = pair.regexpCapture(xmlAttributeRegex(),1)
and result = pair.regexpCapture(xmlAttributeRegex(),2) )
string getAttribute(string element, string key, int offset) {
exists(int offset1, int offset2, string elt, string pair | elt = getElement(offset1) |
element = elt.regexpFind(xmlIdentifierRegex(), 0, offset2) and
offset = offset1 + offset2 and
pair = elt.regexpFind(xmlAttributeRegex(), _, _) and
key = pair.regexpCapture(xmlAttributeRegex(), 1) and
result = pair.regexpCapture(xmlAttributeRegex(), 2)
)
}
/** Holds if the XML element at the given offset is not empty. */
predicate hasBody(string element, int offset)
{
element=getOpenTag(offset) and not element=getEmptyTag(offset)
predicate hasBody(string element, int offset) {
element = getOpenTag(offset) and not element = getEmptyTag(offset)
}
}
@@ -154,40 +151,39 @@ class XmlComment extends CommentLine, @xmldoccomment
* /// </summary>
* ```
*/
class CommentBlock extends @commentblock
{
class CommentBlock extends @commentblock {
/** Gets a textual representation of this comment block. */
string toString() { result=getChild(0).toString() }
string toString() { result = getChild(0).toString() }
/** Gets the location of this comment block */
Location getLocation() { commentblock_location(this,result) }
Location getLocation() { commentblock_location(this, result) }
/** Gets the number of lines in this comment block. */
int getNumLines() { result=count(getAChild()) }
int getNumLines() { result = count(getAChild()) }
/** Gets the `c`th child of this comment block (numbered from 0). */
CommentLine getChild(int c) { commentblock_child(this,result,c) }
CommentLine getChild(int c) { commentblock_child(this, result, c) }
/** Gets a comment line in this comment block. */
CommentLine getAChild() { commentblock_child(this,result,_) }
CommentLine getAChild() { commentblock_child(this, result, _) }
/** Gets the `Element` that contains this comment block, if any. */
Element getParent() { commentblock_binding(this,result,0) }
Element getParent() { commentblock_binding(this, result, 0) }
/** Gets the `Element` that this comment block most probably refers to. */
Element getElement() { commentblock_binding(this,result,1) }
Element getElement() { commentblock_binding(this, result, 1) }
/** Gets the `Element` before this comment block, if any. */
Element getBefore() { commentblock_binding(this,result,2) }
Element getBefore() { commentblock_binding(this, result, 2) }
/** Gets the `Element` after this comment, if any. */
Element getAfter(){ commentblock_binding(this,result,3) }
Element getAfter() { commentblock_binding(this, result, 3) }
/**
* Gets an `Element` possibly associated with this comment.
* This is a superset of `getElement()`.
*/
Element getAnElement() { commentblock_binding(this,result,_) }
Element getAnElement() { commentblock_binding(this, result, _) }
/** Gets a line of text in this comment block. */
string getALine() { result = getAChild().getText() }
@@ -196,24 +192,19 @@ class CommentBlock extends @commentblock
predicate isOrphan() { not exists(getElement()) }
/** Holds if this block consists entirely of XML comments. */
predicate isXmlCommentBlock()
{
forall(CommentLine l | l = getAChild() | l instanceof XmlComment )
predicate isXmlCommentBlock() {
forall(CommentLine l | l = getAChild() | l instanceof XmlComment)
}
/** Gets a `CommentLine` containing text. */
CommentLine getANonEmptyLine()
{
result = getAChild() and result.getText().length()!=0
}
CommentLine getANonEmptyLine() { result = getAChild() and result.getText().length() != 0 }
/** Gets a `CommentLine` that might contain code. */
CommentLine getAProbableCodeLine()
{
CommentLine getAProbableCodeLine() {
// Logic taken verbatim from Java query CommentedCode.qll
result=getAChild() and
exists(string trimmed |
trimmed = result.getText().regexpReplaceAll("\\s*//.*$", "") |
trimmed.matches("%;") or trimmed.matches("%{") or trimmed.matches("%}"))
result = getAChild() and
exists(string trimmed | trimmed = result.getText().regexpReplaceAll("\\s*//.*$", "") |
trimmed.matches("%;") or trimmed.matches("%{") or trimmed.matches("%}")
)
}
}

View File

@@ -55,27 +55,20 @@ private predicate implicitConversionNonNull(Type fromType, Type toType) {
}
private Type getTypeArgument(UnboundGenericType ugt, ConstructedType ct, int i, TypeParameter tp) {
ct.getUnboundGeneric() = ugt
and
not ugt instanceof AnonymousClass
and
tp = ugt.getTypeParameter(i)
and
ct.getUnboundGeneric() = ugt and
not ugt instanceof AnonymousClass and
tp = ugt.getTypeParameter(i) and
result = ct.getTypeArgument(i)
}
/** A type that is an element type of an array type. */
private class ArrayElementType extends Type {
ArrayElementType() {
this = any(ArrayType at).getElementType()
}
ArrayElementType() { this = any(ArrayType at).getElementType() }
}
/** A type that is an argument in a constructed type. */
private class TypeArgument extends Type {
TypeArgument() {
this = any(ConstructedType ct).getATypeArgument()
}
TypeArgument() { this = any(ConstructedType ct).getATypeArgument() }
}
/**
@@ -97,14 +90,13 @@ predicate convIdentity(Type fromType, Type toType) {
private module Identity {
private class IdentityConvertibleType extends Type {
IdentityConvertibleType() {
isIdentityConvertible(this)
}
IdentityConvertibleType() { isIdentityConvertible(this) }
}
private class IdentityConvertibleArrayType extends IdentityConvertibleType, ArrayType { }
private class IdentityConvertibleConstructedType extends IdentityConvertibleType, ConstructedType { }
private class IdentityConvertibleConstructedType extends IdentityConvertibleType, ConstructedType {
}
/**
* A type is (strictly) identity convertible if it contains at least one `object`
@@ -130,20 +122,24 @@ private module Identity {
convIdentityStrictConstructedType(fromType, toType)
}
private predicate convIdentityObjectDynamic(ObjectType fromType, DynamicType toType) {
any()
}
private predicate convIdentityObjectDynamic(ObjectType fromType, DynamicType toType) { any() }
private predicate convIdentityStrictArrayType(IdentityConvertibleArrayType fromType, IdentityConvertibleArrayType toType) {
private predicate convIdentityStrictArrayType(
IdentityConvertibleArrayType fromType, IdentityConvertibleArrayType toType
) {
convIdentityStrictArrayTypeJoin(fromType, toType, toType.getDimension(), toType.getRank())
}
pragma[noinline]
private predicate convIdentityStrictArrayTypeJoin(IdentityConvertibleArrayType fromType, IdentityConvertibleArrayType toType, int dim, int rnk) {
private predicate convIdentityStrictArrayTypeJoin(
IdentityConvertibleArrayType fromType, IdentityConvertibleArrayType toType, int dim, int rnk
) {
convIdentityStrictArrayElementType(fromType, toType.getElementType(), dim, rnk)
}
private predicate convIdentityStrictArrayElementType(IdentityConvertibleArrayType fromType, ArrayElementType aet, int dim, int rnk) {
private predicate convIdentityStrictArrayElementType(
IdentityConvertibleArrayType fromType, ArrayElementType aet, int dim, int rnk
) {
convIdentityStrict(fromType.getElementType(), aet) and
dim = fromType.getDimension() and
rnk = fromType.getRank()
@@ -155,22 +151,20 @@ private module Identity {
*/
private int getTypeArgumentCount(UnboundGenericType ugt, int i) {
result = strictcount(Type arg |
exists(IdentityConvertibleConstructedType ct |
ct.getUnboundGeneric() = ugt |
arg = ct.getTypeArgument(i)
exists(IdentityConvertibleConstructedType ct | ct.getUnboundGeneric() = ugt |
arg = ct.getTypeArgument(i)
)
)
)
}
private int rnk(UnboundGenericType ugt, int i) {
result = rank[i + 1](int j, int k |
j = getTypeArgumentCount(ugt, k) |
k order by j, k
)
result = rank[i + 1](int j, int k | j = getTypeArgumentCount(ugt, k) | k order by j, k)
}
/** Gets the 'i'th type argument, ranked by size, of constructed type `t`. */
private Type getTypeArgumentRanked(UnboundGenericType ugt, IdentityConvertibleConstructedType t, int i) {
private Type getTypeArgumentRanked(
UnboundGenericType ugt, IdentityConvertibleConstructedType t, int i
) {
result = getTypeArgument(ugt, t, rnk(ugt, i), _)
}
@@ -183,14 +177,17 @@ private module Identity {
exists(int j |
fromTypeArgument = getTypeArgumentRanked(_, _, i) and
toTypeArgument = getTypeArgumentRanked(_, _, j) and
i <= j and j <= i
|
i <= j and
j <= i
|
convIdentity(fromTypeArgument, toTypeArgument)
)
}
pragma[nomagic]
private predicate convTypeArgumentsSomeUnbound(UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i) {
private predicate convTypeArgumentsSomeUnbound(
UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i
) {
convTypeArguments(fromTypeArgument, toTypeArgument, i) and
fromTypeArgument = getTypeArgumentRanked(ugt, _, i)
}
@@ -201,13 +198,18 @@ private module Identity {
* based on unbound generic type `ugt`.
*/
pragma[noinline]
private predicate convTypeArgumentsSameUnbound(UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i) {
private predicate convTypeArgumentsSameUnbound(
UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i
) {
convTypeArgumentsSomeUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
toTypeArgument = getTypeArgumentRanked(ugt, _, i)
}
pragma[nomagic]
private predicate convIdentitySingle0(UnboundGenericType ugt, IdentityConvertibleConstructedType toType, TypeArgument fromTypeArgument, TypeArgument toTypeArgument) {
private predicate convIdentitySingle0(
UnboundGenericType ugt, IdentityConvertibleConstructedType toType,
TypeArgument fromTypeArgument, TypeArgument toTypeArgument
) {
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, 0) and
toTypeArgument = getTypeArgumentRanked(ugt, toType, 0) and
ugt.getNumberOfTypeParameters() = 1
@@ -217,22 +219,32 @@ private module Identity {
* Holds if the type arguments of types `fromType` and `toType` are identity
* convertible, and the number of type arguments is 1.
*/
predicate convIdentitySingle(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType) {
predicate convIdentitySingle(
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
IdentityConvertibleConstructedType toType
) {
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
convIdentitySingle0(ugt, toType, fromTypeArgument, toTypeArgument) |
convIdentitySingle0(ugt, toType, fromTypeArgument, toTypeArgument)
|
fromTypeArgument = getTypeArgumentRanked(ugt, fromType, 0)
)
}
pragma[nomagic]
private predicate convIdentityMultiple01Aux0(UnboundGenericType ugt, IdentityConvertibleConstructedType toType, TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1) {
private predicate convIdentityMultiple01Aux0(
UnboundGenericType ugt, IdentityConvertibleConstructedType toType,
TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1
) {
convTypeArgumentsSameUnbound(ugt, fromTypeArgument0, toTypeArgument0, 0) and
toTypeArgument0 = getTypeArgumentRanked(ugt, toType, 0) and
toTypeArgument1 = getTypeArgumentRanked(ugt, toType, 1)
}
pragma[nomagic]
private predicate convIdentityMultiple01Aux1(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1) {
private predicate convIdentityMultiple01Aux1(
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1
) {
convTypeArgumentsSameUnbound(ugt, fromTypeArgument1, toTypeArgument1, 1) and
fromTypeArgument0 = getTypeArgumentRanked(ugt, fromType, 0) and
fromTypeArgument1 = getTypeArgumentRanked(ugt, fromType, 1)
@@ -242,23 +254,37 @@ private module Identity {
* Holds if the first two ranked type arguments of types `fromType` and `toType`
* are identity convertible.
*/
private predicate convIdentityMultiple01(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType) {
exists(Type fromTypeArgument0, Type toTypeArgument0, Type fromTypeArgument1, Type toTypeArgument1 |
convIdentityMultiple01Aux0(ugt, toType, fromTypeArgument0, toTypeArgument0, toTypeArgument1) |
convIdentityMultiple01Aux1(ugt, fromType, fromTypeArgument0, fromTypeArgument1, toTypeArgument1)
private predicate convIdentityMultiple01(
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
IdentityConvertibleConstructedType toType
) {
exists(
Type fromTypeArgument0, Type toTypeArgument0, Type fromTypeArgument1, Type toTypeArgument1
|
convIdentityMultiple01Aux0(ugt, toType, fromTypeArgument0, toTypeArgument0, toTypeArgument1)
|
convIdentityMultiple01Aux1(ugt, fromType, fromTypeArgument0, fromTypeArgument1,
toTypeArgument1)
)
}
pragma[nomagic]
private predicate convIdentityMultiple2Aux(UnboundGenericType ugt, IdentityConvertibleConstructedType toType, int i, TypeArgument fromTypeArgument, TypeArgument toTypeArgument) {
private predicate convIdentityMultiple2Aux(
UnboundGenericType ugt, IdentityConvertibleConstructedType toType, int i,
TypeArgument fromTypeArgument, TypeArgument toTypeArgument
) {
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
toTypeArgument = getTypeArgumentRanked(ugt, toType, i) and
i >= 2
}
private predicate convIdentityMultiple2(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType, int i) {
private predicate convIdentityMultiple2(
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
IdentityConvertibleConstructedType toType, int i
) {
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
convIdentityMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument) |
convIdentityMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument)
|
fromTypeArgument = getTypeArgumentRanked(ugt, fromType, i)
)
}
@@ -268,15 +294,21 @@ private module Identity {
* `fromType` and `toType` are identity convertible.
*/
pragma[nomagic]
predicate convIdentityMultiple(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType, int i) {
predicate convIdentityMultiple(
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
IdentityConvertibleConstructedType toType, int i
) {
convIdentityMultiple01(ugt, fromType, toType) and i = 1
or
convIdentityMultiple(ugt, fromType, toType, i - 1) and
convIdentityMultiple2(ugt, fromType, toType, i)
}
private predicate convIdentityStrictConstructedType(IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType) {
/* Semantically equivalent with
private predicate convIdentityStrictConstructedType(
IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType
) {
/*
* Semantically equivalent with
* ```
* ugt = fromType.getUnboundGeneric()
* and
@@ -292,6 +324,7 @@ private module Identity {
* but performance is improved by explicitly evaluating the `i`th argument
* only when all preceding arguments are convertible.
*/
fromType != toType and
(
convIdentitySingle(_, fromType, toType)
@@ -409,9 +442,7 @@ private predicate convNumericChar(SimpleType toType) {
toType instanceof DecimalType
}
private predicate convNumericFloat(SimpleType toType) {
toType instanceof DoubleType
}
private predicate convNumericFloat(SimpleType toType) { toType instanceof DoubleType }
/**
* INTERNAL: Do not use.
@@ -421,10 +452,8 @@ private predicate convNumericFloat(SimpleType toType) {
* 6.1.4: Implicit nullable conversions.
*/
predicate convNullableType(ValueOrRefType fromType, NullableType toType) {
exists(ValueType vt1, ValueType vt2 |
implicitConversionNonNull(vt1, vt2) |
toType.getUnderlyingType() = vt2
and
exists(ValueType vt1, ValueType vt2 | implicitConversionNonNull(vt1, vt2) |
toType.getUnderlyingType() = vt2 and
(
fromType = vt1
or
@@ -437,9 +466,9 @@ predicate convNullableType(ValueOrRefType fromType, NullableType toType) {
* This is a deliberate, small Cartesian product, so we have manually lifted it to force the
* evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
*/
pragma[noinline]
private
predicate defaultNullConversion(Type fromType, Type toType) {
private predicate defaultNullConversion(Type fromType, Type toType) {
fromType instanceof NullType and convNullType(toType)
}
@@ -466,6 +495,7 @@ private predicate convRefTypeNonNull(Type fromType, Type toType) {
* This is a deliberate, small cartesian product, so we have manually lifted it to force the
* evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
*/
pragma[noinline]
private predicate defaultDynamicConversion(Type fromType, Type toType) {
fromType instanceof RefType and toType instanceof DynamicType
@@ -475,6 +505,7 @@ private predicate defaultDynamicConversion(Type fromType, Type toType) {
* This is a deliberate, small cartesian product, so we have manually lifted it to force the
* evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
*/
pragma[noinline]
private predicate defaultDelegateConversion(RefType fromType, RefType toType) {
fromType instanceof DelegateType and toType = any(SystemDelegateClass c).getABaseType*()
@@ -489,8 +520,7 @@ private predicate convRefTypeRefType(RefType fromType, RefType toType) {
or
defaultDelegateConversion(fromType, toType)
or
exists(Type t |
convIdentity(fromType, t) or convRefTypeRefType(fromType, t) |
exists(Type t | convIdentity(fromType, t) or convRefTypeRefType(fromType, t) |
convIdentity(t, toType) or convVariance(t, toType)
)
}
@@ -499,6 +529,7 @@ private predicate convRefTypeRefType(RefType fromType, RefType toType) {
* This is a deliberate, small cartesian product, so we have manually lifted it to force the
* evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
*/
pragma[noinline]
private predicate defaultArrayConversion(Type fromType, RefType toType) {
fromType instanceof ArrayType and toType = any(SystemArrayClass c).getABaseType*()
@@ -513,12 +544,10 @@ private predicate convArrayTypeRefType(ArrayType fromType, RefType toType) {
fromType.getDimension() = 1 and
fromType.getRank() = 1 and
argumentType = getIListTypeArgument(ci) and
exists(ArrayElementType elementType |
elementType = fromType.getElementType() |
exists(ArrayElementType elementType | elementType = fromType.getElementType() |
convIdentity(elementType, argumentType) or
convRefTypeNonNull(elementType, argumentType)
)
and
) and
toType = ci.getABaseType*()
)
}
@@ -567,8 +596,7 @@ predicate convBoxing(Type fromType, Type toType) {
or
convBoxingTypeParameter(fromType, toType)
or
exists(Type t |
convBoxing(fromType, t) |
exists(Type t | convBoxing(fromType, t) |
convIdentity(t, toType) or
convVariance(t, toType)
)
@@ -605,13 +633,17 @@ private class SignedIntegralConstantExpr extends Expr {
}
private predicate convConstantIntExpr(SignedIntegralConstantExpr e, SimpleType toType) {
exists(int n |
n = e.getValue().toInt() |
toType = any(SByteType t | n in [t.minValue() .. t.maxValue()]) or
toType = any(ByteType t | n in [t.minValue() .. t.maxValue()]) or
toType = any(ShortType t | n in [t.minValue() .. t.maxValue()]) or
toType = any(UShortType t | n in [t.minValue() .. t.maxValue()]) or
toType instanceof UIntType and n >= 0 or
exists(int n | n = e.getValue().toInt() |
toType = any(SByteType t | n in [t.minValue() .. t.maxValue()])
or
toType = any(ByteType t | n in [t.minValue() .. t.maxValue()])
or
toType = any(ShortType t | n in [t.minValue() .. t.maxValue()])
or
toType = any(UShortType t | n in [t.minValue() .. t.maxValue()])
or
toType instanceof UIntType and n >= 0
or
toType instanceof ULongType and n >= 0
)
}
@@ -637,8 +669,7 @@ private predicate convBoxingTypeParameter(TypeParameter fromType, Type toType) {
private predicate convTypeParameter(TypeParameter fromType, Type toType) {
toType = convTypeParameterBase(fromType)
or
exists(Type t |
convTypeParameter(fromType, t) |
exists(Type t | convTypeParameter(fromType, t) |
convIdentity(t, toType) or
convVariance(t, toType)
)
@@ -663,8 +694,7 @@ private Type convTypeParameterBase(TypeParameter tp) {
private Class effectiveBaseClassCandidate(TypeParameter tp) {
not hasPrimaryConstraints(tp) and result instanceof ObjectType
or
exists(TypeParameterConstraints tpc |
tpc = tp.getConstraints() |
exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
tpc.hasValueTypeConstraint() and result instanceof SystemValueTypeClass
or
result = tpc.getClassConstraint()
@@ -677,8 +707,7 @@ private Class effectiveBaseClassCandidate(TypeParameter tp) {
/** 10.1.5: Whether type parameter `tp` has primary constraints. */
private predicate hasPrimaryConstraints(TypeParameter tp) {
exists(TypeParameterConstraints tpc |
tpc = tp.getConstraints() |
exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
exists(tpc.getClassConstraint())
or
tpc.hasRefTypeConstraint()
@@ -689,8 +718,7 @@ private predicate hasPrimaryConstraints(TypeParameter tp) {
/** 10.1.5: The effective interface set of a type parameter `tp` */
private Interface effectiveInterfaceSet(TypeParameter tp) {
exists(TypeParameterConstraints tpc |
tpc = tp.getConstraints() |
exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
result = tpc.getAnInterfaceConstraint()
or
result = effectiveInterfaceSet(tpc.getATypeParameterConstraint())
@@ -717,7 +745,8 @@ predicate convConversionOperator(Type fromType, Type toType) {
/** 13.1.3.2: Variance conversion. */
private predicate convVariance(ConstructedType fromType, ConstructedType toType) {
/* Semantically equivalent with
/*
* Semantically equivalent with
* ```
* ugt = fromType.getUnboundGeneric()
* and
@@ -737,6 +766,7 @@ private predicate convVariance(ConstructedType fromType, ConstructedType toType)
* but performance is improved by explicitly evaluating the `i`th argument
* only when all preceding arguments are convertible.
*/
Variance::convVarianceSingle(_, fromType, toType)
or
exists(UnboundGenericType ugt |
@@ -753,18 +783,15 @@ private module Variance {
private predicate isVarianceConvertible(ConstructedType ct, int i) {
exists(TypeParameter tp, Type t |
tp = ct.getUnboundGeneric().getTypeParameter(i) and
t = ct.getTypeArgument(i) |
(
// Anything that is not a type parameter is potentially convertible
// to/from another type; if the `i`th type parameter is invariant,
// `t` must be strictly identity convertible
not t instanceof TypeParameter
and
(tp.isIn() or tp.isOut() or Identity::convIdentityStrict(t, _))
)
t = ct.getTypeArgument(i)
|
// Anything that is not a type parameter is potentially convertible
// to/from another type; if the `i`th type parameter is invariant,
// `t` must be strictly identity convertible
not t instanceof TypeParameter and
(tp.isIn() or tp.isOut() or Identity::convIdentityStrict(t, _))
or
exists(TypeParameter s |
s = t |
exists(TypeParameter s | s = t |
// A type parameter with implicit reference conversion
exists(convTypeParameterBase(s)) and s.isRefType() and tp.isOut()
or
@@ -775,9 +802,7 @@ private module Variance {
}
private class VarianceConvertibleConstructedType extends ConstructedType {
VarianceConvertibleConstructedType() {
isVarianceConvertible(this, _)
}
VarianceConvertibleConstructedType() { isVarianceConvertible(this, _) }
}
/**
@@ -786,22 +811,20 @@ private module Variance {
*/
private int getTypeArgumentCount(UnboundGenericType ugt, int i) {
result = strictcount(Type arg |
exists(VarianceConvertibleConstructedType ct |
ct.getUnboundGeneric() = ugt |
arg = ct.getTypeArgument(i)
exists(VarianceConvertibleConstructedType ct | ct.getUnboundGeneric() = ugt |
arg = ct.getTypeArgument(i)
)
)
)
}
private int rnk(UnboundGenericType ugt, int i) {
result = rank[i + 1](int j, int k |
j = getTypeArgumentCount(ugt, k) |
k order by j, k
)
result = rank[i + 1](int j, int k | j = getTypeArgumentCount(ugt, k) | k order by j, k)
}
/** Gets the 'i'th type argument, ranked by size, of constructed type `t`. */
private Type getTypeArgumentRanked(UnboundGenericType ugt, VarianceConvertibleConstructedType t, int i, TypeParameter tp) {
private Type getTypeArgumentRanked(
UnboundGenericType ugt, VarianceConvertibleConstructedType t, int i, TypeParameter tp
) {
result = getTypeArgument(ugt, t, rnk(ugt, i), tp)
}
@@ -825,19 +848,25 @@ private module Variance {
toType = getATypeArgumentRankedIn(i)
}
private newtype TVariance = TNone() or TIn() or TOut()
private newtype TVariance =
TNone() or
TIn() or
TOut()
/**
* Holds if `fromTypeArgument` is convertible to `toTypeArgument`, with variance
* `v`, and both types are the `i`th type argument in _some_ constructed type.
*/
pragma[nomagic]
private predicate convTypeArguments(TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i, TVariance v) {
private predicate convTypeArguments(
TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i, TVariance v
) {
exists(int j |
fromTypeArgument = getTypeArgumentRanked(_, _, i, _) and
toTypeArgument = getTypeArgumentRanked(_, _, j, _) and
i <= j and j <= i
|
i <= j and
j <= i
|
convIdentity(fromTypeArgument, toTypeArgument) and
v = TNone()
or
@@ -850,9 +879,12 @@ private module Variance {
}
pragma[nomagic]
private predicate convTypeArgumentsSomeUnbound(UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i) {
private predicate convTypeArgumentsSomeUnbound(
UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i
) {
exists(TypeParameter tp, TVariance v |
convTypeArguments(fromTypeArgument, toTypeArgument, i, v) |
convTypeArguments(fromTypeArgument, toTypeArgument, i, v)
|
fromTypeArgument = getTypeArgumentRanked(ugt, _, i, tp) and
(v = TIn() implies tp.isIn()) and
(v = TOut() implies tp.isOut())
@@ -865,13 +897,18 @@ private module Variance {
* based on unbound generic type `ugt`.
*/
pragma[noinline]
private predicate convTypeArgumentsSameUnbound(UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i) {
private predicate convTypeArgumentsSameUnbound(
UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i
) {
convTypeArgumentsSomeUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
toTypeArgument = getTypeArgumentRanked(ugt, _, i, _)
}
pragma[nomagic]
private predicate convVarianceSingle0(UnboundGenericType ugt, VarianceConvertibleConstructedType toType, TypeArgument fromTypeArgument, TypeArgument toTypeArgument) {
private predicate convVarianceSingle0(
UnboundGenericType ugt, VarianceConvertibleConstructedType toType,
TypeArgument fromTypeArgument, TypeArgument toTypeArgument
) {
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, 0) and
toTypeArgument = getTypeArgumentRanked(ugt, toType, 0, _) and
ugt.getNumberOfTypeParameters() = 1
@@ -881,22 +918,32 @@ private module Variance {
* Holds if the type arguments of types `fromType` and `toType` are variance
* convertible, and the number of type arguments is 1.
*/
predicate convVarianceSingle(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType) {
predicate convVarianceSingle(
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
VarianceConvertibleConstructedType toType
) {
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
convVarianceSingle0(ugt, toType, fromTypeArgument, toTypeArgument) |
convVarianceSingle0(ugt, toType, fromTypeArgument, toTypeArgument)
|
fromTypeArgument = getTypeArgumentRanked(ugt, fromType, 0, _)
)
}
pragma[nomagic]
private predicate convVarianceMultiple01Aux0(UnboundGenericType ugt, VarianceConvertibleConstructedType toType, TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1) {
private predicate convVarianceMultiple01Aux0(
UnboundGenericType ugt, VarianceConvertibleConstructedType toType,
TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1
) {
convTypeArgumentsSameUnbound(ugt, fromTypeArgument0, toTypeArgument0, 0) and
toTypeArgument0 = getTypeArgumentRanked(ugt, toType, 0, _) and
toTypeArgument1 = getTypeArgumentRanked(ugt, toType, 1, _)
}
pragma[nomagic]
private predicate convVarianceMultiple01Aux1(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1) {
private predicate convVarianceMultiple01Aux1(
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1
) {
convTypeArgumentsSameUnbound(ugt, fromTypeArgument1, toTypeArgument1, 1) and
fromTypeArgument0 = getTypeArgumentRanked(ugt, fromType, 0, _) and
fromTypeArgument1 = getTypeArgumentRanked(ugt, fromType, 1, _)
@@ -906,23 +953,38 @@ private module Variance {
* Holds if the first two ranked type arguments of types `fromType` and `toType`
* are variance convertible.
*/
private predicate convVarianceMultiple01(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType) {
exists(TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1 |
convVarianceMultiple01Aux0(ugt, toType, fromTypeArgument0, toTypeArgument0, toTypeArgument1) |
convVarianceMultiple01Aux1(ugt, fromType, fromTypeArgument0, fromTypeArgument1, toTypeArgument1)
private predicate convVarianceMultiple01(
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
VarianceConvertibleConstructedType toType
) {
exists(
TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument fromTypeArgument1,
TypeArgument toTypeArgument1
|
convVarianceMultiple01Aux0(ugt, toType, fromTypeArgument0, toTypeArgument0, toTypeArgument1)
|
convVarianceMultiple01Aux1(ugt, fromType, fromTypeArgument0, fromTypeArgument1,
toTypeArgument1)
)
}
pragma[nomagic]
private predicate convVarianceMultiple2Aux(UnboundGenericType ugt, VarianceConvertibleConstructedType toType, int i, TypeArgument fromTypeArgument, TypeArgument toTypeArgument) {
private predicate convVarianceMultiple2Aux(
UnboundGenericType ugt, VarianceConvertibleConstructedType toType, int i,
TypeArgument fromTypeArgument, TypeArgument toTypeArgument
) {
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
toTypeArgument = getTypeArgumentRanked(ugt, toType, i, _) and
i >= 2
}
private predicate convVarianceMultiple2(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType, int i) {
private predicate convVarianceMultiple2(
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
VarianceConvertibleConstructedType toType, int i
) {
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
convVarianceMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument) |
convVarianceMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument)
|
fromTypeArgument = getTypeArgumentRanked(ugt, fromType, i, _)
)
}
@@ -932,7 +994,10 @@ private module Variance {
* `fromType` and `toType` are variance convertible.
*/
pragma[nomagic]
predicate convVarianceMultiple(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType, int i) {
predicate convVarianceMultiple(
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
VarianceConvertibleConstructedType toType, int i
) {
convVarianceMultiple01(ugt, fromType, toType) and i = 1
or
convVarianceMultiple(ugt, fromType, toType, i - 1) and

View File

@@ -48,15 +48,11 @@ class Element extends DotNet::Element, @element {
/** Gets the number of children of this element. */
pragma[nomagic]
int getNumberOfChildren() {
result = count(int i | exists(this.getChild(i)))
}
int getNumberOfChildren() { result = count(int i | exists(this.getChild(i))) }
/**
* Gets the index of this element among its parent's
* other children (zero-based).
*/
int getIndex() {
exists(Element parent | parent.getChild(result) = this)
}
int getIndex() { exists(Element parent | parent.getChild(result) = this) }
}

View File

@@ -18,13 +18,15 @@ private import semmle.code.csharp.ExprOrStmtParent
/**
* INTERNAL: Do not use.
*/
cached module Internal {
cached
module Internal {
/**
* INTERNAL: Do not use.
*
* Holds if `c` is the enclosing callable of statement `s`.
*/
cached predicate enclosingCallable(Stmt s, Callable c) {
cached
predicate enclosingCallable(Stmt s, Callable c) {
/*
* Compute the enclosing callable for a statement. This walks up through
* enclosing statements until it hits a callable. It's unambiguous, since
@@ -32,6 +34,7 @@ cached module Internal {
* or the body of an anonymous function declaration, in each of which cases the
* non-statement parent is in fact the enclosing callable.
*/
c.getAChildStmt+() = s
}
@@ -45,21 +48,22 @@ cached module Internal {
*
* Holds if `s` is the enclosing statement of expression `e`.
*/
cached predicate enclosingStmt(Expr e, Stmt s) {
cached
predicate enclosingStmt(Expr e, Stmt s) {
/*
* Compute the enclosing statement for an expression. Note that this need
* not exist, since expressions can occur in contexts where they have no
* enclosing statement (examples include field initialisers, both inline
* and explicit on constructor definitions, and annotation arguments).
*/
getAChildExpr+(s) = e
}
private predicate childExprOfCallable(Callable parent, Expr child) {
child = getAChildExpr(parent)
or
exists(Expr mid |
childExprOfCallable(parent, mid) |
exists(Expr mid | childExprOfCallable(parent, mid) |
not mid instanceof Callable and
child = getAChildExpr(mid)
)
@@ -70,7 +74,8 @@ cached module Internal {
*
* Holds if `c` is the enclosing callable of expression `e`.
*/
cached predicate exprEnclosingCallable(Expr e, Callable c) {
cached
predicate exprEnclosingCallable(Expr e, Callable c) {
/*
* Compute the enclosing callable of an expression. Note that expressions in
* lambda functions should have the lambdas as enclosing callables, and their
@@ -78,6 +83,7 @@ cached module Internal {
* lambda; thus, it is *not* safe to go up to the enclosing statement and
* take its own enclosing callable.
*/
childExprOfCallable(c, e)
or
not childExprOfCallable(_, e) and

View File

@@ -16,12 +16,11 @@ import Type
* ```
*/
class Event extends DeclarationWithAccessors, @event {
override string getName() { events(this, result, _, _, _) }
override string getName() { events(this,result,_,_,_) }
override ValueOrRefType getDeclaringType() { events(this, _, result, _, _) }
override ValueOrRefType getDeclaringType() { events(this,_,result,_,_) }
override DelegateType getType() { events(this,_,_,getTypeRef(result),_) }
override DelegateType getType() { events(this, _, _, getTypeRef(result), _) }
/** Gets an `add` or `remove` accessor of this event, if any. */
EventAccessor getAnEventAccessor() { result.getDeclaration() = this }
@@ -43,23 +42,15 @@ class Event extends DeclarationWithAccessors, @event {
not this.getAnEventAccessor().hasBody()
}
override Event getSourceDeclaration() { events(this,_,_,_,result) }
override Event getSourceDeclaration() { events(this, _, _, _, result) }
override Event getOverridee() {
result = DeclarationWithAccessors.super.getOverridee()
}
override Event getOverridee() { result = DeclarationWithAccessors.super.getOverridee() }
override Event getAnOverrider() {
result = DeclarationWithAccessors.super.getAnOverrider()
}
override Event getAnOverrider() { result = DeclarationWithAccessors.super.getAnOverrider() }
override Event getImplementee() {
result = DeclarationWithAccessors.super.getImplementee()
}
override Event getImplementee() { result = DeclarationWithAccessors.super.getImplementee() }
override Event getAnImplementor() {
result = DeclarationWithAccessors.super.getAnImplementor()
}
override Event getAnImplementor() { result = DeclarationWithAccessors.super.getAnImplementor() }
override Event getAnUltimateImplementee() {
result = DeclarationWithAccessors.super.getAnUltimateImplementee()
@@ -69,7 +60,7 @@ class Event extends DeclarationWithAccessors, @event {
result = DeclarationWithAccessors.super.getAnUltimateImplementor()
}
override Location getALocation() { event_location(this,result) }
override Location getALocation() { event_location(this, result) }
}
/**
@@ -92,13 +83,13 @@ class EventAccessor extends Accessor, @event_accessor {
result instanceof VoidType
}
override string getAssemblyName() { event_accessors(this,_,result,_,_) }
override string getAssemblyName() { event_accessors(this, _, result, _, _) }
override EventAccessor getSourceDeclaration() { event_accessors(this,_,_,_,result) }
override EventAccessor getSourceDeclaration() { event_accessors(this, _, _, _, result) }
override Event getDeclaration() { event_accessors(this,_,_,result,_) }
override Event getDeclaration() { event_accessors(this, _, _, result, _) }
override Location getALocation() { event_accessor_location(this,result) }
override Location getALocation() { event_accessor_location(this, result) }
}
/**
@@ -132,5 +123,5 @@ class AddEventAccessor extends EventAccessor, @add_event_accessor {
* ```
*/
class RemoveEventAccessor extends EventAccessor, @remove_event_accessor {
override string getName() { result = "remove" + "_" + getDeclaration().getName() }
override string getName() { result = "remove" + "_" + getDeclaration().getName() }
}

View File

@@ -3,6 +3,7 @@
*
* Provides logic for calculating the child relation on expressions and statements.
*/
import csharp
/**
@@ -14,9 +15,7 @@ import csharp
predicate expr_parent_top_level_adjusted(Expr child, int i, @top_level_exprorstmt_parent parent) {
expr_parent_top_level(child, i, parent)
or
parent = any(Getter g |
expr_parent_top_level(child, i, g.getDeclaration())
)
parent = any(Getter g | expr_parent_top_level(child, i, g.getDeclaration()))
}
/**
@@ -51,12 +50,12 @@ predicate expr_parent_top_level_adjusted(Expr child, int i, @top_level_exprorstm
* ```
*/
private predicate expr_parent_adjusted(Expr child, int i, ControlFlowElement parent) {
exists(AssignExpr ae |
ae = parent.(AssignOperation).getExpandedAssignment() |
exists(AssignExpr ae | ae = parent.(AssignOperation).getExpandedAssignment() |
i = 0 and
exists(Expr right |
// right = `x + y`
expr_parent(right, 0, ae) |
expr_parent(right, 0, ae)
|
expr_parent(child, 1, right)
)
or
@@ -86,9 +85,7 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent {
}
/** Gets a child expression of this element, if any. */
final Expr getAChildExpr() {
result = this.getChildExpr(_)
}
final Expr getAChildExpr() { result = this.getChildExpr(_) }
/** Gets the `i`th child statement of this element (zero-based). */
final Stmt getChildStmt(int i) {
@@ -97,9 +94,7 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent {
}
/** Gets a child statement of this element, if any. */
final Stmt getAChildStmt() {
result = this.getChildStmt(_)
}
final Stmt getAChildStmt() { result = this.getChildStmt(_) }
}
/**
@@ -108,19 +103,13 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent {
* An element that can have a child top-level expression.
*/
class TopLevelExprParent extends Element, @top_level_expr_parent {
final override Expr getChild(int i) {
result = this.getChildExpr(i)
}
final override Expr getChild(int i) { result = this.getChildExpr(i) }
/** Gets the `i`th child expression of this element (zero-based). */
final Expr getChildExpr(int i) {
result = getTopLevelChild(this, i)
}
final Expr getChildExpr(int i) { result = getTopLevelChild(this, i) }
/** Gets a child expression of this element, if any. */
final Expr getAChildExpr() {
result = this.getChildExpr(_)
}
final Expr getAChildExpr() { result = this.getChildExpr(_) }
}
/**
@@ -159,8 +148,7 @@ class MultiImplementationsParent extends ExprOrStmtParent {
MultiImplementationsParent() {
exists(int i |
strictcount(File f |
exists(ControlFlowElement implementation, Location l |
f = l.getFile() |
exists(ControlFlowElement implementation, Location l | f = l.getFile() |
stmt_parent_top_level(implementation, i, this) and
stmt_location(implementation, l)
or
@@ -179,8 +167,7 @@ class MultiImplementationsParent extends ExprOrStmtParent {
* element.
*/
private File getAnImplementation(int i, ControlFlowElement cfe) {
exists(Location l |
result = l.getFile() |
exists(Location l | result = l.getFile() |
stmt_parent_top_level(cfe, i, this) and
stmt_location(cfe, l)
or
@@ -231,8 +218,9 @@ class MultiImplementationsParent extends ExprOrStmtParent {
File getBestFile() {
exists(ValueOrRefType t |
result = max(this.getAnImplementationFileInTopLevelType(_, t) as file
order by getImplementationSize(t, file), file.toString()
)
order by
getImplementationSize(t, file), file.toString()
)
)
}
@@ -242,8 +230,7 @@ class MultiImplementationsParent extends ExprOrStmtParent {
* be the actual run-time implementation.
*/
ControlFlowElement getBestChild(int i) {
exists(File f, ValueOrRefType t |
f = getBestFile() |
exists(File f, ValueOrRefType t | f = getBestFile() |
f = this.getAnImplementationInTopLevelType(i, result, t)
)
}
@@ -255,11 +242,9 @@ class MultiImplementationsParent extends ExprOrStmtParent {
* Holds if accessor `a` has an auto-implementation in file `f`.
*/
predicate hasAccessorAutoImplementation(Accessor a, File f) {
exists(SourceLocation sl |
sl = a.getALocation() |
exists(SourceLocation sl | sl = a.getALocation() |
f = sl.getFile() and
not exists(ControlFlowElement cfe, Location l |
sl.getFile() = l.getFile() |
not exists(ControlFlowElement cfe, Location l | sl.getFile() = l.getFile() |
stmt_parent_top_level(cfe, _, a) and
stmt_location(cfe, l)
or
@@ -293,15 +278,9 @@ private ValueOrRefType getDeclaringType(Declaration d) {
or
fields(d, _, _, result, _, _)
or
exists(DeclarationWithAccessors decl |
d = decl.getAnAccessor() |
result = getDeclaringType(decl)
)
exists(DeclarationWithAccessors decl | d = decl.getAnAccessor() | result = getDeclaringType(decl))
or
exists(Parameterizable p |
params(d, _, _, _, _, p, _) |
result = getDeclaringType(p)
)
exists(Parameterizable p | params(d, _, _, _, _, p, _) | result = getDeclaringType(p))
}
private ControlFlowElement getAChild(ControlFlowElement cfe) {
@@ -311,42 +290,45 @@ private ControlFlowElement getAChild(ControlFlowElement cfe) {
private int getImplementationSize0(ValueOrRefType t, File f) {
result = strictcount(ControlFlowElement cfe |
exists(MultiImplementationsParent p, ControlFlowElement child |
cfe = getAChild*(child) and
not cfe = getAChild*(any(ThrowElement te)) |
f = p.getAnImplementationInTopLevelType(_, child, t)
or
// Merge stats for partial implementations belonging to the same folder
t.isPartial() and
f = p.getAnImplementationInTopLevelType(_, _, t) and
exists(File fOther, MultiImplementationsParent pOther |
f.getParentContainer() = fOther.getParentContainer() |
fOther = pOther.getAnImplementationInTopLevelType(_, child, t)
exists(MultiImplementationsParent p, ControlFlowElement child |
cfe = getAChild*(child) and
not cfe = getAChild*(any(ThrowElement te))
|
f = p.getAnImplementationInTopLevelType(_, child, t)
or
// Merge stats for partial implementations belonging to the same folder
t.isPartial() and
f = p.getAnImplementationInTopLevelType(_, _, t) and
exists(File fOther, MultiImplementationsParent pOther |
f.getParentContainer() = fOther.getParentContainer()
|
fOther = pOther.getAnImplementationInTopLevelType(_, child, t)
)
)
)
)
}
private int getImplementationSize1(ValueOrRefType t, File f) {
result = strictsum(MultiImplementationsParent p, int c |
// Count each auto-implemented accessor as size 4 (getter) or 5 (setter)
f = p.getAnAutoImplementationFileInTopLevelType(t) and
if p instanceof Getter then c = 4 else c = 5 |
c
)
// Count each auto-implemented accessor as size 4 (getter) or 5 (setter)
f = p.getAnAutoImplementationFileInTopLevelType(t) and
if p instanceof Getter then c = 4 else c = 5
|
c
)
}
private int getImplementationSize(ValueOrRefType t, File f) {
if exists(getImplementationSize0(t, f)) then
if exists(getImplementationSize1(t, f)) then
result = getImplementationSize0(t, f) + getImplementationSize1(t, f)
else
result = getImplementationSize0(t, f)
else
result = getImplementationSize1(t, f)
if exists(getImplementationSize0(t, f))
then
if exists(getImplementationSize1(t, f))
then result = getImplementationSize0(t, f) + getImplementationSize1(t, f)
else result = getImplementationSize0(t, f)
else result = getImplementationSize1(t, f)
}
cached module ExprOrStmtParentCached {
cached
module ExprOrStmtParentCached {
cached
ControlFlowElement getTopLevelChild(ExprOrStmtParent p, int i) {
result = p.(MultiImplementationsParent).getBestChild(i)
@@ -366,7 +348,8 @@ cached module ExprOrStmtParentCached {
predicate mustHaveLocationInFile(Declaration d, File f) {
exists(MultiImplementationsParent p, ValueOrRefType t |
t = getTopLevelDeclaringType(p) and
f = p.getBestFile() |
f = p.getBestFile()
|
t = getTopLevelDeclaringType(d) or d = t or d = p
)
}
@@ -385,17 +368,13 @@ cached module ExprOrStmtParentCached {
result = e.getALocation().(SourceLocation) and
(mustHaveLocationInFile(e, _) implies mustHaveLocationInFile(e, result.getFile()))
or
(
hasNoSourceLocation(e)
and
result = min(Location l | l = e.getALocation() | l order by l.getFile().toString())
)
hasNoSourceLocation(e) and
result = min(Location l | l = e.getALocation() | l order by l.getFile().toString())
}
cached
string getURL(Element e) {
exists(Location l, string path, int a, int b, int c, int d |
l = bestLocation(e) |
exists(Location l, string path, int a, int b, int c, int d | l = bestLocation(e) |
l.hasLocationInfo(path, a, b, c, d) and
toUrl(path, a, b, c, d, result)
)

View File

@@ -46,8 +46,9 @@ class Container extends @container {
* if the root folder is not a reflexive, transitive parent of this container.
*/
string getRelativePath() {
exists (string absPath, string pref |
absPath = getAbsolutePath() and sourceLocationPrefix(pref) |
exists(string absPath, string pref |
absPath = getAbsolutePath() and sourceLocationPrefix(pref)
|
absPath = pref and result = ""
or
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
@@ -99,9 +100,7 @@ class Container extends @container {
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
* </table>
*/
string getExtension() {
result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
}
string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) }
/**
* Gets the stem of this container, that is, the prefix of its base name up to
@@ -120,24 +119,16 @@ class Container extends @container {
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
* </table>
*/
string getStem() {
result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
}
string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) }
/** Gets the parent container of this file or folder, if any. */
Container getParentContainer() {
containerparent(result, this)
}
Container getParentContainer() { containerparent(result, this) }
/** Gets a file or sub-folder in this container. */
Container getAChildContainer() {
this = result.getParentContainer()
}
Container getAChildContainer() { this = result.getParentContainer() }
/** Gets a file in this container. */
File getAFile() {
result = getAChildContainer()
}
File getAFile() { result = getAChildContainer() }
/** Gets the file in this container that has the given `baseName`, if any. */
File getFile(string baseName) {
@@ -146,9 +137,7 @@ class Container extends @container {
}
/** Gets a sub-folder in this container. */
Folder getAFolder() {
result = getAChildContainer()
}
Folder getAFolder() { result = getAChildContainer() }
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
Folder getFolder(string baseName) {
@@ -170,60 +159,40 @@ class Container extends @container {
}
/** Gets a sub-folder contained in this container. */
Folder getASubFolder() {
result = getAChildContainer()
}
Folder getASubFolder() { result = getAChildContainer() }
/**
* Gets a textual representation of the path of this container.
*
* This is the absolute path of the container.
*/
string toString() {
result = getAbsolutePath()
}
string toString() { result = getAbsolutePath() }
}
/** A folder. */
class Folder extends Container, @folder {
override string getAbsolutePath() {
folders(this, result, _)
}
override string getAbsolutePath() { folders(this, result, _) }
override string getURL() {
result = "folder://" + getAbsolutePath()
}
override string getURL() { result = "folder://" + getAbsolutePath() }
}
/** A file. */
class File extends Container, @file {
override string getAbsolutePath() {
files(this, result, _, _, _)
}
override string getAbsolutePath() { files(this, result, _, _, _) }
/** Gets the number of lines in this file. */
int getNumberOfLines() {
numlines(this, result, _, _)
}
int getNumberOfLines() { numlines(this, result, _, _) }
/** Gets the number of lines containing code in this file. */
int getNumberOfLinesOfCode() {
numlines(this, _, result, _)
}
int getNumberOfLinesOfCode() { numlines(this, _, result, _) }
/** Gets the number of lines containing comments in this file. */
int getNumberOfLinesOfComments() {
numlines(this, _, _, result)
}
int getNumberOfLinesOfComments() { numlines(this, _, _, result) }
override string getURL() {
result = "file://" + this.getAbsolutePath() + ":0:0:0:0"
}
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
/** Holds if this file contains source code. */
predicate fromSource() {
this.getNumberOfLinesOfCode() > 0
}
predicate fromSource() { this.getNumberOfLinesOfCode() > 0 }
/** Holds if this file is a library. */
predicate fromLibrary() {
@@ -236,20 +205,15 @@ class File extends Container, @file {
* A source file can come from a PDB and from regular extraction
* in the same snapshot.
*/
predicate isPdbSourceFile() {
file_extraction_mode(this, 2)
}
predicate isPdbSourceFile() { file_extraction_mode(this, 2) }
}
/**
* A source file.
*/
class SourceFile extends File {
SourceFile() { this.fromSource() }
/** Holds if the file was extracted without building the source code. */
predicate extractedStandalone() {
file_extraction_mode(this, 1)
}
predicate extractedStandalone() { file_extraction_mode(this, 1) }
}

View File

@@ -37,13 +37,9 @@ class Generic extends DotNet::Generic, Declaration, @generic {
class UnboundGeneric extends DotNet::UnboundGeneric, Generic {
UnboundGeneric() { is_generic(this) }
override TypeParameter getTypeParameter(int n) {
type_parameters(result, n, this, _)
}
override TypeParameter getTypeParameter(int n) { type_parameters(result, n, this, _) }
override ConstructedGeneric getAConstructedGeneric() {
result.getUnboundGeneric() = this
}
override ConstructedGeneric getAConstructedGeneric() { result.getUnboundGeneric() = this }
override TypeParameter getATypeParameter() {
result = DotNet::UnboundGeneric.super.getATypeParameter()
@@ -59,24 +55,20 @@ class UnboundGeneric extends DotNet::UnboundGeneric, Generic {
class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic {
ConstructedGeneric() { is_constructed(this) }
override UnboundGeneric getUnboundGeneric() {
constructed_generic(this, result)
}
override UnboundGeneric getUnboundGeneric() { constructed_generic(this, result) }
override UnboundGeneric getSourceDeclaration() {
result = getUnboundGeneric().getSourceDeclaration()
}
override int getNumberOfTypeArguments() {
// getTypeArgument() could fail if the type does not exist in the database
result = count(int i | type_arguments(_, i, this))
// getTypeArgument() could fail if the type does not exist in the database
result = count(int i | type_arguments(_, i, this))
}
override Type getTypeArgument(int i) { none() }
override Type getATypeArgument() {
result=getTypeArgument(_)
}
override Type getATypeArgument() { result = getTypeArgument(_) }
}
/**
@@ -105,13 +97,11 @@ class UnboundGenericType extends ValueOrRefType, UnboundGeneric {
* arguments being the corresponding type parameter.
*/
ConstructedType getInstanceType() {
result = this.getAConstructedGeneric()
and forall(TypeParameter tp, int i | tp = this.getTypeParameter(i) | tp = result.getTypeArgument(i))
result = this.getAConstructedGeneric() and
forall(TypeParameter tp, int i | tp = this.getTypeParameter(i) | tp = result.getTypeArgument(i))
}
override Location getALocation() {
type_location(this, result)
}
override Location getALocation() { type_location(this, result) }
/** Gets the name of this generic type without the `<...>` brackets. */
string getNameWithoutBrackets() {
@@ -134,17 +124,14 @@ class UnboundGenericType extends ValueOrRefType, UnboundGeneric {
*/
class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter {
/** Gets the constraints on this type parameter, if any. */
TypeParameterConstraints getConstraints() {
result.getTypeParameter() = this
}
TypeParameterConstraints getConstraints() { result.getTypeParameter() = this }
/**
* Holds if this type parameter is guaranteed to always be instantiated
* to a reference type.
*/
predicate isRefType() {
exists(TypeParameterConstraints tpc |
tpc = getConstraints() |
exists(TypeParameterConstraints tpc | tpc = getConstraints() |
tpc.hasRefTypeConstraint() or
exists(tpc.getClassConstraint()) or
tpc.getATypeParameterConstraint().isRefType()
@@ -157,50 +144,48 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter {
* to a value type.
*/
predicate isValueType() {
exists(TypeParameterConstraints tpc |
tpc = getConstraints() |
exists(TypeParameterConstraints tpc | tpc = getConstraints() |
tpc.hasValueTypeConstraint() or
tpc.getATypeParameterConstraint().isValueType()
)
}
/** Holds if this type parameter is contravariant. */
predicate isIn() {
type_parameters(this, _, _, 2)
}
predicate isIn() { type_parameters(this, _, _, 2) }
/** Holds if this type parameter is covariant. */
predicate isOut() {
type_parameters(this, _, _, 1)
}
predicate isOut() { type_parameters(this, _, _, 1) }
/** Gets a type that was supplied for this parameter. */
Type getASuppliedType()
{
/* A type parameter either comes from the source declaration
or from a partially constructed generic.
Type getASuppliedType() {
/*
* A type parameter either comes from the source declaration
* or from a partially constructed generic.
*
* When from a source declaration, return type arguments from all ConstructedGenerics,
* and when from a partially constructed UnboundGeneric, return type arguments from
* directly ConstructedGenerics.
*
* e.g.
*
* class A<T1> { class B<T2> { } }
*
* A<T1>.B<T2> is the UnboundGenericClass source declaration,
* A<int>.B<T2> is a partially constructed UnboundGenericClass and
* A<int>.B<int> is a ConstructedGenericClass.
*/
When from a source declaration, return type arguments from all ConstructedGenerics,
and when from a partially constructed UnboundGeneric, return type arguments from
directly ConstructedGenerics.
e.g.
class A<T1> { class B<T2> { } }
A<T1>.B<T2> is the UnboundGenericClass source declaration,
A<int>.B<T2> is a partially constructed UnboundGenericClass and
A<int>.B<int> is a ConstructedGenericClass.
*/
exists(ConstructedGeneric c, UnboundGeneric u, int tpi |
this = u.getTypeParameter(tpi) and
(u = c.getUnboundGeneric() or u = c.getSourceDeclaration()) and
result = c.getTypeArgument(tpi) )
result = c.getTypeArgument(tpi)
)
}
/** Gets a non-type-parameter type that was transitively supplied for this parameter. */
Type getAnUltimatelySuppliedType() {
result = getASuppliedType() and not result instanceof TypeParameter or
result = getASuppliedType() and not result instanceof TypeParameter
or
result = getASuppliedType().(TypeParameter).getAnUltimatelySuppliedType()
}
@@ -222,7 +207,6 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter {
* ```
*/
class TypeParameterConstraints extends Element, @type_parameter_constraints {
/** Gets a specific interface constraint (if any). */
Interface getAnInterfaceConstraint() {
specific_type_parameter_constraints(this, getTypeRef(result))
@@ -234,38 +218,24 @@ class TypeParameterConstraints extends Element, @type_parameter_constraints {
}
/** Gets the specific class constraint (if any). */
Class getClassConstraint() {
specific_type_parameter_constraints(this, getTypeRef(result))
}
Class getClassConstraint() { specific_type_parameter_constraints(this, getTypeRef(result)) }
override Location getALocation() {
type_parameter_constraints_location(this, result)
}
override Location getALocation() { type_parameter_constraints_location(this, result) }
/** Gets the type parameter to which these constraints apply. */
TypeParameter getTypeParameter() {
type_parameter_constraints(this, result)
}
TypeParameter getTypeParameter() { type_parameter_constraints(this, result) }
/** Holds if these constraints include a constructor constraint. */
predicate hasConstructorConstraint() {
general_type_parameter_constraints(this, 3)
}
predicate hasConstructorConstraint() { general_type_parameter_constraints(this, 3) }
/** Holds if these constraints include a general reference type constraint. */
predicate hasRefTypeConstraint() {
general_type_parameter_constraints(this, 1)
}
predicate hasRefTypeConstraint() { general_type_parameter_constraints(this, 1) }
/** Holds if these constraints include a general value type constraint. */
predicate hasValueTypeConstraint() {
general_type_parameter_constraints(this, 2)
}
predicate hasValueTypeConstraint() { general_type_parameter_constraints(this, 2) }
/** Gets a textual representation of these constraints. */
override string toString() {
result = "where " + this.getTypeParameter().toString() + ": ..."
}
override string toString() { result = "where " + this.getTypeParameter().toString() + ": ..." }
}
/**
@@ -364,7 +334,8 @@ class UnboundGenericDelegateType extends DelegateType, UnboundGenericType {
}
override string toStringWithTypes() {
result = getNameWithoutBrackets() + "<" + this.typeParametersToString() + ">(" + parameterTypesToString() + ")"
result = getNameWithoutBrackets() + "<" + this.typeParametersToString() + ">(" +
parameterTypesToString() + ")"
}
}
@@ -384,17 +355,11 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric {
result = ConstructedGeneric.super.getSourceDeclaration()
}
override Location getALocation() {
result = this.getSourceDeclaration().getALocation()
}
override Location getALocation() { result = this.getSourceDeclaration().getALocation() }
override Type getTypeArgument(int n) {
type_arguments(getTypeRef(result), n, getTypeRef(this))
}
override Type getTypeArgument(int n) { type_arguments(getTypeRef(result), n, getTypeRef(this)) }
override UnboundGenericType getUnboundGeneric() {
constructed_generic(this, getTypeRef(result))
}
override UnboundGenericType getUnboundGeneric() { constructed_generic(this, getTypeRef(result)) }
override string toStringWithTypes() {
result = getUnboundGeneric().getNameWithoutBrackets() + "<" + this.typeArgumentsToString() + ">"
@@ -516,7 +481,8 @@ class UnboundGenericMethod extends Method, UnboundGeneric {
}
override string toStringWithTypes() {
result = getName() + "<" + this.typeParametersToString() + ">" + "(" + parameterTypesToString() + ")"
result = getName() + "<" + this.typeParametersToString() + ">" + "(" + parameterTypesToString() +
")"
}
}
@@ -539,20 +505,15 @@ class UnboundGenericMethod extends Method, UnboundGeneric {
* corresponds to `UnboundGenericType`.
*/
class ConstructedMethod extends Method, ConstructedGeneric {
override Location getALocation() {
result = this.getSourceDeclaration().getALocation()
}
override Location getALocation() { result = this.getSourceDeclaration().getALocation() }
override Type getTypeArgument(int n) {
type_arguments(getTypeRef(result), n, this)
}
override Type getTypeArgument(int n) { type_arguments(getTypeRef(result), n, this) }
override UnboundGenericMethod getUnboundGeneric() {
constructed_generic(this, result)
}
override UnboundGenericMethod getUnboundGeneric() { constructed_generic(this, result) }
override string toStringWithTypes() {
result = getName() + "<" + this.typeArgumentsToString() + ">" + "(" + parameterTypesToString() + ")"
result = getName() + "<" + this.typeArgumentsToString() + ">" + "(" + parameterTypesToString() +
")"
}
override UnboundGenericMethod getSourceDeclaration() {
@@ -571,8 +532,7 @@ class ConstructedMethod extends Method, ConstructedGeneric {
* }
* ```
*/
class UnboundLocalFunction extends LocalFunction, UnboundGeneric
{
class UnboundLocalFunction extends LocalFunction, UnboundGeneric {
override ConstructedLocalFunction getAConstructedGeneric() {
result = UnboundGeneric.super.getAConstructedGeneric()
}
@@ -591,10 +551,9 @@ class UnboundLocalFunction extends LocalFunction, UnboundGeneric
* }
* ```
*/
class ConstructedLocalFunction extends LocalFunction, ConstructedGeneric
{
class ConstructedLocalFunction extends LocalFunction, ConstructedGeneric {
override UnboundLocalFunction getSourceDeclaration() {
result=LocalFunction.super.getSourceDeclaration()
result = LocalFunction.super.getSourceDeclaration()
}
override UnboundLocalFunction getUnboundGeneric() {
@@ -607,9 +566,7 @@ class ConstructedLocalFunction extends LocalFunction, ConstructedGeneric
* not a generic method or an unbound generic method (`UnboundGenericMethod`).
*/
class NonConstructedMethod extends Method {
NonConstructedMethod() {
not this instanceof ConstructedMethod
}
NonConstructedMethod() { not this instanceof ConstructedMethod }
/**
* Gets a method that either equals this non-constructed method, or

View File

@@ -6,6 +6,7 @@
* Do not use the predicates in this library directly; use the methods
* of the class `Virtualizable` instead.
*/
import csharp
private import Conversion
private import dispatch.Dispatch
@@ -76,7 +77,8 @@ private Virtualizable getAnImplementedInterfaceMemberForSubType(Virtualizable m,
)
}
pragma [noinline] // predicate folding for proper join order
// predicate folding for proper join order
pragma[noinline]
private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Virtualizable m) {
m = getACompatibleInterfaceMember(t.getAMember())
}
@@ -121,15 +123,16 @@ private DeclarationWithAccessors getACompatibleInterfaceAccessor(DeclarationWith
}
private DeclarationWithAccessors getACompatibleInterfaceAccessorCandidate(DeclarationWithAccessors d) {
getACompatibleInterfaceAccessorAux(result, d.getDeclaringType(), d.getName())
and
not d instanceof Indexer
and
getACompatibleInterfaceAccessorAux(result, d.getDeclaringType(), d.getName()) and
not d instanceof Indexer and
d.isPublic()
}
pragma [noinline] // predicate folding for proper join-order
private predicate getACompatibleInterfaceAccessorAux(DeclarationWithAccessors d, ValueOrRefType t, string name) {
// predicate folding for proper join-order
pragma[noinline]
private predicate getACompatibleInterfaceAccessorAux(
DeclarationWithAccessors d, ValueOrRefType t, string name
) {
t = getAPossibleImplementor(d.getDeclaringType()) and
name = d.getName()
}
@@ -155,8 +158,7 @@ private predicate getACompatibleInterfaceAccessorAux(DeclarationWithAccessors d,
*/
pragma[nomagic]
ValueOrRefType getAPossibleImplementor(Interface i) {
result.getASubType*().getABaseInterface+() = i
and
result.getASubType*().getABaseInterface+() = i and
not result instanceof Interface
}
@@ -166,36 +168,33 @@ ValueOrRefType getAPossibleImplementor(Interface i) {
* the interface indexer is accessed.
*/
private Indexer getACompatibleInterfaceIndexer(Indexer i) {
result = getACompatibleInterfaceIndexerCandidate(i)
and
convIdentity(i.getType(), result.getType())
and
forex(int j |
j in [0 .. i.getNumberOfParameters() - 1] |
result = getACompatibleInterfaceIndexerCandidate(i) and
convIdentity(i.getType(), result.getType()) and
forex(int j | j in [0 .. i.getNumberOfParameters() - 1] |
convIdentity(i.getParameter(j).getType(), result.getParameter(j).getType())
)
}
private Indexer getACompatibleInterfaceIndexerCandidate(Indexer i) {
getACompatibleInterfaceIndexerAux(result, i.getDeclaringType())
and
getACompatibleInterfaceIndexerAux(result, i.getDeclaringType()) and
i.isPublic()
}
pragma [noinline] // predicate folding for proper join-order
// predicate folding for proper join-order
pragma[noinline]
private predicate getACompatibleInterfaceIndexerAux(Indexer i, ValueOrRefType t) {
t = getAPossibleImplementor(i.getDeclaringType())
}
private Method getACompatibleInterfaceMethod(Method m) {
result = getAnInterfaceMethodCandidate(m)
and
forex(int i |
i in [0 .. m.getNumberOfParameters()] |
result = getAnInterfaceMethodCandidate(m) and
forex(int i | i in [0 .. m.getNumberOfParameters()] |
exists(Type t1, Type t2 |
t1 = getArgumentOrReturnType(m, i) and
t2 = getArgumentOrReturnType(result, i) |
convIdentity(t1, t2) or
t2 = getArgumentOrReturnType(result, i)
|
convIdentity(t1, t2)
or
// In the case where both `m` and `result` are unbound generic methods,
// we need to do check for structural equality modulo the method type
// parameters
@@ -211,13 +210,16 @@ private Method getACompatibleInterfaceMethod(Method m) {
* in a type that is a possible implementor type for the interface type.
*/
private Method getAnInterfaceMethodCandidate(Method m) {
getAPotentialInterfaceMethodAux(result, m.getDeclaringType(), m.getName(), m.getNumberOfParameters())
and
getAPotentialInterfaceMethodAux(result, m.getDeclaringType(), m.getName(),
m.getNumberOfParameters()) and
m.isPublic()
}
pragma [nomagic] // predicate folding for proper join-order
private predicate getAPotentialInterfaceMethodAux(Method m, ValueOrRefType t, string name, int params) {
// predicate folding for proper join-order
pragma[nomagic]
private predicate getAPotentialInterfaceMethodAux(
Method m, ValueOrRefType t, string name, int params
) {
t = getAPossibleImplementor(m.getDeclaringType()) and
name = m.getName() and
params = m.getNumberOfParameters()
@@ -239,37 +241,37 @@ private Type getArgumentOrReturnType(Method m, int i) {
* Here, compatibility means that the two types are structurally equal
* modulo identity conversions and method type parameters.
*/
private predicate structurallyCompatible(UnboundGenericMethod m1, UnboundGenericMethod m2, Type t1, Type t2) {
private predicate structurallyCompatible(
UnboundGenericMethod m1, UnboundGenericMethod m2, Type t1, Type t2
) {
candidateTypes(m1, m2, t1, t2) and
(
// Base case: identity convertible
convIdentity(t1, t2)
or
// Base case: method type parameter (at same index)
exists(int i |
structurallyCompatibleTypeParameter(m1, m2, i, t1, m2.getTypeParameter(i))
)
exists(int i | structurallyCompatibleTypeParameter(m1, m2, i, t1, m2.getTypeParameter(i)))
or
// Recursive case
(
(
t1 instanceof PointerType and t2 instanceof PointerType
or
t1 instanceof NullableType and t2 instanceof NullableType
or
t1.(ArrayType).hasSameShapeAs((ArrayType)t2)
or
t1.(ConstructedType).getUnboundGeneric() = t2.(ConstructedType).getUnboundGeneric()
)
and
structurallyCompatibleChildren(m1, m2, t1, t2, t1.getNumberOfChildren() - 1)
)
t1 instanceof PointerType and t2 instanceof PointerType
or
t1 instanceof NullableType and t2 instanceof NullableType
or
t1.(ArrayType).hasSameShapeAs(t2.(ArrayType))
or
t1.(ConstructedType).getUnboundGeneric() = t2.(ConstructedType).getUnboundGeneric()
) and
structurallyCompatibleChildren(m1, m2, t1, t2, t1.getNumberOfChildren() - 1)
)
}
// Predicate folding to force joining on `candidateTypes` first
pragma [nomagic] // to prevent `private#structurallyCompatibleTypeParameter#fbbfb`
private predicate structurallyCompatibleTypeParameter(UnboundGenericMethod m1, UnboundGenericMethod m2, int i, Type t1, Type t2) {
// to prevent `private#structurallyCompatibleTypeParameter#fbbfb`
pragma[nomagic]
private predicate structurallyCompatibleTypeParameter(
UnboundGenericMethod m1, UnboundGenericMethod m2, int i, Type t1, Type t2
) {
candidateTypes(m1, m2, t1, t2) and
t1 = m1.getTypeParameter(i)
}
@@ -277,7 +279,9 @@ private predicate structurallyCompatibleTypeParameter(UnboundGenericMethod m1, U
/**
* Holds if the `i+1` first children of types `x` and `y` are compatible.
*/
private predicate structurallyCompatibleChildren(UnboundGenericMethod m1, UnboundGenericMethod m2, Type t1, Type t2, int i) {
private predicate structurallyCompatibleChildren(
UnboundGenericMethod m1, UnboundGenericMethod m2, Type t1, Type t2, int i
) {
exists(Type t3, Type t4 |
i = 0 and
candidateChildren(t1, t2, i, t3, t4) and
@@ -293,8 +297,7 @@ private predicate structurallyCompatibleChildren(UnboundGenericMethod m1, Unboun
// manual magic predicate used to enumerate types relevant for structural comparison
private predicate candidateTypes(UnboundGenericMethod m1, UnboundGenericMethod m2, Type t1, Type t2) {
m2 = getAnInterfaceMethodCandidate(m1)
and
m2 = getAnInterfaceMethodCandidate(m1) and
(
exists(int i |
t1 = getArgumentOrReturnType(m1, i) and
@@ -309,7 +312,8 @@ private predicate candidateTypes(UnboundGenericMethod m1, UnboundGenericMethod m
)
}
pragma [noinline] // predicate folding for proper join-order
// predicate folding for proper join-order
pragma[noinline]
private predicate candidateChildren(Type t1, Type t2, int i, Type t3, Type t4) {
candidateTypes(_, _, t1, t2) and
t3 = t1.getChild(i) and

View File

@@ -18,9 +18,7 @@ private import Attribute
/**
* A location of a program element.
*/
class Location extends @location
{
class Location extends @location {
/** Gets the file of the location. */
File getFile() { none() }
@@ -31,7 +29,11 @@ class Location extends @location
* For more information, see
* [LGTM locations](https://lgtm.com/help/ql/locations).
*/
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) { none() }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets a textual representation of this location. */
string toString() { none() }
@@ -54,41 +56,40 @@ class Location extends @location
* within the file.
*/
class SourceLocation extends Location, @location_default {
override File getFile() { locations_default(this, result, _, _, _, _) }
override File getFile() {
locations_default(this,result,_,_,_,_)
}
override predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
exists(File f |
locations_default(this, f, startline, startcolumn, endline, endcolumn) |
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f | locations_default(this, f, startline, startcolumn, endline, endcolumn) |
filepath = f.getAbsolutePath()
)
}
override string toString() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) |
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
result = filepath + ":" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
)
}
}
bindingset[version]
private int versionField(string version, int field)
{
private int versionField(string version, int field) {
exists(string format |
format = "(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)" or
format = "(\\d+)\\.(\\d+)\\.(\\d+)" or
format = "(\\d+)\\.(\\d+)" |
result = version.regexpCapture(format, field).toInt())
and result >= 0
and result <= 255
format = "(\\d+)\\.(\\d+)"
|
result = version.regexpCapture(format, field).toInt()
) and
result >= 0 and
result <= 255
}
/** An assembly version, for example `4.0.0.0` or `4.5`. */
class Version extends string
{
class Version extends string {
bindingset[this]
Version() { exists(versionField(this, 1)) }
@@ -97,13 +98,9 @@ class Version extends string
* If the field is unspecified in the version string, then the result is `0`.
*/
bindingset[this]
int getField(int field)
{
field in [1..4]
and
if exists(versionField(this, field))
then result = versionField(this, field)
else result = 0
int getField(int field) {
field in [1 .. 4] and
if exists(versionField(this, field)) then result = versionField(this, field) else result = 0
}
/** Gets the major version, for example `1` in `1.2.3.4`. */
@@ -133,10 +130,9 @@ class Version extends string
* For example, `4.0.0.0` is earlier than `4.5`.
*/
bindingset[this, other]
predicate isEarlierThan(Version other)
{
predicate isEarlierThan(Version other) {
exists(int i | this.getField(i) < other.getField(i) |
forall(int j | j in [1..i-1] | this.getField(j) = other.getField(j))
forall(int j | j in [1 .. i - 1] | this.getField(j) = other.getField(j))
)
}
@@ -150,9 +146,7 @@ class Version extends string
int compareTo(Version other) {
if this.isEarlierThan(other)
then result = -1
else if other.isEarlierThan(this)
then result = 1
else result = 0
else if other.isEarlierThan(this) then result = 1 else result = 0
}
}
@@ -160,21 +154,22 @@ class Version extends string
* A .NET assembly location.
*/
class Assembly extends Location, Attributable, @assembly {
/** Gets the full name of this assembly, including its version and public token. */
string getFullName() { assemblies(this,_,result,_,_) }
string getFullName() { assemblies(this, _, result, _, _) }
/** Gets the name of this assembly. */
string getName() { assemblies(this,_,_,result,_) }
string getName() { assemblies(this, _, _, result, _) }
/** Gets the version of this assembly. */
Version getVersion() { assemblies(this,_,_,_,result) }
Version getVersion() { assemblies(this, _, _, _, result) }
override File getFile() { assemblies(this,result,_,_,_) }
override File getFile() { assemblies(this, result, _, _, _) }
override string toString() { result = this.getFullName() }
override predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f |
assemblies(this, f, _, _, _) and
filepath = f.getAbsolutePath() and

View File

@@ -16,7 +16,7 @@ class Declaration extends DotNet::Declaration, Element, @declaration {
override ValueOrRefType getDeclaringType() { none() }
/** Holds if this declaration is unconstructed and in source code. */
predicate isSourceDeclaration() { fromSource() and this=getSourceDeclaration() }
predicate isSourceDeclaration() { fromSource() and this = getSourceDeclaration() }
override string toString() { result = this.getName() }
@@ -40,9 +40,7 @@ class Declaration extends DotNet::Declaration, Element, @declaration {
* Holds if this declaration has been generated by the compiler, for example
* implicit constructors or accessors.
*/
predicate isCompilerGenerated() {
compiler_generated(this)
}
predicate isCompilerGenerated() { compiler_generated(this) }
}
/** A declaration that can have a modifier. */
@@ -140,29 +138,23 @@ class Virtualizable extends Member, @virtualizable {
* to members that can be declared on an interface, i.e. methods, properties,
* indexers and events.
*/
Interface getExplicitlyImplementedInterface() {
explicitly_implements(this, getTypeRef(result))
}
Interface getExplicitlyImplementedInterface() { explicitly_implements(this, getTypeRef(result)) }
/**
* Holds if this member implements an interface member explicitly.
*/
predicate implementsExplicitInterface() {
exists(getExplicitlyImplementedInterface())
}
predicate implementsExplicitInterface() { exists(getExplicitlyImplementedInterface()) }
/** Holds if this member can be overridden or implemented. */
predicate isOverridableOrImplementable() {
not isSealed()
and
not getDeclaringType().isSealed()
and
(
isVirtual() or
isOverride() or
isAbstract() or
getDeclaringType() instanceof Interface
)
not isSealed() and
not getDeclaringType().isSealed() and
(
isVirtual() or
isOverride() or
isAbstract() or
getDeclaringType() instanceof Interface
)
}
/** Gets the member that is immediately overridden by this member, if any. */
@@ -273,7 +265,8 @@ class Virtualizable extends Member, @virtualizable {
*/
Virtualizable getAnUltimateImplementee() {
exists(Virtualizable implementation, ValueOrRefType implementationType |
implements(implementation, result, implementationType) |
implements(implementation, result, implementationType)
|
this = implementation
or
getOverridee+() = implementation and
@@ -333,15 +326,14 @@ class Parameterizable extends Declaration, @parameterizable {
private string parameterTypeToString(int i) {
exists(Parameter p, string prefix |
p = getParameter(i) and
result = prefix + p.getType().toStringWithTypes() |
if p.isOut() then
prefix = "out "
else if p.isRef() then
prefix = "ref "
else if p.isParams() then
prefix = "params "
result = prefix + p.getType().toStringWithTypes()
|
if p.isOut()
then prefix = "out "
else
prefix = ""
if p.isRef()
then prefix = "ref "
else if p.isParams() then prefix = "params " else prefix = ""
)
}
@@ -349,11 +341,8 @@ class Parameterizable extends Declaration, @parameterizable {
* Gets the types of the parameters of this declaration as a
* comma-separated string.
*/
language [monotonicAggregates]
language[monotonicAggregates]
string parameterTypesToString() {
result = concat(int i |
exists(getParameter(i)) |
parameterTypeToString(i), ", " order by i asc
)
result = concat(int i | exists(getParameter(i)) | parameterTypeToString(i), ", " order by i)
}
}

View File

@@ -6,7 +6,6 @@ import Element
* A modifier, for example `static`, `virtual`, `public` and so on.
*/
class Modifier extends Element, @modifier {
/** Gets the name of this modifier, for example `public`. */
string getName() { modifiers(this, result) }

View File

@@ -106,7 +106,8 @@ class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
DelegateType getADelegate() { result = this.getATypeDeclaration() }
override predicate fromSource() {
exists(ValueOrRefType t | t.getNamespace() = this and t.fromSource()) or
exists(ValueOrRefType t | t.getNamespace() = this and t.fromSource())
or
exists(Namespace n | n.getParentNamespace() = this and n.fromSource())
}
@@ -115,18 +116,13 @@ class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
/** Gets a declaration of this namespace, if any. */
NamespaceDeclaration getADeclaration() { result.getNamespace() = this }
override Location getALocation() {
result = this.getADeclaration().getALocation()
}
override Location getALocation() { result = this.getADeclaration().getALocation() }
}
/**
* The global namespace. This is the root of all namespaces.
*/
class GlobalNamespace extends Namespace {
GlobalNamespace() { this.hasName("") }
}
class GlobalNamespace extends Namespace { GlobalNamespace() { this.hasName("") } }
/**
* An explicit namespace declaration in a source file. For example:
@@ -138,7 +134,6 @@ class GlobalNamespace extends Namespace {
* ```
*/
class NamespaceDeclaration extends Element, @namespace_declaration {
/**
* Gets the declared namespace, for example `N1.N2` in
*
@@ -148,7 +143,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration {
* }
* ```
*/
Namespace getNamespace() { namespace_declarations(this,result) }
Namespace getNamespace() { namespace_declarations(this, result) }
/**
* Gets the parent namespace declaration, if any. In the following example,
@@ -168,7 +163,9 @@ class NamespaceDeclaration extends Element, @namespace_declaration {
* }
* ```
*/
NamespaceDeclaration getParentNamespaceDeclaration() { parent_namespace_declaration(this,result) }
NamespaceDeclaration getParentNamespaceDeclaration() {
parent_namespace_declaration(this, result)
}
/**
* Gets a child namespace declaration, if any. In the following example,
@@ -182,8 +179,10 @@ class NamespaceDeclaration extends Element, @namespace_declaration {
* }
* }
* ```
*/
NamespaceDeclaration getAChildNamespaceDeclaration() { parent_namespace_declaration(result,this) }
*/
NamespaceDeclaration getAChildNamespaceDeclaration() {
parent_namespace_declaration(result, this)
}
/**
* Gets a type directly declared within this namespace declaration.

View File

@@ -12,15 +12,12 @@ private import dotnet
* A declaration that may have accessors. Either an event (`Event`), a property
* (`Property`), or an indexer (`Indexer`).
*/
class DeclarationWithAccessors extends AssignableMember, Virtualizable, Attributable, @declaration_with_accessors {
class DeclarationWithAccessors extends AssignableMember, Virtualizable, Attributable,
@declaration_with_accessors {
/** Gets an accessor of this declaration. */
Accessor getAnAccessor() {
result.getDeclaration() = this
}
Accessor getAnAccessor() { result.getDeclaration() = this }
override DeclarationWithAccessors getOverridee() {
result = Virtualizable.super.getOverridee()
}
override DeclarationWithAccessors getOverridee() { result = Virtualizable.super.getOverridee() }
override DeclarationWithAccessors getAnOverrider() {
result = Virtualizable.super.getAnOverrider()
@@ -53,7 +50,8 @@ class DeclarationWithAccessors extends AssignableMember, Virtualizable, Attribut
* A declaration that may have a `get` accessor and a `set` accessor. Either a
* property (`Property`) or an indexer (`Indexer`).
*/
class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelExprParent, @assignable_with_accessors {
class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelExprParent,
@assignable_with_accessors {
/** Gets the `get` accessor of this declaration, if any. */
Getter getGetter() { result = getAnAccessor() }
@@ -103,9 +101,7 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE
}
/** Gets the expression body of this declaration, if any. */
Expr getExpressionBody() {
result = this.getChildExpr(0)
}
Expr getExpressionBody() { result = this.getChildExpr(0) }
}
/**
@@ -118,17 +114,11 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE
* ```
*/
class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @property {
override string getName() {
properties(this, result, _, _, _)
}
override string getName() { properties(this, result, _, _, _) }
override ValueOrRefType getDeclaringType() {
properties(this, _, result, _, _)
}
override ValueOrRefType getDeclaringType() { properties(this, _, result, _, _) }
override Type getType() {
properties(this, _, _, getTypeRef(result), _)
}
override Type getType() { properties(this, _, _, getTypeRef(result), _) }
/**
* Holds if this property is automatically implemented. For example, `P1`
@@ -157,13 +147,9 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
not this.getAnAccessor().hasBody()
}
override Property getSourceDeclaration() {
properties(this, _, _, _, result)
}
override Property getSourceDeclaration() { properties(this, _, _, _, result) }
override Property getOverridee() {
result = DeclarationWithGetSetAccessors.super.getOverridee()
}
override Property getOverridee() { result = DeclarationWithGetSetAccessors.super.getOverridee() }
override Property getAnOverrider() {
result = DeclarationWithGetSetAccessors.super.getAnOverrider()
@@ -185,13 +171,9 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
result = DeclarationWithGetSetAccessors.super.getAnUltimateImplementor()
}
override PropertyAccess getAnAccess() {
result.getTarget() = this
}
override PropertyAccess getAnAccess() { result.getTarget() = this }
override Location getALocation() {
property_location(this, result)
}
override Location getALocation() { property_location(this, result) }
override Expr getAnAssignedValue() {
result = DeclarationWithGetSetAccessors.super.getAnAssignedValue()
@@ -200,13 +182,15 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
* For library types, we don't know about assignments in constructors. We instead assume that
* arguments passed to parameters of constructors with suitable names.
*/
getDeclaringType().fromLibrary() and
exists(Parameter param, Constructor c, string propertyName |
propertyName = getName() and
c = getDeclaringType().getAConstructor() and
param = c.getAParameter() and
// Find a constructor parameter with the same name, but with a lower case initial letter.
param.hasName(propertyName.charAt(0).toLowerCase() + propertyName.suffix(1)) |
param.hasName(propertyName.charAt(0).toLowerCase() + propertyName.suffix(1))
|
result = param.getAnAssignedArgument()
)
}
@@ -238,6 +222,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
}
override Getter getGetter() { result = DeclarationWithGetSetAccessors.super.getGetter() }
override Setter getSetter() { result = DeclarationWithGetSetAccessors.super.getSetter() }
}
@@ -253,26 +238,16 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
* ```
*/
class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer {
override string getName() {
indexers(this, result, _, _, _)
}
override string getName() { indexers(this, result, _, _, _) }
/** Gets the dimension of this indexer, that is, its number of parameters. */
int getDimension() {
result = getNumberOfParameters()
}
int getDimension() { result = getNumberOfParameters() }
override ValueOrRefType getDeclaringType() {
indexers(this, _, result, _, _)
}
override ValueOrRefType getDeclaringType() { indexers(this, _, result, _, _) }
override Type getType() {
indexers(this, _, _, getTypeRef(result), _)
}
override Type getType() { indexers(this, _, _, getTypeRef(result), _) }
override IndexerAccess getAnAccess() {
result.getTarget() = this
}
override IndexerAccess getAnAccess() { result.getTarget() = this }
/**
* Gets the expression body of this indexer, if any. For example, the
@@ -288,13 +263,9 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer
result = DeclarationWithGetSetAccessors.super.getExpressionBody()
}
override Indexer getSourceDeclaration() {
indexers(this, _, _, _, result)
}
override Indexer getSourceDeclaration() { indexers(this, _, _, _, result) }
override Indexer getOverridee() {
result = DeclarationWithGetSetAccessors.super.getOverridee()
}
override Indexer getOverridee() { result = DeclarationWithGetSetAccessors.super.getOverridee() }
override Indexer getAnOverrider() {
result = DeclarationWithGetSetAccessors.super.getAnOverrider()
@@ -316,13 +287,9 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer
result = DeclarationWithGetSetAccessors.super.getAnUltimateImplementor()
}
override Location getALocation() {
indexer_location(this, result)
}
override Location getALocation() { indexer_location(this, result) }
override string toStringWithTypes() {
result = getName() + "[" + parameterTypesToString() + "]"
}
override string toStringWithTypes() { result = getName() + "[" + parameterTypesToString() + "]" }
}
/**
@@ -330,14 +297,10 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer
* accessor (`EventAccessor`).
*/
class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
override ValueOrRefType getDeclaringType() {
result = this.getDeclaration().getDeclaringType()
}
override ValueOrRefType getDeclaringType() { result = this.getDeclaration().getDeclaringType() }
/** Gets the assembly name of this accessor. */
string getAssemblyName() {
accessors(this, _, result, _, _)
}
string getAssemblyName() { accessors(this, _, result, _, _) }
/**
* Gets the declaration that this accessor belongs to. For example, both
@@ -352,9 +315,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
* }
* ```
*/
DeclarationWithAccessors getDeclaration() {
accessors(this, _ , _, result, _)
}
DeclarationWithAccessors getDeclaration() { accessors(this, _, _, result, _) }
/**
* Gets an explicit access modifier of this accessor, if any. For example,
@@ -370,9 +331,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
* }
* ```
*/
AccessModifier getAnAccessModifier() {
result = Modifiable.super.getAModifier()
}
AccessModifier getAnAccessModifier() { result = Modifiable.super.getAModifier() }
/**
* Gets a modifier of this accessor, if any.
@@ -398,17 +357,11 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
not (result instanceof AccessModifier and exists(getAnAccessModifier()))
}
override Accessor getSourceDeclaration() {
accessors(this, _, _, _, result)
}
override Accessor getSourceDeclaration() { accessors(this, _, _, _, result) }
override Location getALocation() {
accessor_location(this, result)
}
override Location getALocation() { accessor_location(this, result) }
override string toString() {
result = getName()
}
override string toString() { result = getName() }
override Location getLocation() { result = Callable.super.getLocation() }
}
@@ -427,13 +380,9 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
* ```
*/
class Getter extends Accessor, @getter {
override string getName() {
result = "get" + "_" + getDeclaration().getName()
}
override string getName() { result = "get" + "_" + getDeclaration().getName() }
override Type getReturnType() {
result = getDeclaration().getType()
}
override Type getReturnType() { result = getDeclaration().getType() }
/**
* Gets the field used in the trival implementation of this getter, if any.
@@ -476,9 +425,7 @@ class Getter extends Accessor, @getter {
* ```
*/
class Setter extends Accessor, @setter {
override string getName() {
result = "set" + "_" + getDeclaration().getName()
}
override string getName() { result = "set" + "_" + getDeclaration().getName() }
override Type getReturnType() {
exists(this) and // needed to avoid compiler warning
@@ -516,8 +463,7 @@ class Setter extends Accessor, @setter {
/**
* Gets an access to the special `value` parameter available in setters.
*/
private
ParameterAccess accessToValue() {
private ParameterAccess accessToValue() {
result.getTarget().hasName("value") and
result.getEnclosingCallable() instanceof Setter
}
@@ -547,8 +493,7 @@ ParameterAccess accessToValue() {
* }
* ```
*/
class TrivialProperty extends Property
{
class TrivialProperty extends Property {
TrivialProperty() {
isAutoImplemented()
or
@@ -560,9 +505,7 @@ class TrivialProperty extends Property
* A `Property` which holds a type with an indexer.
*/
class IndexerProperty extends Property {
IndexerProperty() {
exists(getType().(RefType).getABaseType*().getAnIndexer())
}
IndexerProperty() { exists(getType().(RefType).getABaseType*().getAnIndexer()) }
/**
* Gets a call to the indexer of the type returned by this property, for a value returned by this
@@ -573,8 +516,7 @@ class IndexerProperty extends Property {
IndexerCall getAnIndexerCall() {
result = getType().(RefType).getAnIndexer().getAnAccessor().getACall() and
// The qualifier of this indexer call should be a value returned from an access of this property
exists(Expr qualifier |
qualifier = result.(IndexerAccess).getQualifier() |
exists(Expr qualifier | qualifier = result.(IndexerAccess).getQualifier() |
DataFlow::localFlow(DataFlow::exprNode(this.getAnAccess()), DataFlow::exprNode(qualifier))
)
}

View File

@@ -25,11 +25,8 @@ private import semmle.code.csharp.frameworks.System
* (`FixedStmt`).
*/
class Stmt extends ControlFlowElement, @stmt {
/** Gets the enclosing callable of this statement. */
override Callable getEnclosingCallable() {
enclosingCallable(this, result)
}
override Callable getEnclosingCallable() { enclosingCallable(this, result) }
override string toString() { result = "Statement" }
@@ -54,7 +51,6 @@ class Stmt extends ControlFlowElement, @stmt {
* ```
*/
class BlockStmt extends Stmt, @block_stmt {
/** Gets a statement in this block, if any. */
Stmt getAStmt() { result.getParent() = this }
@@ -74,10 +70,9 @@ class BlockStmt extends Stmt, @block_stmt {
predicate isEmpty() { not exists(this.getAStmt()) }
override Stmt stripSingletonBlocks() {
if getNumberOfStmts() = 1 then
result = getAChildStmt().stripSingletonBlocks()
else
result = this
if getNumberOfStmts() = 1
then result = getAChildStmt().stripSingletonBlocks()
else result = this
}
override string toString() { result = "{...}" }
@@ -97,7 +92,6 @@ class BlockStmt extends Stmt, @block_stmt {
* ```
*/
class ExprStmt extends Stmt, @expr_stmt {
/** Gets the expression in this expression statement. */
Expr getExpr() { result.getParent() = this }
@@ -110,7 +104,6 @@ class ExprStmt extends Stmt, @expr_stmt {
* Either an `if` statement (`IfStmt`) or a `switch` statement (`SwitchStmt`).
*/
class SelectionStmt extends Stmt, @cond_stmt {
/** Gets the condition of this selection statement. */
Expr getCondition() { none() }
}
@@ -129,7 +122,6 @@ class SelectionStmt extends Stmt, @cond_stmt {
* The `else` part is optional.
*/
class IfStmt extends SelectionStmt, @if_stmt {
override Expr getCondition() { result = this.getChild(0) }
/** Gets the `then` (true) branch of this `if` statement. */
@@ -151,7 +143,6 @@ class IfStmt extends SelectionStmt, @if_stmt {
* ```
*/
class SwitchStmt extends SelectionStmt, @switch_stmt {
override Expr getCondition() { result = this.getChild(0) }
/**
@@ -217,16 +208,14 @@ class SwitchStmt extends SelectionStmt, @switch_stmt {
Stmt getAStmt() { result = this.getStmt(_) }
}
private cached module SwithStmtInternal {
cached
private module SwithStmtInternal {
cached
CaseStmt getCase(SwitchStmt ss, int i) {
exists(int index, int rankIndex |
result = ss.getChildStmt(index) and
rankIndex = i + 1 and
index = rank[rankIndex](int j, CaseStmt cs |
cs = ss.getChildStmt(j) |
j
)
index = rank[rankIndex](int j, CaseStmt cs | cs = ss.getChildStmt(j) | j)
)
}
@@ -236,12 +225,13 @@ private cached module SwithStmtInternal {
result = ss.getChildStmt(index) and
rankIndex = i + 1 and
index = rank[rankIndex](int j, Stmt s |
// `getChild` includes both labeled statements and the targeted
// statements of labeled statement as separate children, but we
// only want the labeled statement
s = getLabeledStmt(ss, j) |
j
)
// `getChild` includes both labeled statements and the targeted
// statements of labeled statement as separate children, but we
// only want the labeled statement
s = getLabeledStmt(ss, j)
|
j
)
)
}
@@ -271,9 +261,7 @@ class CaseStmt extends Stmt, @case {
* }
* ```
*/
Expr getCondition() {
result = this.getChild(2)
}
Expr getCondition() { result = this.getChild(2) }
}
/**
@@ -318,9 +306,7 @@ class ConstCase extends LabeledStmt, CaseStmt {
* ```
*/
class TypeCase extends LabeledStmt, CaseStmt {
TypeCase() {
this.getChild(1) instanceof TypeAccess
}
TypeCase() { this.getChild(1) instanceof TypeAccess }
/**
* Gets the local variable declaration of this type case, if any. For example,
@@ -337,9 +323,7 @@ class TypeCase extends LabeledStmt, CaseStmt {
* }
* ```
*/
LocalVariableDeclExpr getVariableDeclExpr() {
result = getChild(0)
}
LocalVariableDeclExpr getVariableDeclExpr() { result = getChild(0) }
/**
* Gets the type access of this case, for example access to `string` or
@@ -354,9 +338,7 @@ class TypeCase extends LabeledStmt, CaseStmt {
* }
* ```
*/
TypeAccess getTypeAccess() {
result = getChild(1)
}
TypeAccess getTypeAccess() { result = getChild(1) }
/**
* Gets the type being checked by this case. For example, the type being checked
@@ -371,17 +353,14 @@ class TypeCase extends LabeledStmt, CaseStmt {
* }
* ```
*/
Type getCheckedType() {
result = getTypeAccess().getType()
}
Type getCheckedType() { result = getTypeAccess().getType() }
override string toString() {
exists(string var |
if exists(this.getVariableDeclExpr()) then
var = " " + this.getVariableDeclExpr().getName()
else
var = ""
|
if exists(this.getVariableDeclExpr())
then var = " " + this.getVariableDeclExpr().getName()
else var = ""
|
result = "case " + this.getTypeAccess().getType().getName() + var + ":"
)
}
@@ -399,7 +378,6 @@ class TypeCase extends LabeledStmt, CaseStmt {
* ```
*/
class DefaultCase extends CaseStmt {
DefaultCase() { not exists(Expr e | e.getParent() = this) }
override string toString() { result = "default:" }
@@ -413,7 +391,6 @@ class DefaultCase extends CaseStmt {
* (`ForeachStmt`).
*/
class LoopStmt extends Stmt, @loop_stmt {
/** Gets the body of this loop statement. */
Stmt getBody() { result.getParent() = this }
@@ -431,7 +408,6 @@ class LoopStmt extends Stmt, @loop_stmt {
* ```
*/
class WhileStmt extends LoopStmt, @while_stmt {
override Expr getCondition() { result.getParent() = this }
override string toString() { result = "while (...) ..." }
@@ -448,7 +424,6 @@ class WhileStmt extends LoopStmt, @while_stmt {
* ```
*/
class DoStmt extends LoopStmt, @do_stmt {
override Expr getCondition() { result.getParent() = this }
override string toString() { result = "do ... while (...);" }
@@ -464,7 +439,6 @@ class DoStmt extends LoopStmt, @do_stmt {
* ```
*/
class ForStmt extends LoopStmt, @for_stmt {
/**
* Gets an initializer expression of this `for` loop, if any.
*
@@ -490,7 +464,9 @@ class ForStmt extends LoopStmt, @for_stmt {
* }
* ```
*/
Expr getInitializer(int n) { exists(int i | result = this.getChild(i) and n = -1-i and i <= -1) }
Expr getInitializer(int n) {
exists(int i | result = this.getChild(i) and n = -1 - i and i <= -1)
}
override Expr getCondition() { result = this.getChild(0) }
@@ -518,7 +494,7 @@ class ForStmt extends LoopStmt, @for_stmt {
* }
* ```
*/
Expr getUpdate(int n) { exists(int i | result = this.getChild(i) and n = i-1 and i >= 1) }
Expr getUpdate(int n) { exists(int i | result = this.getChild(i) and n = i - 1 and i >= 1) }
override string toString() { result = "for (...;...;...) ..." }
}
@@ -532,8 +508,7 @@ class ForStmt extends LoopStmt, @for_stmt {
* }
* ```
*/
class ForeachStmt extends LoopStmt, @foreach_stmt {
class ForeachStmt extends LoopStmt, @foreach_stmt {
/**
* Gets the local variable of this `foreach` loop, if any.
*
@@ -572,8 +547,9 @@ class ForeachStmt extends LoopStmt, @foreach_stmt {
* ```
*/
LocalVariableDeclExpr getVariableDeclExpr(int i) {
result = getVariableDeclTuple().getArgument(i) or
i=0 and result = this.getChild(0)
result = getVariableDeclTuple().getArgument(i)
or
i = 0 and result = this.getChild(0)
}
/**
@@ -665,9 +641,7 @@ class JumpStmt extends Stmt, @jump_stmt { }
* }
* ```
*/
class BreakStmt extends JumpStmt, @break_stmt {
override string toString() { result = "break;" }
}
class BreakStmt extends JumpStmt, @break_stmt { override string toString() { result = "break;" } }
/**
* A `continue` statement, for example line 4 in
@@ -690,7 +664,6 @@ class ContinueStmt extends JumpStmt, @continue_stmt {
*
* Either a `goto` label (`GotoLabelStmt`), a `goto case` (`GotoCaseStmt`), or
* a `goto default` (`GotoDefaultStmt`).
*
*/
class GotoStmt extends JumpStmt, @goto_any_stmt { }
@@ -707,7 +680,6 @@ class GotoStmt extends JumpStmt, @goto_any_stmt { }
* ```
*/
class GotoLabelStmt extends GotoStmt, @goto_stmt {
/** Gets the label that this `goto` statement jumps to. */
string getLabel() { exprorstmt_name(this, result) }
@@ -715,8 +687,7 @@ class GotoLabelStmt extends GotoStmt, @goto_stmt {
/** Gets the target statement that this `goto` statement jumps to. */
LabeledStmt getTarget() {
result.getEnclosingCallable() = getEnclosingCallable()
and
result.getEnclosingCallable() = getEnclosingCallable() and
result.getLabel() = getLabel()
}
}
@@ -738,7 +709,6 @@ class GotoLabelStmt extends GotoStmt, @goto_stmt {
* ```
*/
class GotoCaseStmt extends GotoStmt, @goto_case_stmt {
/** Gets the constant expression that this `goto case` statement jumps to. */
Expr getExpr() { result = this.getChild(0) }
@@ -803,9 +773,7 @@ class ThrowStmt extends JumpStmt, ThrowElement, @throw_stmt {
* and may be thrown as an exception.
*/
class ExceptionClass extends Class {
ExceptionClass() {
getBaseClass*() instanceof SystemExceptionClass
}
ExceptionClass() { getBaseClass*() instanceof SystemExceptionClass }
}
/**
@@ -818,7 +786,6 @@ class ExceptionClass extends Class {
* ```
*/
class ReturnStmt extends JumpStmt, @return_stmt {
/** Gets the expression being returned, if any. */
Expr getExpr() { result.getParent() = this }
@@ -832,7 +799,6 @@ class ReturnStmt extends JumpStmt, @return_stmt {
* `yield break` statement (`YieldBreakStmt`).
*/
class YieldStmt extends JumpStmt, @yield_stmt {
/** Gets the expression being yielded, if any. */
Expr getExpr() { result.getParent() = this }
}
@@ -893,7 +859,6 @@ class YieldReturnStmt extends YieldStmt {
* ```
*/
class TryStmt extends Stmt, @try_stmt {
/** Gets the block of this `try` statement. */
BlockStmt getBlock() { result = this.getChild(0) }
@@ -901,7 +866,7 @@ class TryStmt extends Stmt, @try_stmt {
CatchClause getACatchClause() { result = this.getAChild() }
/** Gets the `n`th catch clause of this `try` statement. */
CatchClause getCatchClause(int n) { exists(int i | result = this.getChild(i) and n = i-1) }
CatchClause getCatchClause(int n) { exists(int i | result = this.getChild(i) and n = i - 1) }
/** Gets the `finally` block of this `try` statement, if any. */
BlockStmt getFinally() { result = this.getChild(-1) }
@@ -912,18 +877,14 @@ class TryStmt extends Stmt, @try_stmt {
override string toString() { result = "try {...} ..." }
/** Gets the `catch` clause that handles an exception of type `ex`, if any. */
CatchClause getAnExceptionHandler(ExceptionClass ex) {
result = clauseHandlesException(ex, 0)
}
CatchClause getAnExceptionHandler(ExceptionClass ex) { result = clauseHandlesException(ex, 0) }
/**
* Holds if catch clause `cc` definitely handles exceptions of type `ex`.
*/
predicate definitelyHandles(ExceptionClass ex, CatchClause cc) {
cc=getACatchClause()
and
not exists(cc.getFilterClause())
and
cc = getACatchClause() and
not exists(cc.getFilterClause()) and
(
cc.getCaughtExceptionType() = ex.getBaseClass*()
or
@@ -932,26 +893,23 @@ class TryStmt extends Stmt, @try_stmt {
}
private predicate maybeHandles(ExceptionClass ex, CatchClause cc) {
cc=getACatchClause()
and
cc = getACatchClause() and
cc.getCaughtExceptionType().getBaseClass*() = ex
}
private CatchClause clauseHandlesException(ExceptionClass ex, int n) {
exists(CatchClause clause |
clause = getCatchClause(n) |
if
definitelyHandles(ex, clause)
then
result = clause
else if
maybeHandles(ex, clause)
then
result = clause or
result = clauseHandlesException(ex, n+1)
else // Does not handle
result = clauseHandlesException(ex, n+1)
)
exists(CatchClause clause | clause = getCatchClause(n) |
if definitelyHandles(ex, clause)
then result = clause
else
if maybeHandles(ex, clause)
then
result = clause or
result = clauseHandlesException(ex, n + 1)
else
// Does not handle
result = clauseHandlesException(ex, n + 1)
)
}
/**
@@ -1003,7 +961,7 @@ class CatchClause extends Stmt, @catch {
* }
* ```
*/
ExceptionClass getCaughtExceptionType() { catch_type(this,getTypeRef(result),_) }
ExceptionClass getCaughtExceptionType() { catch_type(this, getTypeRef(result), _) }
/**
* Gets the `catch` filter clause, if any. For example, the filter expression
@@ -1018,7 +976,7 @@ class CatchClause extends Stmt, @catch {
* }
* ```
*/
Expr getFilterClause() { result=getChild(2) }
Expr getFilterClause() { result = getChild(2) }
/** Holds if this `catch` clause has a filter. */
predicate hasFilterClause() { exists(getFilterClause()) }
@@ -1050,8 +1008,7 @@ class CatchClause extends Stmt, @catch {
* The exception variable (`ex`) is optional.
*/
class SpecificCatchClause extends CatchClause {
SpecificCatchClause() { catch_type(this,_,1) }
SpecificCatchClause() { catch_type(this, _, 1) }
/** Gets the local variable of this catch clause, if any. */
LocalVariable getVariable() { result = this.getVariableDeclExpr().getVariable() }
@@ -1077,11 +1034,9 @@ class SpecificCatchClause extends CatchClause {
* ```
*/
class GeneralCatchClause extends CatchClause {
GeneralCatchClause() { catch_type(this,_,2) }
GeneralCatchClause() { catch_type(this, _, 2) }
override string toString() { result = "catch {...}" }
}
/**
@@ -1095,7 +1050,6 @@ class GeneralCatchClause extends CatchClause {
* ```
*/
class CheckedStmt extends Stmt, @checked_stmt {
/** Gets the block of this `checked` statement. */
BlockStmt getBlock() { result.getParent() = this }
@@ -1113,7 +1067,6 @@ class CheckedStmt extends Stmt, @checked_stmt {
* ```
*/
class UncheckedStmt extends Stmt, @unchecked_stmt {
/** Gets the block of this unchecked statement. */
BlockStmt getBlock() { result.getParent() = this }
@@ -1130,7 +1083,6 @@ class UncheckedStmt extends Stmt, @unchecked_stmt {
* ```
*/
class LockStmt extends Stmt, @lock_stmt {
/** Gets the expression being locked. */
Expr getExpr() { result.getParent() = this }
@@ -1140,31 +1092,22 @@ class LockStmt extends Stmt, @lock_stmt {
override string toString() { result = "lock (...) {...}" }
/** Gets the variable being locked, if any. */
Variable getLockVariable()
{
result.getAnAccess() = getExpr()
}
Variable getLockVariable() { result.getAnAccess() = getExpr() }
/** Gets a statement in the scope of this `lock` statement. */
Stmt getALockedStmt()
{
Stmt getALockedStmt() {
// Do this instead of getParent+, because we don't want to escape
// delegates and lambdas
result.getParent() = this
or exists( Stmt mid | mid=getALockedStmt() and result.getParent()=mid )
or
exists(Stmt mid | mid = getALockedStmt() and result.getParent() = mid)
}
/** Holds if this statement is of the form `lock(this) { ... }`. */
predicate isLockThis()
{
getExpr() instanceof ThisAccess
}
predicate isLockThis() { getExpr() instanceof ThisAccess }
/** Gets the type `T` if this statement is of the form `lock(typeof(T)) { ... }`. */
Type getLockTypeObject()
{
result = ((TypeofExpr)getExpr()).getTypeAccess().getTarget()
}
Type getLockTypeObject() { result = getExpr().(TypeofExpr).getTypeAccess().getTarget() }
}
/**
@@ -1177,7 +1120,6 @@ class LockStmt extends Stmt, @lock_stmt {
* ```
*/
class UsingStmt extends Stmt, @using_stmt {
/** Gets the `i`th local variable of this `using` statement. */
LocalVariable getVariable(int i) { result = this.getVariableDeclExpr(i).getVariable() }
@@ -1201,9 +1143,7 @@ class UsingStmt extends Stmt, @using_stmt {
* }
* ```
*/
Expr getExpr() {
result = this.getChild(0)
}
Expr getExpr() { result = this.getChild(0) }
/**
* Gets an expression that is used in this `using` statement. Either an
@@ -1247,7 +1187,6 @@ class UsingStmt extends Stmt, @using_stmt {
* ```
*/
class LocalVariableDeclStmt extends Stmt, @decl_stmt {
/**
* Gets a local variable declaration, for example `x = null` and
* `y = ""` in
@@ -1273,7 +1212,6 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt {
LocalVariableDeclExpr getVariableDeclExpr(int n) { result = this.getChild(n) }
override string toString() { result = "... ...;" }
}
/**
@@ -1286,7 +1224,6 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt {
* ```
*/
class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt {
/**
* Gets a local constant declaration, for example `x = 1` and `y = 2` in
*
@@ -1322,10 +1259,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt {
* }
* ```
*/
class EmptyStmt extends Stmt, @empty_stmt {
override string toString() { result = ";" }
}
class EmptyStmt extends Stmt, @empty_stmt { override string toString() { result = ";" } }
/**
* An `unsafe` statement, for example
@@ -1340,7 +1274,6 @@ class EmptyStmt extends Stmt, @empty_stmt {
* ```
*/
class UnsafeStmt extends Stmt, @unsafe_stmt {
/** Gets the block of this unsafe statement. */
BlockStmt getBlock() { result.getParent() = this }
@@ -1360,7 +1293,6 @@ class UnsafeStmt extends Stmt, @unsafe_stmt {
* ```
*/
class FixedStmt extends Stmt, @fixed_stmt {
/** Gets the `i`th local variable of this `fixed` statement. */
LocalVariable getVariable(int i) { result = this.getVariableDeclExpr(i).getVariable() }
@@ -1392,8 +1324,7 @@ class FixedStmt extends Stmt, @fixed_stmt {
* exit: ...
* ```
*/
class LabelStmt extends LabeledStmt, @label_stmt {
}
class LabelStmt extends LabeledStmt, @label_stmt { }
/**
* A labeled statement.
@@ -1401,7 +1332,6 @@ class LabelStmt extends LabeledStmt, @label_stmt {
* Either a `case` statement (`ConstCase`) or a label statement (`LabelStmt`).
*/
class LabeledStmt extends Stmt, @labeled_stmt {
/**
* Gets the next statement after this labeled statement.
*
@@ -1413,8 +1343,10 @@ class LabeledStmt extends Stmt, @labeled_stmt {
* ```
*/
Stmt getStmt() {
exists(int i | this = this.getParent().getChild(i)
and result = this.getParent().getChild(i+1))
exists(int i |
this = this.getParent().getChild(i) and
result = this.getParent().getChild(i + 1)
)
}
/** Gets the label of this statement. */
@@ -1438,11 +1370,8 @@ class LabeledStmt extends Stmt, @labeled_stmt {
* ```
*/
class LocalFunctionStmt extends Stmt, @local_function_stmt {
/** Gets the local function defined by this statement. */
LocalFunction getLocalFunction() {
local_function_stmts(this, result)
}
LocalFunction getLocalFunction() { local_function_stmts(this, result) }
override string toString() { result = getLocalFunction().getName() + "(...)" }
}

View File

@@ -18,19 +18,14 @@ private import dotnet
* type (`UnknownType`), or a type parameter (`TypeParameter`).
*/
class Type extends DotNet::Type, Member, TypeContainer, @type {
override string getName() { types(this,_,result) }
override string getName() { types(this, _, result) }
override Type getSourceDeclaration() { result = this }
/** Holds if this type is implicitly convertible to `that` type. */
predicate isImplicitlyConvertibleTo(Type that) {
implicitConversion(this, that)
}
predicate isImplicitlyConvertibleTo(Type that) { implicitConversion(this, that) }
override Location getALocation() {
type_location(this, result)
}
override Location getALocation() { type_location(this, result) }
override Type getChild(int n) { none() }
@@ -50,7 +45,6 @@ class Type extends DotNet::Type, Member, TypeContainer, @type {
* Either a value type (`ValueType`) or a reference type (`RefType`).
*/
class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_or_ref_type {
/**
* Holds if this type has the qualified name `qualifier`.`name`.
*
@@ -59,37 +53,35 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
*/
override predicate hasQualifiedName(string qualifier, string name) {
name = this.getName() and
if exists(this.getDeclaringType()) then
qualifier = this.getDeclaringType().getQualifiedName()
else
qualifier = this.getNamespace().getQualifiedName()
if exists(this.getDeclaringType())
then qualifier = this.getDeclaringType().getQualifiedName()
else qualifier = this.getNamespace().getQualifiedName()
}
/** Gets the namespace containing this type. */
Namespace getNamespace() {
if exists(this.getDeclaringType()) then
result = this.getDeclaringType().getNamespace()
else
result.getATypeDeclaration() = this
if exists(this.getDeclaringType())
then result = this.getDeclaringType().getNamespace()
else result.getATypeDeclaration() = this
}
override Namespace getDeclaringNamespace() {
this = result.getATypeDeclaration()
}
override Namespace getDeclaringNamespace() { this = result.getATypeDeclaration() }
override ValueOrRefType getDeclaringType() { none() }
override string getUndecoratedName() {
if
this.getName().indexOf("<")>0
if this.getName().indexOf("<") > 0
then
exists(string name, int p | name = this.getName() and p = min(int p2 | p2 = name.indexOf("<") and p2>0) | result=name.substring(0, p))
else
result = this.getName()
exists(string name, int p |
name = this.getName() and p = min(int p2 | p2 = name.indexOf("<") and p2 > 0)
|
result = name.substring(0, p)
)
else result = this.getName()
}
/** Gets a nested child type, if any. */
NestedType getAChildType() { nested_types(result,this,_) }
NestedType getAChildType() { nested_types(result, this, _) }
/**
* Gets the source namespace declaration in which this type is declared, if any.
@@ -108,7 +100,9 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
* }
* ```
*/
NamespaceDeclaration getParentNamespaceDeclaration() { parent_namespace_declaration(this,result) }
NamespaceDeclaration getParentNamespaceDeclaration() {
parent_namespace_declaration(this, result)
}
/** Gets the immediate base class of this class, if any. */
Class getBaseClass() { extend(this, getTypeRef(result)) }
@@ -222,8 +216,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
}
private predicate hasNonOverriddenMember(Member m) {
isNonOverridden(m)
and
isNonOverridden(m) and
(
m = getAMember()
or
@@ -241,7 +234,8 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
not memberOverrides(v)
}
pragma [noinline] // Predicate folding for proper join-order
// Predicate folding for proper join-order
pragma[noinline]
private predicate memberOverrides(Virtualizable v) {
getAMember().(Virtualizable).getOverridee() = v
}
@@ -280,25 +274,21 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
StaticConstructor getStaticConstructor() { result = getAMember() }
/** Gets a nested type of this type, if any. */
NestedType getANestedType() { result = getAMember() }
NestedType getANestedType() { result = getAMember() }
/** Gets the number of types that directly depend on this type. */
int getAfferentCoupling() {
afferentCoupling(this, result)
}
int getAfferentCoupling() { afferentCoupling(this, result) }
/** Gets the number of types that this type directly depends upon. */
int getEfferentCoupling() {
efferentCoupling(this, result)
}
int getEfferentCoupling() { efferentCoupling(this, result) }
/** Gets the length of *some* path to the root of the hierarchy. */
int getADepth() {
(this.hasQualifiedName("System", "Object") and result = 0)
this.hasQualifiedName("System", "Object") and result = 0
or
(result = this.getABaseType().getADepth() + 1
//prevent recursion on cyclic inheritance (only for incorrect databases)
and not (this = this.getABaseType+()))
result = this.getABaseType().getADepth() + 1 and
//prevent recursion on cyclic inheritance (only for incorrect databases)
not this = this.getABaseType+()
}
/**
@@ -306,14 +296,10 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
* `object` in the type hierarchy. Types that are very deeply nested
* may be difficult to maintain.
*/
int getInheritanceDepth() {
result = max(this.getADepth())
}
int getInheritanceDepth() { result = max(this.getADepth()) }
/** Gets the number of (direct or indirect) base types. */
int getNumberOfAncestors() {
result = count(this.getABaseType+())
}
int getNumberOfAncestors() { result = count(this.getABaseType+()) }
/**
* Gets the Henderson-Sellers lack of cohesion metric.
@@ -325,9 +311,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
* Types with a high Henderson-Sellers metric have methods
* which access many fields, and can be a maintainability problem.
*/
float getLackOfCohesionHS() {
lackOfCohesionHS(this, result)
}
float getLackOfCohesionHS() { lackOfCohesionHS(this, result) }
/**
* Gets the Chidamber and Kemerer lack of cohesion metric.
@@ -340,9 +324,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
* Types with a high Chidamber and Kemerer metric have multiple
* responsibilities so could be refactored.
*/
float getLackOfCohesionCK() {
lackOfCohesionCK(this, result)
}
float getLackOfCohesionCK() { lackOfCohesionCK(this, result) }
/**
* Gets the *response* of this type, which is defined as the total number
@@ -351,18 +333,17 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
*/
int getResponse() {
result = sum(Callable c |
c.getDeclaringType() = this |
count(Call call |
call.getEnclosingCallable() = c and
not call instanceof MemberAccess // property, indexer, and event accesses are not counted
c.getDeclaringType() = this
|
count(Call call |
call.getEnclosingCallable() = c and
not call instanceof MemberAccess // property, indexer, and event accesses are not counted
)
)
)
}
/** Gets the number of callables in this type. */
int getNumberOfCallables() {
result = count(Callable c | this.getAMember() = c)
}
int getNumberOfCallables() { result = count(Callable c | this.getAMember() = c) }
override ValueOrRefType getSourceDeclaration() {
result = this and
@@ -371,7 +352,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
// We must use `nested_types` here, rather than overriding `getSourceDeclaration`
// in the class `NestedType` below. Otherwise, the overrides in `UnboundGenericType`
// and its subclasses will not work
nested_types(this,_,result)
nested_types(this, _, result)
}
override string toString() { result = Type.super.toString() }
@@ -391,18 +372,16 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
* ```
*/
class NestedType extends ValueOrRefType {
NestedType() { nested_types(this, _, _) }
NestedType() { nested_types(this,_,_) }
override ValueOrRefType getDeclaringType() { nested_types(this,result,_) }
override ValueOrRefType getDeclaringType() { nested_types(this, result, _) }
}
/**
* A non-nested type, that is declared directly in a namespace.
*/
class NonNestedType extends ValueOrRefType {
NonNestedType() { exists(Namespace n | parent_namespace(this,n)) }
NonNestedType() { exists(Namespace n | parent_namespace(this, n)) }
}
/**
@@ -437,7 +416,6 @@ class ValueType extends ValueOrRefType, @value_type { }
* (`FloatingPointType`), or a decimal type (`DecimalType`).
*/
class SimpleType extends ValueType, @simple_type {
/** Gets the minimum integral value of this type, if any. */
int minValue() { none() }
@@ -451,7 +429,6 @@ class SimpleType extends ValueType, @simple_type {
* The Boolean type, `bool`.
*/
class BoolType extends SimpleType, @bool_type {
override string toStringWithTypes() { result = "bool" }
}
@@ -459,12 +436,11 @@ class BoolType extends SimpleType, @bool_type {
* The Unicode character type, `char`.
*/
class CharType extends SimpleType, @char_type {
override string toStringWithTypes() { result = "char" }
override int minValue() { result=0 }
override int minValue() { result = 0 }
override int maxValue() { result=65535 }
override int maxValue() { result = 65535 }
}
/**
@@ -473,8 +449,7 @@ class CharType extends SimpleType, @char_type {
* Either a signed integral type (`SignedIntegralType`) or an unsigned integral type
* (`UnsignedIntegralType`).
*/
class IntegralType extends SimpleType, @integral_type {
}
class IntegralType extends SimpleType, @integral_type { }
/**
* An unsigned integral type.
@@ -483,8 +458,7 @@ class IntegralType extends SimpleType, @integral_type {
* or a `ulong` (`ULongType`).
*/
class UnsignedIntegralType extends IntegralType, @unsigned_integral_type {
override int minValue() { result=0 }
override int minValue() { result = 0 }
}
/**
@@ -493,50 +467,45 @@ class UnsignedIntegralType extends IntegralType, @unsigned_integral_type {
* Either an `sbyte` (`SByteType`), a `short` (`ShortType`), an `int`
* (`IntType`), or a `long` (`LongType`).
*/
class SignedIntegralType extends IntegralType, @signed_integral_type {
}
class SignedIntegralType extends IntegralType, @signed_integral_type { }
/**
* The signed byte type, `sbyte`.
*/
class SByteType extends SignedIntegralType, @sbyte_type {
override string toStringWithTypes() { result = "sbyte" }
override int minValue() { result=-128 }
override int minValue() { result = -128 }
override int maxValue() { result=127 }
override int maxValue() { result = 127 }
}
/**
* The `short` type.
*/
class ShortType extends SignedIntegralType, @short_type {
override string toStringWithTypes() { result = "short" }
override int minValue() { result=-32768 }
override int minValue() { result = -32768 }
override int maxValue() { result=32767 }
override int maxValue() { result = 32767 }
}
/**
* The `int` type.
*/
class IntType extends SignedIntegralType, @int_type {
override string toStringWithTypes() { result = "int" }
override int minValue() { result=-2147483647-1 }
override int minValue() { result = -2147483647 - 1 }
override int maxValue() { result=2147483647 }
override int maxValue() { result = 2147483647 }
}
/**
* The `long` type.
*/
class LongType extends SignedIntegralType, @long_type {
override string toStringWithTypes() { result = "long" }
}
@@ -545,7 +514,8 @@ class LongType extends SignedIntegralType, @long_type {
*/
class ByteType extends UnsignedIntegralType, @byte_type {
override string toStringWithTypes() { result = "byte" }
override int maxValue() { result=255 }
override int maxValue() { result = 255 }
}
/**
@@ -553,14 +523,14 @@ class ByteType extends UnsignedIntegralType, @byte_type {
*/
class UShortType extends UnsignedIntegralType, @ushort_type {
override string toStringWithTypes() { result = "ushort" }
override int maxValue() { result=65535 }
override int maxValue() { result = 65535 }
}
/**
* The unsigned int type, `uint`.
*/
class UIntType extends UnsignedIntegralType, @uint_type {
override string toStringWithTypes() { result = "uint" }
}
@@ -568,7 +538,6 @@ class UIntType extends UnsignedIntegralType, @uint_type {
* The unsigned long type, `ulong`.
*/
class ULongType extends UnsignedIntegralType, @ulong_type {
override string toStringWithTypes() { result = "ulong" }
}
@@ -577,14 +546,12 @@ class ULongType extends UnsignedIntegralType, @ulong_type {
*
* Either a `float` (`FloatType`) or a `double` (`DoubleType`).
*/
class FloatingPointType extends SimpleType, @floating_point_type {
}
class FloatingPointType extends SimpleType, @floating_point_type { }
/**
* The `float` type.
*/
class FloatType extends FloatingPointType, @float_type {
override string toStringWithTypes() { result = "float" }
}
@@ -592,7 +559,6 @@ class FloatType extends FloatingPointType, @float_type {
* The `double` type.
*/
class DoubleType extends FloatingPointType, @double_type {
override string toStringWithTypes() { result = "double" }
}
@@ -600,7 +566,6 @@ class DoubleType extends FloatingPointType, @double_type {
* The high-precision decimal type, `decimal`.
*/
class DecimalType extends SimpleType, @decimal_type {
override string toStringWithTypes() { result = "decimal" }
}
@@ -615,7 +580,6 @@ class DecimalType extends SimpleType, @decimal_type {
* ```
*/
class Enum extends ValueType, @enum_type {
/**
* Gets the underlying integral type of this enum, not to be confused with
* its base type which is always `System.Enum`.
@@ -673,16 +637,13 @@ class Struct extends ValueType, @struct_type {
* `null` (`NullType`), `dynamic` (`DynamicType`), or an array (`ArrayType`).
*/
class RefType extends ValueOrRefType, @ref_type {
/** Gets the number of overridden methods (NORM) of this reference type. */
int getNumberOverridden() {
result = count(this.getAnOverrider())
}
int getNumberOverridden() { result = count(this.getAnOverrider()) }
/** Gets a member that overrides a non-abstract member in a super type, if any. */
private Virtualizable getAnOverrider() {
getAMember() = result and
exists(Virtualizable v | result.getOverridee() = v and not v.isAbstract())
getAMember() = result and
exists(Virtualizable v | result.getOverridee() = v and not v.isAbstract())
}
/**
@@ -694,18 +655,14 @@ class RefType extends ValueOrRefType, @ref_type {
* This measures the inheritance complexity of this type.
*/
float getSpecialisationIndex() {
this.getNumberOfCallables() != 0
and
result = (this.getNumberOverridden() * this.getInheritanceDepth())
/
((float)this.getNumberOfCallables())
this.getNumberOfCallables() != 0 and
result = (this.getNumberOverridden() * this.getInheritanceDepth()) /
this.getNumberOfCallables().(float)
}
}
// Helper predicate to avoid slow "negation_body"
private predicate isNonOverridden(Member m) {
not m.(Virtualizable).isOverridden()
}
private predicate isNonOverridden(Member m) { not m.(Virtualizable).isOverridden() }
/**
* A `class`, for example
@@ -716,8 +673,7 @@ private predicate isNonOverridden(Member m) {
* }
* ```
*/
class Class extends RefType, @class_type {
}
class Class extends RefType, @class_type { }
/**
* A class generated by the compiler from an anonymous object creation.
@@ -728,15 +684,12 @@ class Class extends RefType, @class_type {
* new { X = 0, Y = 0 };
* ```
*/
class AnonymousClass extends Class {
AnonymousClass() { this.getName().matches("<%") }
}
class AnonymousClass extends Class { AnonymousClass() { this.getName().matches("<%") } }
/**
* The `object` type, `System.Object`.
*/
class ObjectType extends Class {
ObjectType() { this.hasQualifiedName("System.Object") }
override string toStringWithTypes() { result = "object" }
@@ -746,7 +699,6 @@ class ObjectType extends Class {
* The `string` type, `System.String`.
*/
class StringType extends Class {
StringType() { this.hasQualifiedName("System.String") }
override string toStringWithTypes() { result = "string" }
@@ -761,9 +713,7 @@ class StringType extends Class {
* }
* ```
*/
class Interface extends RefType, @interface_type {
}
class Interface extends RefType, @interface_type { }
/**
* A `delegate` type, for example
@@ -774,7 +724,7 @@ class Interface extends RefType, @interface_type {
*/
class DelegateType extends RefType, Parameterizable, @delegate_type {
/** Gets the return type of this delegate. */
Type getReturnType() { delegate_return_type(this,getTypeRef(result)) }
Type getReturnType() { delegate_return_type(this, getTypeRef(result)) }
/** Holds if this delegate returns a `ref`. */
predicate returnsRef() { ref_returns(this) }
@@ -792,46 +742,42 @@ class NullType extends RefType, @null_type { }
* A nullable type, for example `int?`.
*/
class NullableType extends ValueType, DotNet::ConstructedGeneric, @nullable_type {
/**
* Gets the underlying value type of this nullable type.
* For example `int` in `int?`.
*/
Type getUnderlyingType() { nullable_underlying_type(this,getTypeRef(result)) }
Type getUnderlyingType() { nullable_underlying_type(this, getTypeRef(result)) }
override string toStringWithTypes() {
result = getUnderlyingType().toStringWithTypes() + "?"
}
override string toStringWithTypes() { result = getUnderlyingType().toStringWithTypes() + "?" }
override Type getChild(int n) { result = getUnderlyingType() and n = 0 }
override Location getALocation() { result = getUnderlyingType().getALocation() }
override Type getTypeArgument(int p) { p=0 and result = getUnderlyingType() }
override Type getTypeArgument(int p) { p = 0 and result = getUnderlyingType() }
}
/**
* An array type, for example `int[]`.
*/
class ArrayType extends DotNet::ArrayType, RefType, @array_type {
/**
* Gets the dimension of this array type. For example `int[][]` is of
* dimension 2, while `int[]` is of dimension 1.
*/
int getDimension() { array_element_type(this,result,_,_) }
int getDimension() { array_element_type(this, result, _, _) }
/**
* Gets the rank of this array type. For example `int[,]` is of
* rank 2, while `int[]` is of rank 1.
*/
int getRank() { array_element_type(this,_,result,_) }
int getRank() { array_element_type(this, _, result, _) }
/** Holds if this array is multi-dimensional. */
predicate isMultiDimensional() { this.getRank() > 1 }
/** Gets the element type of this array, for example `int` in `int[]`. */
override Type getElementType() { array_element_type(this,_,_,getTypeRef(result)) }
override Type getElementType() { array_element_type(this, _, _, getTypeRef(result)) }
/** Holds if this array type has the same shape (dimension and rank) as `that` array type. */
predicate hasSameShapeAs(ArrayType that) {
@@ -840,23 +786,19 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type {
}
private string getRankString(int i) {
i in [0 .. getRank() - 1]
and
if i = getRank() - 1 then
result = ""
else (
result = "," + getRankString(i + 1)
)
i in [0 .. getRank() - 1] and
if i = getRank() - 1 then result = "" else result = "," + getRankString(i + 1)
}
private string getDimensionString(Type elementType) {
exists(Type et, string res |
et = getElementType() and
res = "[" + getRankString(0) + "]" and
if et instanceof ArrayType then
result = res + et.(ArrayType).getDimensionString(elementType)
else
(result = res and elementType = et)
if et instanceof ArrayType
then result = res + et.(ArrayType).getDimensionString(elementType)
else (
result = res and elementType = et
)
)
}
@@ -880,7 +822,7 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type {
* A pointer type, for example `char*`.
*/
class PointerType extends DotNet::PointerType, Type, @pointer_type {
override Type getReferentType() { pointer_referent_type(this,getTypeRef(result)) }
override Type getReferentType() { pointer_referent_type(this, getTypeRef(result)) }
override string toStringWithTypes() { result = DotNet::PointerType.super.toStringWithTypes() }
@@ -897,7 +839,6 @@ class PointerType extends DotNet::PointerType, Type, @pointer_type {
* The `dynamic` type.
*/
class DynamicType extends RefType, @dynamic_type {
override string toStringWithTypes() { result = "dynamic" }
}
@@ -905,7 +846,6 @@ class DynamicType extends RefType, @dynamic_type {
* The `__arglist` type, modeling varargs invocation in C++.
*/
class ArglistType extends Type, @arglist_type {
override string toStringWithTypes() { result = "__arglist" }
}
@@ -913,55 +853,48 @@ class ArglistType extends Type, @arglist_type {
* A type that could not be resolved. This could happen if an indirect reference
* is not available at compilation time.
*/
class UnknownType extends Type, @unknown_type {
}
class UnknownType extends Type, @unknown_type { }
/**
* A type representing a tuple. For example, `(int, bool, string)`.
*/
class TupleType extends ValueType, @tuple_type {
/** Gets the underlying type of this tuple, which is of type `System.ValueTuple`. */
ConstructedStruct getUnderlyingType() {
tuple_underlying_type(this, result)
}
ConstructedStruct getUnderlyingType() { tuple_underlying_type(this, result) }
/**
* Gets the `n`th element of this tuple, indexed from 0.
* For example, the 0th (first) element of `(int, string)` is the field `Item1 int`.
*/
Field getElement(int n) {
tuple_element(this, n, result)
}
Field getElement(int n) { tuple_element(this, n, result) }
/**
* Gets the type of the `n`th element of this tuple, indexed from 0.
* For example, the 0th (first) element type of `(int, string)` is `int`.
*/
Type getElementType(int n) {
result = getElement(n).getType()
}
Type getElementType(int n) { result = getElement(n).getType() }
/** Gets an element of this tuple. */
Field getAnElement() {
result = getElement(_)
}
Field getAnElement() { result = getElement(_) }
override Location getALocation() {
type_location(this, result)
}
override Location getALocation() { type_location(this, result) }
/**
* Gets the arity of this tuple. For example, the arity of
* `(int, int, double)` is 3.
*/
int getArity() {
result=count(getAnElement())
}
int getArity() { result = count(getAnElement()) }
language [monotonicAggregates]
language[monotonicAggregates]
override string toStringWithTypes() {
result = "(" + concat(int i | exists(getElement(i)) | getElement(i).getType().toStringWithTypes(), ", " order by i) + ")"
result = "(" +
concat(int i |
exists(getElement(i))
|
getElement(i).getType().toStringWithTypes(), ", "
order by
i
) + ")"
}
override string getLabel() { result = getUnderlyingType().getLabel() }
@@ -973,6 +906,7 @@ class TupleType extends ValueType, @tuple_type {
*/
class TypeMention extends @type_mention {
Type type;
@type_mention_parent parent;
TypeMention() { type_mention(this, getTypeRef(type), parent) }

View File

@@ -34,9 +34,7 @@ class UsingDirective extends Element, @using_directive {
parent_namespace_declaration(this, result)
}
override Location getALocation() {
using_directive_location(this, result)
}
override Location getALocation() { using_directive_location(this, result) }
}
/**
@@ -47,7 +45,7 @@ class UsingNamespaceDirective extends UsingDirective, @using_namespace_directive
* Gets the target of this namespace `using` directive, for example `System`
* in `using System`.
*/
Namespace getImportedNamespace() { using_namespace_directives(this,result) }
Namespace getImportedNamespace() { using_namespace_directives(this, result) }
override string toString() { result = "using ...;" }
}
@@ -60,9 +58,7 @@ class UsingStaticDirective extends UsingDirective, @using_static_directive {
* Gets the target of this type `using` directive, for example
* `System.Console` in `using static System.Console`.
*/
ValueOrRefType getTarget() {
using_static_directives(this, getTypeRef(result))
}
ValueOrRefType getTarget() { using_static_directives(this, getTypeRef(result)) }
override string toString() { result = "using static ...;" }
}

View File

@@ -14,46 +14,56 @@ private import semmle.code.csharp.ExprOrStmtParent
* A variable. Either a variable with local scope (`LocalScopeVariable`) or a field (`Field`).
*/
class Variable extends Assignable, DotNet::Variable, @variable {
/** Gets the type that declares this variable, if any. */
override ValueOrRefType getDeclaringType() {
fields(this,_,_,result,_,_) or
exists(Expr e | localvars(this, _, _, _, _, e) and result = e.getEnclosingStmt().getEnclosingCallable().getDeclaringType()) or
exists(Callable parent | params(this, _, _, _, _ , parent, _) and result = parent.getDeclaringType()) or
exists(Indexer indexer | params(this, _, _, _, _, indexer, _) and result = indexer.getDeclaringType()) or
exists(@delegate_type t | params(this, _, _, _, _, t, _) and result = t) or
exists(Expr parent | params(this, _, _, _, _, parent, _) and result = parent.getEnclosingCallable().getDeclaringType())
fields(this, _, _, result, _, _)
or
exists(Expr e |
localvars(this, _, _, _, _, e) and
result = e.getEnclosingStmt().getEnclosingCallable().getDeclaringType()
)
or
exists(Callable parent |
params(this, _, _, _, _, parent, _) and result = parent.getDeclaringType()
)
or
exists(Indexer indexer |
params(this, _, _, _, _, indexer, _) and result = indexer.getDeclaringType()
)
or
exists(@delegate_type t | params(this, _, _, _, _, t, _) and result = t)
or
exists(Expr parent |
params(this, _, _, _, _, parent, _) and
result = parent.getEnclosingCallable().getDeclaringType()
)
}
override Variable getSourceDeclaration() { result = this }
override string getName() {
params(this,result,_,_,_,_,_) or
localvars(this,_,result,_,_,_) or
fields(this,_,result,_,_,_)
params(this, result, _, _, _, _, _) or
localvars(this, _, result, _, _, _) or
fields(this, _, result, _, _, _)
}
/** Gets the type of this variable. For example `int` in `int x`. */
override Type getType() {
params(this,_,getTypeRef(result),_,_,_,_) or
localvars(this,_,_,_,getTypeRef(result),_) or
fields(this,_,_,_,getTypeRef(result),_)
params(this, _, getTypeRef(result), _, _, _, _) or
localvars(this, _, _, _, getTypeRef(result), _) or
fields(this, _, _, _, getTypeRef(result), _)
}
override Location getALocation() {
param_location(this,result) or
localvar_location(this,result) or
field_location(this,result)
param_location(this, result) or
localvar_location(this, result) or
field_location(this, result)
}
override VariableAccess getAnAccess() {
result.getTarget() = this
}
override VariableAccess getAnAccess() { result.getTarget() = this }
/** Gets the expression used to initialise this variable, if any. */
Expr getInitializer() {
none()
}
Expr getInitializer() { none() }
}
/**
@@ -77,9 +87,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable {
* }
* ```
*/
predicate isCaptured() {
exists(this.getACapturingCallable())
}
predicate isCaptured() { exists(this.getACapturingCallable()) }
/**
* Gets a callable that captures this variable, if any. For example,
@@ -115,8 +123,8 @@ class LocalScopeVariable extends Variable, @local_scope_variable {
* }
* ```
*/
class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, TopLevelExprParent, @parameter {
class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, TopLevelExprParent,
@parameter {
/**
* Gets the position of this parameter. For example, the position of `x` is
* 0 and the position of `y` is 1 in
@@ -127,7 +135,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
* }
* ```
*/
override int getPosition() { params(this,_,_,result,_,_,_) }
override int getPosition() { params(this, _, _, result, _, _, _) }
override int getIndex() { result = this.getPosition() }
@@ -141,7 +149,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
* }
* ```
*/
predicate isValue() { params(this,_,_,_,0,_,_) }
predicate isValue() { params(this, _, _, _, 0, _, _) }
/**
* Holds if this parameter is a reference parameter. For example, `p`
@@ -153,7 +161,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
* }
* ```
*/
override predicate isRef() { params(this,_,_,_,1,_,_) }
override predicate isRef() { params(this, _, _, _, 1, _, _) }
/**
* Holds if this parameter is an output parameter. For example, `p`
@@ -165,7 +173,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
* }
* ```
*/
override predicate isOut() { params(this,_,_,_,2,_,_) }
override predicate isOut() { params(this, _, _, _, 2, _, _) }
/**
* Holds if this parameter is a value type that is passed in by reference.
@@ -177,7 +185,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
* }
* ```
*/
predicate isIn() { params(this,_,_,_,5,_,_) }
predicate isIn() { params(this, _, _, _, 5, _, _) }
/** Holds if this parameter is an output or reference parameter. */
predicate isOutOrRef() { isOut() or isRef() }
@@ -192,7 +200,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
* }
* ```
*/
predicate isParams() { params(this,_,_,_,3,_,_) }
predicate isParams() { params(this, _, _, _, 3, _, _) }
/**
* Holds this parameter is the first parameter of an extension method.
@@ -205,12 +213,12 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
* }
* ```
*/
predicate hasExtensionMethodModifier() { params(this,_,_,_,4,_,_) }
predicate hasExtensionMethodModifier() { params(this, _, _, _, 4, _, _) }
/** Gets the declaring element of this parameter. */
Parameterizable getDeclaringElement() { params(this,_,_,_,_,result,_) }
Parameterizable getDeclaringElement() { params(this, _, _, _, _, result, _) }
override Parameter getSourceDeclaration() { params(this,_,_,_,_,_,result) }
override Parameter getSourceDeclaration() { params(this, _, _, _, _, _, result) }
override string toString() { result = this.getName() }
@@ -232,9 +240,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
predicate hasDefaultValue() { exists(getDefaultValue()) }
/** Gets the callable to which this parameter belongs, if any. */
override Callable getCallable() {
result.getAParameter() = this
}
override Callable getCallable() { result.getAParameter() = this }
/**
* Gets an argument which is assigned to this parameter in a call to the
@@ -258,9 +264,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top
* The assigned arguments to `x` are `1` and `4`, the assigned argument to
* `y` is `5`, and the assigned arguments to `z` are `3` and `6`, respectively.
*/
Expr getAnAssignedArgument() {
result = getCallable().getACall().getArgumentForParameter(this)
}
Expr getAnAssignedArgument() { result = getCallable().getACall().getArgumentForParameter(this) }
/** Holds if this parameter is potentially overwritten in the body of its callable. */
predicate isOverwritten() {
@@ -310,7 +314,6 @@ class ImplicitAccessorParameter extends Parameter {
* ```
*/
class LocalVariable extends LocalScopeVariable, @local_variable {
/** Gets the declaration of this local variable. */
LocalVariableDeclExpr getVariableDeclExpr() { result.getVariable() = this }
@@ -343,16 +346,14 @@ class LocalVariable extends LocalScopeVariable, @local_variable {
* }
* ```
*/
predicate isImplicitlyTyped() { localvars(this,_,_,1,_,_) }
predicate isImplicitlyTyped() { localvars(this, _, _, 1, _, _) }
/** Gets the enclosing callable of this local variable. */
Callable getEnclosingCallable() {
result = this.getVariableDeclExpr().getEnclosingCallable()
}
Callable getEnclosingCallable() { result = this.getVariableDeclExpr().getEnclosingCallable() }
override Callable getCallable() { result = getEnclosingCallable() }
override predicate isRef() { localvars(this,3,_,_,_,_) }
override predicate isRef() { localvars(this, 3, _, _, _, _) }
}
/**
@@ -367,7 +368,6 @@ class LocalVariable extends LocalScopeVariable, @local_variable {
* ```
*/
class LocalConstant extends LocalVariable, @local_constant {
/** Gets the declaration of this local constant. */
override LocalConstantDeclExpr getVariableDeclExpr() { result.getVariable() = this }
@@ -384,7 +384,8 @@ class LocalConstant extends LocalVariable, @local_constant {
* }
* ```
*/
class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent, DotNet::Field, @field {
class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent, DotNet::Field,
@field {
/** Gets the initializer of this field, if any. */
override Expr getInitializer() { result = this.getChildExpr(0) }
@@ -394,7 +395,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent
/** Holds if this field is `readonly`. */
predicate isReadOnly() { this.hasModifier("readonly") }
override Field getSourceDeclaration() { fields(this,_,_,_,_,result) }
override Field getSourceDeclaration() { fields(this, _, _, _, _, result) }
override FieldAccess getAnAccess() { result = Variable.super.getAnAccess() }
@@ -415,7 +416,6 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent
* ```
*/
class MemberConstant extends Field, @constant {
/** Gets the computed value of this constant. */
string getValue() { constant_value(this, result) }
}
@@ -431,7 +431,6 @@ class MemberConstant extends Field, @constant {
* ```
*/
class EnumConstant extends MemberConstant {
EnumConstant() { this.getDeclaringType() instanceof Enum }
/** Gets the `enum` that declares this constant. */
@@ -448,9 +447,7 @@ class EnumConstant extends MemberConstant {
* }
* ```
*/
IntegralType getUnderlyingType() {
result = this.getDeclaringEnum().getUnderlyingType()
}
IntegralType getUnderlyingType() { result = this.getDeclaringEnum().getUnderlyingType() }
/**
* Holds if this `enum` constant has an explicit value. If not,

View File

@@ -9,7 +9,7 @@ import semmle.code.csharp.Location
library class XMLLocatableElement extends @xmllocatable, Element {
override string toString() { result = this.(XMLLocatable).toString() }
override Location getALocation() { result = this.(XMLLocatable).getALocation() }
override Location getALocation() { result = this.(XMLLocatable).getALocation() }
}
/** An XML element that has a location. */
@@ -19,15 +19,17 @@ class XMLLocatable extends @xmllocatable {
}
/** Gets the source location for this element. */
Location getALocation() { xmllocations(this,result) }
Location getALocation() { xmllocations(this, result) }
/**
* Whether this element has the specified location information,
* including file path, start line, start column, end line and end column.
*/
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f, Location l | l = this.getALocation() |
locations_default(l,f,startline,startcolumn,endline,endcolumn) and
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
filepath = f.getAbsolutePath()
)
}
@@ -48,45 +50,45 @@ class XMLParent extends @xmlparent {
abstract string getName();
/** Gets the file to which this XML parent belongs. */
XMLFile getFile() { result = this or xmlElements(this,_,_,_,result) }
XMLFile getFile() { result = this or xmlElements(this, _, _, _, result) }
/** Gets the child element at a specified index of this XML parent. */
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
/** Gets a child element of this XML parent. */
XMLElement getAChild() { xmlElements(result,_,this,_,_) }
XMLElement getAChild() { xmlElements(result, _, this, _, _) }
/** Gets a child element of this XML parent with the given `name`. */
XMLElement getAChild(string name) { xmlElements(result,_,this,_,_) and result.hasName(name) }
XMLElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
/** Gets a comment that is a child of this XML parent. */
XMLComment getAComment() { xmlComments(result,_,this,_) }
XMLComment getAComment() { xmlComments(result, _, this, _) }
/** Gets a character sequence that is a child of this XML parent. */
XMLCharacters getACharactersSet() { xmlChars(result,_,this,_,_,_) }
XMLCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
/** Gets the depth in the tree. (Overridden in XMLElement.) */
int getDepth() { result = 0 }
/** Gets the number of child XML elements of this XML parent. */
int getNumberOfChildren() {
result = count(XMLElement e | xmlElements(e,_,this,_,_))
}
int getNumberOfChildren() { result = count(XMLElement e | xmlElements(e, _, this, _, _)) }
/** Gets the number of places in the body of this XML parent where text occurs. */
int getNumberOfCharacterSets() {
result = count(int pos | xmlChars(_,_,this,pos,_,_))
}
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
/** Append all the character sequences of this XML parent from left to right, separated by a space. */
string allCharactersString() {
result = concat(string chars, int pos | xmlChars(_, chars, this, pos, _, _) | chars, " " order by pos)
result = concat(string chars, int pos |
xmlChars(_, chars, this, pos, _, _)
|
chars, " "
order by
pos
)
}
/** Gets the text value contained in this XML parent. */
string getTextValue() {
result = allCharactersString()
}
string getTextValue() { result = allCharactersString() }
/** Gets a printable representation of this XML parent. */
string toString() { result = this.getName() }
@@ -94,63 +96,59 @@ class XMLParent extends @xmlparent {
/** An XML file. */
class XMLFile extends XMLParent, File {
XMLFile() {
xmlEncoding(this,_)
}
XMLFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */
override string toString() { result = XMLParent.super.toString() }
/** Gets the name of this XML file. */
override string getName() { files(this,result,_,_,_) }
override string getName() { files(this, result, _, _, _) }
/** Gets the path of this XML file. */
string getPath() { files(this,_,result,_,_) }
string getPath() { files(this, _, result, _, _) }
/** Gets the path of the folder that contains this XML file. */
string getFolder() {
result = this.getPath().substring(0, this.getPath().length()-this.getName().length())
result = this.getPath().substring(0, this.getPath().length() - this.getName().length())
}
/** Gets the encoding of this XML file. */
string getEncoding() { xmlEncoding(this,result) }
string getEncoding() { xmlEncoding(this, result) }
/** Gets the XML file itself. */
override
XMLFile getFile() { result = this }
override XMLFile getFile() { result = this }
/** Gets a top-most element in an XML file. */
XMLElement getARootElement() { result = this.getAChild() }
/** Gets a DTD associated with this XML file. */
XMLDTD getADTD() { xmlDTDs(result,_,_,_,this) }
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
}
/** A "Document Type Definition" of an XML file. */
class XMLDTD extends XMLLocatable, @xmldtd {
/** Gets the name of the root element of this DTD. */
string getRoot() { xmlDTDs(this,result,_,_,_) }
string getRoot() { xmlDTDs(this, result, _, _, _) }
/** Gets the public ID of this DTD. */
string getPublicId() { xmlDTDs(this,_,result,_,_) }
string getPublicId() { xmlDTDs(this, _, result, _, _) }
/** Gets the system ID of this DTD. */
string getSystemId() { xmlDTDs(this,_,_,result,_) }
string getSystemId() { xmlDTDs(this, _, _, result, _) }
/** Holds if this DTD is public. */
predicate isPublic() { not xmlDTDs(this,_,"",_,_) }
predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
/** Gets the parent of this DTD. */
XMLParent getParent() { xmlDTDs(this,_,_,_,result) }
XMLParent getParent() { xmlDTDs(this, _, _, _, result) }
/** Gets a printable representation of this DTD. */
override string toString() {
(this.isPublic() and result = this.getRoot() + " PUBLIC '" +
this.getPublicId() + "' '" +
this.getSystemId() + "'") or
(not this.isPublic() and result = this.getRoot() +
" SYSTEM '" +
this.getSystemId() + "'")
this.isPublic() and
result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'"
or
not this.isPublic() and
result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'"
}
}
@@ -160,48 +158,40 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
predicate hasName(string name) { name = getName() }
/** Gets the name of this XML element. */
override string getName() { xmlElements(this,result,_,_,_) }
override string getName() { xmlElements(this, result, _, _, _) }
/** Gets the XML file in which this XML element occurs. */
override
XMLFile getFile() { xmlElements(this,_,_,_,result) }
override XMLFile getFile() { xmlElements(this, _, _, _, result) }
/** Gets the parent of this XML element. */
XMLParent getParent() { xmlElements(this,_,result,_,_) }
XMLParent getParent() { xmlElements(this, _, result, _, _) }
/** Gets the index of this XML element among its parent's children. */
int getIndex() { xmlElements(this, _, _, result, _) }
/** Holds if this XML element has a namespace. */
predicate hasNamespace() { xmlHasNs(this,_,_) }
predicate hasNamespace() { xmlHasNs(this, _, _) }
/** Gets the namespace of this XML element, if any. */
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
/** Gets the index of this XML element among its parent's children. */
int getElementPositionIndex() { xmlElements(this,_,_,result,_) }
int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
/** Gets the depth of this element within the XML file tree structure. */
override
int getDepth() { result = this.getParent().getDepth() + 1 }
override int getDepth() { result = this.getParent().getDepth() + 1 }
/** Gets an XML attribute of this XML element. */
XMLAttribute getAnAttribute() { result.getElement() = this }
/** Gets the attribute with the specified `name`, if any. */
XMLAttribute getAttribute(string name) {
result.getElement() = this and result.getName() = name
}
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
/** Holds if this XML element has an attribute with the specified `name`. */
predicate hasAttribute(string name) {
exists(XMLAttribute a| a = this.getAttribute(name))
}
predicate hasAttribute(string name) { exists(XMLAttribute a | a = this.getAttribute(name)) }
/** Gets the value of the attribute with the specified `name`, if any. */
string getAttributeValue(string name) {
result = this.getAttribute(name).getValue()
}
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
/** Gets a printable representation of this XML element. */
override string toString() { result = XMLParent.super.toString() }
@@ -210,19 +200,19 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
/** An attribute that occurs inside an XML element. */
class XMLAttribute extends @xmlattribute, XMLLocatable {
/** Gets the name of this attribute. */
string getName() { xmlAttrs(this,_,result,_,_,_) }
string getName() { xmlAttrs(this, _, result, _, _, _) }
/** Gets the XML element to which this attribute belongs. */
XMLElement getElement() { xmlAttrs(this,result,_,_,_,_) }
XMLElement getElement() { xmlAttrs(this, result, _, _, _, _) }
/** Holds if this attribute has a namespace. */
predicate hasNamespace() { xmlHasNs(this,_,_) }
predicate hasNamespace() { xmlHasNs(this, _, _) }
/** Gets the namespace of this attribute, if any. */
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
/** Gets the value of this attribute. */
string getValue() { xmlAttrs(this,_,_,result,_,_) }
string getValue() { xmlAttrs(this, _, _, result, _, _) }
/** Gets a printable representation of this XML attribute. */
override string toString() { result = this.getName() + "=" + this.getValue() }
@@ -231,27 +221,28 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
/** A namespace used in an XML file */
class XMLNamespace extends XMLLocatable, @xmlnamespace {
/** Gets the prefix of this namespace. */
string getPrefix() { xmlNs(this,result,_,_) }
string getPrefix() { xmlNs(this, result, _, _) }
/** Gets the URI of this namespace. */
string getURI() { xmlNs(this,_,result,_) }
string getURI() { xmlNs(this, _, result, _) }
/** Holds if this namespace has no prefix. */
predicate isDefault() { this.getPrefix() = "" }
override string toString() {
(this.isDefault() and result = this.getURI()) or
(not this.isDefault() and result = this.getPrefix() + ":" + this.getURI())
this.isDefault() and result = this.getURI()
or
not this.isDefault() and result = this.getPrefix() + ":" + this.getURI()
}
}
/** A comment of the form `<!-- ... -->` is an XML comment. */
class XMLComment extends @xmlcomment, XMLLocatable {
/** Gets the text content of this XML comment. */
string getText() { xmlComments(this,result,_,_) }
string getText() { xmlComments(this, result, _, _) }
/** Gets the parent of this XML comment. */
XMLParent getParent() { xmlComments(this,_,result,_) }
XMLParent getParent() { xmlComments(this, _, result, _) }
/** Gets a printable representation of this XML comment. */
override string toString() { result = this.getText() }
@@ -263,13 +254,13 @@ class XMLComment extends @xmlcomment, XMLLocatable {
*/
class XMLCharacters extends @xmlcharacters, XMLLocatable {
/** Gets the content of this character sequence. */
string getCharacters() { xmlChars(this,result,_,_,_,_) }
string getCharacters() { xmlChars(this, result, _, _, _, _) }
/** Gets the parent of this character sequence. */
XMLParent getParent() { xmlChars(this,_,result,_,_,_) }
XMLParent getParent() { xmlChars(this, _, result, _, _, _) }
/** Holds if this character sequence is CDATA. */
predicate isCDATA() { xmlChars(this,_,_,_,1,_) }
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
/** Gets a printable representation of this XML character sequence. */
override string toString() { result = this.getCharacters() }

View File

@@ -1,4 +1,5 @@
/** Provides classes for assertions. */
private import semmle.code.csharp.frameworks.system.Diagnostics
private import semmle.code.csharp.frameworks.test.VisualStudio
private import semmle.code.csharp.frameworks.System
@@ -11,29 +12,23 @@ abstract class AssertMethod extends Method {
abstract int getAssertionIndex();
/** Gets the parameter being asserted. */
final Parameter getAssertedParameter() {
result = this.getParameter(this.getAssertionIndex())
}
final Parameter getAssertedParameter() { result = this.getParameter(this.getAssertionIndex()) }
/** Gets the exception being thrown if the assertion fails, if any. */
abstract ExceptionClass getExceptionClass();
}
/** A positive assertion method. */
abstract class AssertTrueMethod extends AssertMethod {
}
abstract class AssertTrueMethod extends AssertMethod { }
/** A negated assertion method. */
abstract class AssertFalseMethod extends AssertMethod {
}
abstract class AssertFalseMethod extends AssertMethod { }
/** A `null` assertion method. */
abstract class AssertNullMethod extends AssertMethod {
}
abstract class AssertNullMethod extends AssertMethod { }
/** A non-`null` assertion method. */
abstract class AssertNonNullMethod extends AssertMethod {
}
abstract class AssertNonNullMethod extends AssertMethod { }
/** An assertion, that is, a call to an assertion method. */
class Assertion extends MethodCall {
@@ -45,17 +40,14 @@ class Assertion extends MethodCall {
AssertMethod getAssertMethod() { result = target }
/** Gets the expression that this assertion pertains to. */
Expr getExpr() {
result = this.getArgumentForParameter(target.getAssertedParameter())
}
Expr getExpr() { result = this.getArgumentForParameter(target.getAssertedParameter()) }
pragma[nomagic]
private JoinBlockPredecessor getAPossiblyDominatedPredecessor(JoinBlock jb) {
// Only calculate dominance by explicit recursion for split nodes;
// all other nodes can use regular CFG dominance
this instanceof ControlFlow::Internal::SplitControlFlowElement and
exists(BasicBlock bb |
bb = this.getAControlFlowNode().getBasicBlock() |
exists(BasicBlock bb | bb = this.getAControlFlowNode().getBasicBlock() |
result = bb.getASuccessor*()
) and
result.getASuccessor() = jb and
@@ -65,8 +57,7 @@ class Assertion extends MethodCall {
pragma[nomagic]
private predicate isPossiblyDominatedJoinBlock(JoinBlock jb) {
exists(this.getAPossiblyDominatedPredecessor(jb)) and
forall(BasicBlock pred |
pred = jb.getAPredecessor() |
forall(BasicBlock pred | pred = jb.getAPredecessor() |
pred = this.getAPossiblyDominatedPredecessor(jb)
or
jb.dominates(pred)
@@ -77,16 +68,15 @@ class Assertion extends MethodCall {
private predicate strictlyDominatesSplit(BasicBlock bb) {
this.getAControlFlowNode().getBasicBlock().immediatelyDominates(bb)
or
if bb instanceof JoinBlock then
if bb instanceof JoinBlock
then
this.isPossiblyDominatedJoinBlock(bb) and
forall(BasicBlock pred |
pred = this.getAPossiblyDominatedPredecessor(bb) |
forall(BasicBlock pred | pred = this.getAPossiblyDominatedPredecessor(bb) |
this.strictlyDominatesSplit(pred)
or
this.getAControlFlowNode().getBasicBlock() = pred
)
else
this.strictlyDominatesSplit(bb.getAPredecessor())
else this.strictlyDominatesSplit(bb.getAPredecessor())
}
/**
@@ -111,7 +101,8 @@ class FailingAssertion extends Assertion {
FailingAssertion() {
exists(AssertMethod am, Expr e |
am = this.getAssertMethod() and
e = this.getExpr() |
e = this.getExpr()
|
am instanceof AssertTrueMethod and
e.getValue() = "false"
or
@@ -140,9 +131,7 @@ class SystemDiagnosticsDebugAssertTrueMethod extends AssertTrueMethod {
/** A Visual Studio assertion method. */
class VSTestAssertTrueMethod extends AssertTrueMethod {
VSTestAssertTrueMethod() {
this = any(VSTestAssertClass c).getIsTrueMethod()
}
VSTestAssertTrueMethod() { this = any(VSTestAssertClass c).getIsTrueMethod() }
override int getAssertionIndex() { result = 0 }
@@ -151,9 +140,7 @@ class VSTestAssertTrueMethod extends AssertTrueMethod {
/** A Visual Studio negated assertion method. */
class VSTestAssertFalseMethod extends AssertFalseMethod {
VSTestAssertFalseMethod() {
this = any(VSTestAssertClass c).getIsFalseMethod()
}
VSTestAssertFalseMethod() { this = any(VSTestAssertClass c).getIsFalseMethod() }
override int getAssertionIndex() { result = 0 }
@@ -162,9 +149,7 @@ class VSTestAssertFalseMethod extends AssertFalseMethod {
/** A Visual Studio `null` assertion method. */
class VSTestAssertNullMethod extends AssertNullMethod {
VSTestAssertNullMethod() {
this = any(VSTestAssertClass c).getIsNullMethod()
}
VSTestAssertNullMethod() { this = any(VSTestAssertClass c).getIsNullMethod() }
override int getAssertionIndex() { result = 0 }
@@ -173,9 +158,7 @@ class VSTestAssertNullMethod extends AssertNullMethod {
/** A Visual Studio non-`null` assertion method. */
class VSTestAssertNonNullMethod extends AssertNonNullMethod {
VSTestAssertNonNullMethod() {
this = any(VSTestAssertClass c).getIsNotNullMethod()
}
VSTestAssertNonNullMethod() { this = any(VSTestAssertClass c).getIsNotNullMethod() }
override int getAssertionIndex() { result = 0 }
@@ -185,13 +168,13 @@ class VSTestAssertNonNullMethod extends AssertNonNullMethod {
/** A method that forwards to another assertion method. */
class ForwarderAssertMethod extends AssertMethod {
Assertion a;
Parameter p;
ForwarderAssertMethod() {
p = this.getAParameter() and
strictcount(AssignableDefinition def | def.getTarget() = p) = 1 and
forex(ControlFlowElement body |
body = this.getABody() |
forex(ControlFlowElement body | body = this.getABody() |
bodyAsserts(this, body, a) and
a.getExpr() = p.getAnAccess()
)
@@ -227,33 +210,23 @@ private Stmt getAnAssertingStmt(Assertion a) {
/** A method that forwards to a positive assertion method. */
class ForwarderAssertTrueMethod extends ForwarderAssertMethod, AssertTrueMethod {
ForwarderAssertTrueMethod() {
this.getUnderlyingAssertMethod() instanceof AssertTrueMethod
}
ForwarderAssertTrueMethod() { this.getUnderlyingAssertMethod() instanceof AssertTrueMethod }
}
/** A method that forwards to a negated assertion method. */
class ForwarderAssertFalseMethod extends ForwarderAssertMethod, AssertFalseMethod {
ForwarderAssertFalseMethod() {
this.getUnderlyingAssertMethod() instanceof AssertFalseMethod
}
ForwarderAssertFalseMethod() { this.getUnderlyingAssertMethod() instanceof AssertFalseMethod }
}
/** A method that forwards to a `null` assertion method. */
class ForwarderAssertNullMethod extends ForwarderAssertMethod, AssertNullMethod {
ForwarderAssertNullMethod() {
this.getUnderlyingAssertMethod() instanceof AssertNullMethod
}
ForwarderAssertNullMethod() { this.getUnderlyingAssertMethod() instanceof AssertNullMethod }
}
/** A method that forwards to a non-`null` assertion method. */
class ForwarderAssertNonNullMethod extends ForwarderAssertMethod, AssertNonNullMethod {
ForwarderAssertNonNullMethod() {
this.getUnderlyingAssertMethod() instanceof AssertNonNullMethod
}
ForwarderAssertNonNullMethod() { this.getUnderlyingAssertMethod() instanceof AssertNonNullMethod }
}
/** Holds if expression `e` appears in an assertion. */
predicate isExprInAssertion(Expr e) {
e = any(Assertion a).getExpr().getAChildExpr*()
}
predicate isExprInAssertion(Expr e) { e = any(Assertion a).getExpr().getAChildExpr*() }

View File

@@ -1,4 +1,5 @@
/** Provides classes for collections. */
import csharp
private string modifyMethodName() {
@@ -82,11 +83,13 @@ private string genericCollectionTypeName() {
/** A collection type. */
class CollectionType extends RefType {
CollectionType() {
exists(RefType base |
base = this.getABaseType*() |
exists(RefType base | base = this.getABaseType*() |
base.hasQualifiedName(collectionNamespaceName(), collectionTypeName())
or
base.(ConstructedType).getUnboundGeneric().hasQualifiedName(genericCollectionNamespaceName(), genericCollectionTypeName())
base
.(ConstructedType)
.getUnboundGeneric()
.hasQualifiedName(genericCollectionNamespaceName(), genericCollectionTypeName())
)
or
this instanceof ArrayType
@@ -138,10 +141,7 @@ private string noAddMethodName() {
/** Holds if `a` is an access that does not modify a collection. */
private predicate readonlyAccess(Access a) {
// A read-only method call
exists(MethodCall mc |
mc.getQualifier() = a |
mc.getTarget().hasName(readonlyMethodName())
)
exists(MethodCall mc | mc.getQualifier() = a | mc.getTarget().hasName(readonlyMethodName()))
or
// Any property access
a = any(PropertyAccess pa).getQualifier()
@@ -155,19 +155,14 @@ class NoAddAccess extends Access {
NoAddAccess() {
readonlyAccess(this)
or
exists(MethodCall mc |
mc.getQualifier() = this |
mc.getTarget().hasName(noAddMethodName())
)
exists(MethodCall mc | mc.getQualifier() = this | mc.getTarget().hasName(noAddMethodName()))
}
}
/** An access that initializes an empty collection. */
class EmptyInitializationAccess extends Access {
EmptyInitializationAccess() {
exists(AssignableDefinition def |
def.getTargetAccess() = this |
exists(AssignableDefinition def | def.getTargetAccess() = this |
def.getSource() instanceof EmptyCollectionCreation
)
}

View File

@@ -84,49 +84,44 @@ private newtype TComparisonTest =
kind.isLessThanEquals() and
first = co.getLeftOperand() and
second = co.getRightOperand()
}
or
} or
TEqualsCall(MethodCall mc) {
exists(Method m |
m = mc.getTarget() |
exists(Method m | m = mc.getTarget() |
m instanceof EqualsMethod or
m instanceof IEquatableEqualsMethod
)
}
or
} or
TStaticEqualsCall(MethodCall mc) {
exists(Method m |
m = mc.getTarget() |
exists(Method m | m = mc.getTarget() |
m = any(SystemObjectClass c).getStaticEqualsMethod() or
m = any(SystemObjectClass c).getReferenceEqualsMethod()
)
}
or
} or
TCompareToCall(MethodCall mc) {
exists(Method m, Method target |
target = mc.getTarget() and
(target = m or target = m.getAnUltimateImplementor()) |
(target = m or target = m.getAnUltimateImplementor())
|
m = any(SystemIComparableInterface i).getCompareToMethod()
or
m = any(SystemIComparableTInterface i).getAConstructedGeneric().getAMethod() and
m.getSourceDeclaration() = any(SystemIComparableTInterface i).getCompareToMethod()
)
}
or
} or
TCompareCall(MethodCall mc) {
exists(Method m, Method target |
target = mc.getTarget() and
(target = m or target = m.getAnUltimateImplementor()) |
(target = m or target = m.getAnUltimateImplementor())
|
m = any(SystemCollectionsIComparerInterface i).getCompareMethod()
or
m = any(SystemCollectionsGenericIComparerTInterface i).getAConstructedGeneric().getAMethod() and
m.getSourceDeclaration() = any(SystemCollectionsGenericIComparerTInterface i).getCompareMethod()
m.getSourceDeclaration() = any(SystemCollectionsGenericIComparerTInterface i)
.getCompareMethod()
)
}
or
} or
TComparisonOperatorCall(OperatorCall oc, ComparisonKind kind, Expr first, Expr second) {
exists(Operator o |
o = oc.getTarget() |
exists(Operator o | o = oc.getTarget() |
o instanceof EQOperator and
kind.isEquality() and
first = oc.getArgument(0) and
@@ -157,15 +152,16 @@ private newtype TComparisonTest =
first = oc.getArgument(0) and
second = oc.getArgument(1)
)
}
or
} or
TCompareWithConstant(ComparisonTest outer, ComparisonKind kind, Expr first, Expr second) {
exists(ComparisonKind outerKind, ComparisonTest compare, int i |
compare.getComparisonKind().isCompare() and
outerKind = outer.getComparisonKind() and
outer.getAnArgument() = compare.getExpr() and
i = outer.getAnArgument().getValue().toInt() |
outerKind.isEquality() and (
i = outer.getAnArgument().getValue().toInt()
|
outerKind.isEquality() and
(
// `x.CompareTo(y) == 0` => `x = y`
i = 0 and
kind.isEquality() and
@@ -185,8 +181,10 @@ private newtype TComparisonTest =
second = compare.getSecondArgument()
)
or
outerKind.isLessThan() and (
outer.getFirstArgument() = compare.getExpr() and (
outerKind.isLessThan() and
(
outer.getFirstArgument() = compare.getExpr() and
(
// `x.CompareTo(y) < 1` => `x <= y`
i = 1 and
kind.isLessThanEquals() and
@@ -200,7 +198,8 @@ private newtype TComparisonTest =
second = compare.getSecondArgument()
)
or
outer.getSecondArgument() = compare.getExpr() and (
outer.getSecondArgument() = compare.getExpr() and
(
// `-1 < x.CompareTo(y)` => `x >= y`
i = -1 and
kind.isLessThanEquals() and
@@ -215,8 +214,10 @@ private newtype TComparisonTest =
)
)
or
outerKind.isLessThanEquals() and (
outer.getFirstArgument() = compare.getExpr() and (
outerKind.isLessThanEquals() and
(
outer.getFirstArgument() = compare.getExpr() and
(
// `x.CompareTo(y) <= 0` => `x <= y`
i = 0 and
kind.isLessThanEquals() and
@@ -230,7 +231,8 @@ private newtype TComparisonTest =
second = compare.getSecondArgument()
)
or
outer.getSecondArgument() = compare.getExpr() and (
outer.getSecondArgument() = compare.getExpr() and
(
// `0 <= x.CompareTo(y)` => `x >= y`
i = 0 and
kind.isLessThanEquals() and
@@ -262,12 +264,18 @@ class ComparisonTest extends TComparisonTest {
/** Gets the comparison kind. */
final ComparisonKind getComparisonKind() {
this = TComparisonOperation(_, result, _, _) or
this = TEqualsCall(_) and result.isEquality() or
this = TCompareToCall(_) and result.isCompare() or
this = TStaticEqualsCall(_) and result.isEquality() or
this = TCompareCall(_) and result.isCompare() or
this = TComparisonOperatorCall(_, result, _, _) or
this = TComparisonOperation(_, result, _, _)
or
this = TEqualsCall(_) and result.isEquality()
or
this = TCompareToCall(_) and result.isCompare()
or
this = TStaticEqualsCall(_) and result.isEquality()
or
this = TCompareCall(_) and result.isCompare()
or
this = TComparisonOperatorCall(_, result, _, _)
or
this = TCompareWithConstant(_, result, _, _)
}

View File

@@ -4,25 +4,26 @@
* Provides functionality for validating that the database and library are in a
* consistent state.
*/
import csharp
private predicate missingLocation(Element e, string m) {
(
e instanceof Declaration
or e instanceof Expr
or e instanceof Stmt
)
and not e instanceof ImplicitAccessorParameter
and not e instanceof NullType
and not e instanceof Parameter // Bug in Roslyn - params occasionally lack locations
and not e.(Operator).getDeclaringType() instanceof IntType // Roslyn quirk
and not e instanceof Constructor
and not e instanceof ArrayType
and not e instanceof UnknownType
and not e instanceof ArglistType
and not exists(TupleType t | e=t or e=t.getAField())
and not exists(e.getLocation())
and m = "Element does not have a location"
e instanceof Declaration or
e instanceof Expr or
e instanceof Stmt
) and
not e instanceof ImplicitAccessorParameter and
not e instanceof NullType and
not e instanceof Parameter and // Bug in Roslyn - params occasionally lack locations
not e.(Operator).getDeclaringType() instanceof IntType and // Roslyn quirk
not e instanceof Constructor and
not e instanceof ArrayType and
not e instanceof UnknownType and
not e instanceof ArglistType and
not exists(TupleType t | e = t or e = t.getAField()) and
not exists(e.getLocation()) and
m = "Element does not have a location"
}
private predicate inconsistentGeneric(ConstructedGeneric g, string m) {
@@ -40,21 +41,18 @@ module SsaChecks {
import Ssa
predicate nonUniqueSsaDef(AssignableRead read, string m) {
exists(ControlFlow::Node cfn |
strictcount(Definition def | def.getAReadAtNode(cfn) = read) > 1
)
and
exists(ControlFlow::Node cfn | strictcount(Definition def | def.getAReadAtNode(cfn) = read) > 1) and
m = "Read is associated with multiple SSA definitions"
}
predicate notDominatedByDef(AssignableRead read, string m) {
exists(Definition def, BasicBlock bb, ControlFlow::Node rnode, ControlFlow::Node dnode, int i |
def.getAReadAtNode(rnode) = read |
def.getAReadAtNode(rnode) = read
|
def.definesAt(bb, i) and
dnode = bb.getNode(max(int j | j = i or j = 0)) and
not dnode.dominates(rnode)
)
and
) and
m = "Read is not dominated by SSA definition"
}
@@ -63,14 +61,14 @@ module SsaChecks {
// local variables should not have an SSA definition, as that would imply that
// the declaration is live (can reach a use without passing through a definition)
exists(ExplicitDefinition def |
d = def.getADefinition().(AssignableDefinitions::LocalVariableDefinition).getDeclaration() |
d = def.getADefinition().(AssignableDefinitions::LocalVariableDefinition).getDeclaration()
|
not d = any(ForeachStmt fs).getVariableDeclExpr() and
not d = any(SpecificCatchClause scc).getVariableDeclExpr() and
not d.getVariable().getType() instanceof Struct and
not d = any(TypeCase ts).getVariableDeclExpr() and
not d = any(IsPatternExpr ipe).getVariableDeclExpr()
)
and
) and
m = "Local variable declaration has unexpected SSA definition"
}
@@ -83,8 +81,7 @@ module SsaChecks {
module CfgChecks {
predicate multipleSuccessors(ControlFlowElement cfe, string m) {
exists(ControlFlow::Node cfn |
cfn = cfe.getAControlFlowNode() |
exists(ControlFlow::Node cfn | cfn = cfe.getAControlFlowNode() |
strictcount(cfn.getASuccessorByType(any(ControlFlow::SuccessorTypes::NormalSuccessor e))) > 1 and
m = "Multiple (non-conditional/exceptional) successors"
)

View File

@@ -1,4 +1,5 @@
/** Provides logic for determining constant expressions. */
import csharp
private import semmle.code.csharp.commons.ComparisonTest
private import semmle.code.csharp.commons.StructuralComparison as StructuralComparison
@@ -7,21 +8,25 @@ private import semmle.code.csharp.commons.StructuralComparison as StructuralComp
* Holds if `e` is a condition that always evaluates to Boolean value `b`.
*/
predicate isConstantCondition(Expr e, boolean b) {
forex(ControlFlow::Node cfn |
cfn = e.getAControlFlowNode() |
exists(cfn.getASuccessorByType(any(ControlFlow::SuccessorTypes::BooleanSuccessor t | t.getValue() = b))) and
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() |
exists(
cfn
.getASuccessorByType(any(ControlFlow::SuccessorTypes::BooleanSuccessor t |
t.getValue() = b
))
) and
strictcount(ControlFlow::SuccessorType t | exists(cfn.getASuccessorByType(t))) = 1
)
}
/**
* Holds if comparison operation `co` is constant with the Boolean value `b`.
* For example, the comparison `x > x` is constantly `false` in
*
* ```
* int MaxWrong(int x, int y) => x > x ? x : y;
* ```
*/
* Holds if comparison operation `co` is constant with the Boolean value `b`.
* For example, the comparison `x > x` is constantly `false` in
*
* ```
* int MaxWrong(int x, int y) => x > x ? x : y;
* ```
*/
predicate isConstantComparison(ComparisonOperation co, boolean b) {
co.getValue() = "true" and
b = true
@@ -38,26 +43,18 @@ predicate isConstantComparison(ComparisonOperation co, boolean b) {
private module ConstantComparisonOperation {
private import semmle.code.csharp.commons.ComparisonTest
private SimpleType convertedType(Expr expr) {
result = expr.stripImplicitCasts().getType()
}
private SimpleType convertedType(Expr expr) { result = expr.stripImplicitCasts().getType() }
private int maxValue(Expr expr) {
if
convertedType(expr) instanceof IntegralType and exists(expr.getValue())
then
result = expr.getValue().toInt()
else
result = convertedType(expr).maxValue()
if convertedType(expr) instanceof IntegralType and exists(expr.getValue())
then result = expr.getValue().toInt()
else result = convertedType(expr).maxValue()
}
private int minValue(Expr expr) {
if
convertedType(expr) instanceof IntegralType and exists(expr.getValue())
then
result = expr.getValue().toInt()
else
result = convertedType(expr).minValue()
if convertedType(expr) instanceof IntegralType and exists(expr.getValue())
then result = expr.getValue().toInt()
else result = convertedType(expr).minValue()
}
/** Holds if the comparison test `cmp` is constant with the value `value`. */
@@ -66,7 +63,7 @@ private module ConstantComparisonOperation {
e = cmp.getExpr() and
l = cmp.getFirstArgument() and
r = cmp.getSecondArgument()
|
|
cmp.getComparisonKind().isLessThan() and
maxValue(l) < minValue(r) and
value = true
@@ -85,13 +82,17 @@ private module ConstantComparisonOperation {
or
// Operands are unequal
(maxValue(l) < minValue(r) or maxValue(r) < minValue(l)) and
(cmp.getComparisonKind().isInequality() and value = true or cmp.getComparisonKind().isEquality() and value = false)
(
cmp.getComparisonKind().isInequality() and value = true
or
cmp.getComparisonKind().isEquality() and value = false
)
or
exists(LocalScopeVariable v |
l.(VariableRead).getTarget() = v and
r.(VariableRead).getTarget() = v and
not v.getType() instanceof FloatingPointType // One of the arguments may be NaN
|
|
cmp.getComparisonKind().isLessThan() and value = false
or
cmp.getComparisonKind().isLessThanEquals() and value = true
@@ -105,24 +106,19 @@ private module ConstantComparisonOperation {
}
private class StructuralComparisonConfig extends StructuralComparison::StructuralComparisonConfiguration {
StructuralComparisonConfig() {
this = "CompareIdenticalValues"
}
StructuralComparisonConfig() { this = "CompareIdenticalValues" }
override predicate candidate(Element x, Element y) {
exists(ComparisonTest ct |
x = ct.getFirstArgument()
and
x = ct.getFirstArgument() and
y = ct.getSecondArgument()
)
}
ComparisonTest getComparisonTest() {
exists(Element x, Element y |
result.getFirstArgument() = x
and
result.getSecondArgument() = y
and
result.getFirstArgument() = x and
result.getSecondArgument() = y and
same(x, y)
)
}
@@ -144,20 +140,17 @@ predicate comparesIdenticalValues(ComparisonTest ct) {
*/
predicate comparesIdenticalValuesNan(ComparisonTest ct, string builtin) {
comparesIdenticalValues(ct) and
exists(FloatingPointType fpt, string type, string neg |
fpt = ct.getAnArgument().getType() |
exists(FloatingPointType fpt, string type, string neg | fpt = ct.getAnArgument().getType() |
(
fpt instanceof DoubleType and type = "double"
or
fpt instanceof FloatType and type = "float"
)
and
) and
(
ct.getComparisonKind().isEquality() and neg = "!"
or
ct.getComparisonKind().isInequality() and neg = ""
)
and
) and
builtin = neg + type + ".IsNaN()"
)
}

View File

@@ -37,21 +37,24 @@ private predicate disposedCilVariable(CIL::Variable variable) {
private predicate disposedCSharpVariable(Variable variable) {
// A C# parameter is disposed if its corresponding CIL parameter is disposed
exists(CIL::Method m, CIL::Parameter p, int i |
disposedCilVariable(p) and p = m.getRawParameter(i) |
disposedCilVariable(p) and p = m.getRawParameter(i)
|
variable = any(Callable c2 | c2.matchesHandle(m)).getRawParameter(i)
)
or
// Call to a method that disposes it
exists(Call call, int arg, VariableRead read |
read.getTarget() = variable and
read = call.getArgument(arg) |
read = call.getArgument(arg)
|
disposedCSharpVariable(call.getTarget().getParameter(arg))
)
or
// Call to `Dispose`
exists(MethodCall call, VariableRead read |
read.getTarget() = variable and
read = call.getQualifier() |
read = call.getQualifier()
|
isDisposeMethod(call.getTarget())
)
or
@@ -60,8 +63,8 @@ private predicate disposedCSharpVariable(Variable variable) {
or
// A variable is disposed if it's assigned to another variable that is disposed
exists(AssignableDefinition assign |
assign.getSource() = variable.getAnAccess()
and disposedCSharpVariable(assign.getTarget())
assign.getSource() = variable.getAnAccess() and
disposedCSharpVariable(assign.getTarget())
)
}

View File

@@ -6,39 +6,28 @@ private import semmle.code.csharp.frameworks.system.codedom.Compiler
/** A source file that contains generated code. */
abstract class GeneratedCodeFile extends SourceFile { }
/** An auto-generated Designer file.*/
/** An auto-generated Designer file. */
class DesignerFile extends GeneratedCodeFile {
DesignerFile() {
this.getBaseName().toLowerCase().matches("%.designer.cs")
}
DesignerFile() { this.getBaseName().toLowerCase().matches("%.designer.cs") }
}
/** An auto-generated SpecFlow feature file. */
class FeatureFile extends GeneratedCodeFile {
FeatureFile() {
this.getBaseName().toLowerCase().matches("%.feature.cs")
}
FeatureFile() { this.getBaseName().toLowerCase().matches("%.feature.cs") }
}
/** An auto-generated XAML code file. */
class XamlFile extends GeneratedCodeFile {
XamlFile() {
this.getBaseName().matches("%.g.cs")
}
}
class XamlFile extends GeneratedCodeFile { XamlFile() { this.getBaseName().matches("%.g.cs") } }
/** An auto-generated XSD code file. */
class AutogenXsdFile extends GeneratedCodeFile {
AutogenXsdFile() {
this.getBaseName().matches("%.autogen.cs")
}
AutogenXsdFile() { this.getBaseName().matches("%.autogen.cs") }
}
/** An auto-generated CodeDOM file. */
class GeneratedAttributeFile extends GeneratedCodeFile {
GeneratedAttributeFile() {
exists(Attribute a |
a.getType() instanceof SystemCodeDomCompilerGeneratedCodeAttributeClass |
exists(Attribute a | a.getType() instanceof SystemCodeDomCompilerGeneratedCodeAttributeClass |
a.getFile() = this
)
}
@@ -46,20 +35,16 @@ class GeneratedAttributeFile extends GeneratedCodeFile {
/** A file auto-generated by `sgen.exe`. */
class GeneratedNamespaceFile extends GeneratedCodeFile {
GeneratedNamespaceFile()
{
exists(Namespace n |
n.getATypeDeclaration().getFile() = this |
GeneratedNamespaceFile() {
exists(Namespace n | n.getATypeDeclaration().getFile() = this |
n.getQualifiedName() = "Microsoft.Xml.Serialization.GeneratedAssembly"
)
}
}
/** A file contining comments suggesting it contains generated code.*/
/** A file contining comments suggesting it contains generated code. */
class GeneratedCommentFile extends GeneratedCodeFile {
GeneratedCommentFile() {
this = any(GeneratedCodeComment c).getLocation().getFile()
}
GeneratedCommentFile() { this = any(GeneratedCodeComment c).getLocation().getFile() }
}
/** A comment line that indicates generated code. */
@@ -70,12 +55,13 @@ abstract class GeneratedCodeComment extends CommentLine { }
*/
class GenericGeneratedCodeComment extends GeneratedCodeComment {
GenericGeneratedCodeComment() {
exists(string line, string entity, string was, string automatically |
line = getText() |
exists(string line, string entity, string was, string automatically | line = getText() |
entity = "file|class|interface|art[ei]fact|module|script" and
was = "was|is|has been" and
automatically = "automatically |mechanically |auto[- ]?" and
line.regexpMatch("(?i).*\\bThis (" + entity + ") (" + was + ") (" + automatically + ")?generated\\b.*")
line
.regexpMatch("(?i).*\\bThis (" + entity + ") (" + was + ") (" + automatically +
")?generated\\b.*")
)
}
}
@@ -83,8 +69,7 @@ class GenericGeneratedCodeComment extends GeneratedCodeComment {
/** A comment warning against modifications. */
class DontModifyMarkerComment extends GeneratedCodeComment {
DontModifyMarkerComment() {
exists(string line |
line = getText() |
exists(string line | line = getText() |
line.regexpMatch("(?i).*\\bGenerated by\\b.*\\bDo not edit\\b.*") or
line.regexpMatch("(?i).*\\bAny modifications to this file will be lost\\b.*")
)

View File

@@ -1,9 +1,6 @@
/** Provides classes associated with logging frameworks. */
import csharp
/** A logger type that extends from an `ILogger` type. */
class LoggerType extends RefType {
LoggerType() {
this.getABaseType*().hasName("ILogger")
}
}
class LoggerType extends RefType { LoggerType() { this.getABaseType*().hasName("ILogger") } }

View File

@@ -7,7 +7,6 @@ private import semmle.code.csharp.frameworks.Format
private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.frameworks.system.Text
/**
* An expression that appears in a context where an implicit `ToString()`
* invocation will take place, unless the expression is already a string.
@@ -26,23 +25,23 @@ class ImplicitToStringExpr extends Expr {
ImplicitToStringExpr() {
exists(Parameter p, Method m |
this = getAnAssignedArgumentOrParam(p) and
m = p.getCallable() |
m = p.getCallable()
|
m = any(SystemTextStringBuilderClass c).getAMethod() and
m.getName().regexpMatch("Append(Line)?")
or
p instanceof StringFormatItemParameter and
not p.getType() = any(ArrayType at |
at.getElementType() instanceof ObjectType and
this.getType().isImplicitlyConvertibleTo(at)
)
at.getElementType() instanceof ObjectType and
this.getType().isImplicitlyConvertibleTo(at)
)
or
m = any(SystemClass c | c.hasName("Console")).getAMethod() and
m.getName().regexpMatch("Write(Line)?") and
p.getPosition() = 0
)
or
exists(AddExpr add, Expr o |
o = add.getAnOperand() |
exists(AddExpr add, Expr o | o = add.getAnOperand() |
o.stripImplicitCasts().getType() instanceof StringType and
this = add.getOtherOperand(o)
)
@@ -55,8 +54,7 @@ private Expr getAnAssignedArgumentOrParam(Parameter p) {
result = p.getAnAssignedArgument()
or
p.isParams() and
exists(MethodCall mc, int i |
mc.getTarget().getAParameter() = p |
exists(MethodCall mc, int i | mc.getTarget().getAParameter() = p |
result = mc.getArgument(i) and
i >= p.getPosition()
)

View File

@@ -2,6 +2,7 @@
* Provides functionality for performing structural comparison of
* expressions and statements.
*/
import csharp
/** Gets the declaration referenced by the expression `e`, if any. */
@@ -21,10 +22,9 @@ private int elementKind(Element e) {
}
private int getNumberOfActualChildren(Element e) {
if e.(MemberAccess).targetIsThisInstance() then
result = e.getNumberOfChildren() - 1
else
result = e.getNumberOfChildren()
if e.(MemberAccess).targetIsThisInstance()
then result = e.getNumberOfChildren() - 1
else result = e.getNumberOfChildren()
}
/**
@@ -61,68 +61,53 @@ abstract class StructuralComparisonConfiguration extends string {
(
candidate(x, y)
or
exists(Element xParent, Element yParent, int i |
candidateInternal(xParent, yParent) |
hasChild(xParent, i, x)
and
exists(Element xParent, Element yParent, int i | candidateInternal(xParent, yParent) |
hasChild(xParent, i, x) and
hasChild(yParent, i, y)
)
)
}
pragma [noinline]
private predicate hasChild(Element e, int i, Element child) {
child = e.getChild(i)
}
pragma[noinline]
private predicate hasChild(Element e, int i, Element child) { child = e.getChild(i) }
private predicate sameByValue(Expr x, Expr y) {
sameByValueAux(x, y, y.getValue())
}
private predicate sameByValue(Expr x, Expr y) { sameByValueAux(x, y, y.getValue()) }
pragma [noinline]
pragma[noinline]
private predicate sameByValueAux(Expr x, Expr y, string value) {
candidateInternal(x, y) and
value = x.getValue()
}
pragma [nomagic]
pragma[nomagic]
private predicate sameByStructure(Element x, Element y) {
// At least one of `x` and `y` must not have a value, they must have
// the same kind, and the same number of children
sameByStructureCandidate(x, y, elementKind(y), getNumberOfActualChildren(y))
and
sameByStructureCandidate(x, y, elementKind(y), getNumberOfActualChildren(y)) and
// If one of them has a reference attribute, they should both reference
// the same node
(exists(referenceAttribute(x)) implies
referenceAttribute(x) = referenceAttribute(y))
and
(exists(referenceAttribute(x)) implies referenceAttribute(x) = referenceAttribute(y)) and
// x is a member access on `this` iff y is
(x.(MemberAccess).targetIsThisInstance() implies
y.(MemberAccess).targetIsThisInstance())
and
(y.(MemberAccess).targetIsThisInstance() implies
x.(MemberAccess).targetIsThisInstance())
and
(x.(MemberAccess).targetIsThisInstance() implies y.(MemberAccess).targetIsThisInstance()) and
(y.(MemberAccess).targetIsThisInstance() implies x.(MemberAccess).targetIsThisInstance()) and
// All of their corresponding children must be structurally equal
forall(int i, Element xc |
xc = x.getChild(i) and
// exclude `this` qualifier, which has been checked above
not (i = -1 and x.(MemberAccess).targetIsThisInstance()) |
not (i = -1 and x.(MemberAccess).targetIsThisInstance())
|
sameInternal(xc, y.getChild(i))
)
}
private predicate sameByStructureCandidate(Element x, Element y, int elementKind, int children) {
candidateInternal(x, y)
and
elementKind = elementKind(x)
and
children = getNumberOfActualChildren(x)
and
candidateInternal(x, y) and
elementKind = elementKind(x) and
children = getNumberOfActualChildren(x) and
not (x.(Expr).hasValue() and y.(Expr).hasValue())
}
pragma [nomagic]
pragma[nomagic]
private predicate sameInternal(Element x, Element y) {
sameByValue(x, y)
or
@@ -135,8 +120,7 @@ abstract class StructuralComparisonConfiguration extends string {
* `candidate(x, y)` must hold.
*/
predicate same(Element x, Element y) {
candidate(x, y)
and
candidate(x, y) and
sameInternal(x, y)
}
}
@@ -188,68 +172,53 @@ module Internal {
(
candidate(x, y)
or
exists(Element xParent, Element yParent, int i |
candidateInternal(xParent, yParent) |
hasChild(xParent, i, x)
and
exists(Element xParent, Element yParent, int i | candidateInternal(xParent, yParent) |
hasChild(xParent, i, x) and
hasChild(yParent, i, y)
)
)
}
pragma [noinline]
private predicate hasChild(Element e, int i, Element child) {
child = e.getChild(i)
}
pragma[noinline]
private predicate hasChild(Element e, int i, Element child) { child = e.getChild(i) }
private predicate sameByValue(Expr x, Expr y) {
sameByValueAux(x, y, y.getValue())
}
private predicate sameByValue(Expr x, Expr y) { sameByValueAux(x, y, y.getValue()) }
pragma [noinline]
pragma[noinline]
private predicate sameByValueAux(Expr x, Expr y, string value) {
candidateInternal(x, y) and
value = x.getValue()
}
pragma [nomagic]
pragma[nomagic]
private predicate sameByStructure(Element x, Element y) {
// At least one of `x` and `y` must not have a value, they must have
// the same kind, and the same number of children
sameByStructureCandidate(x, y, elementKind(y), getNumberOfActualChildren(y))
and
sameByStructureCandidate(x, y, elementKind(y), getNumberOfActualChildren(y)) and
// If one of them has a reference attribute, they should both reference
// the same node
(exists(referenceAttribute(x)) implies
referenceAttribute(x) = referenceAttribute(y))
and
(exists(referenceAttribute(x)) implies referenceAttribute(x) = referenceAttribute(y)) and
// x is a member access on `this` iff y is
(x.(MemberAccess).targetIsThisInstance() implies
y.(MemberAccess).targetIsThisInstance())
and
(y.(MemberAccess).targetIsThisInstance() implies
x.(MemberAccess).targetIsThisInstance())
and
(x.(MemberAccess).targetIsThisInstance() implies y.(MemberAccess).targetIsThisInstance()) and
(y.(MemberAccess).targetIsThisInstance() implies x.(MemberAccess).targetIsThisInstance()) and
// All of their corresponding children must be structurally equal
forall(int i, Element xc |
xc = x.getChild(i) and
// exclude `this` qualifier, which has been checked above
not (i = -1 and x.(MemberAccess).targetIsThisInstance()) |
not (i = -1 and x.(MemberAccess).targetIsThisInstance())
|
sameInternal(xc, y.getChild(i))
)
}
private predicate sameByStructureCandidate(Element x, Element y, int elementKind, int children) {
candidateInternal(x, y)
and
elementKind = elementKind(x)
and
children = getNumberOfActualChildren(x)
and
candidateInternal(x, y) and
elementKind = elementKind(x) and
children = getNumberOfActualChildren(x) and
not (x.(Expr).hasValue() and y.(Expr).hasValue())
}
pragma [nomagic]
pragma[nomagic]
private predicate sameInternal(Element x, Element y) {
sameByValue(x, y)
or
@@ -262,8 +231,7 @@ module Internal {
* `candidate(x, y)` must hold.
*/
predicate same(Element x, Element y) {
candidate(x, y)
and
candidate(x, y) and
sameInternal(x, y)
}
}

View File

@@ -25,9 +25,7 @@ class TargetFrameworkAttribute extends Attribute {
* ```
* is `".NETFramework,Version=v4.6.1"`.
*/
string getFrameworkName() {
result = this.getArgument(0).getValue()
}
string getFrameworkName() { result = this.getArgument(0).getValue() }
private string frameworkCapture(int n) {
result = this.getFrameworkName().regexpCapture("([^,]+),Version=v(.+)", n)
@@ -40,9 +38,7 @@ class TargetFrameworkAttribute extends Attribute {
* ```
* is `".NETFramework"`. Other framework types include `".NETStandard"` and `".NETCoreApp"`.
*/
string getFrameworkType() {
result = this.frameworkCapture(1)
}
string getFrameworkType() { result = this.frameworkCapture(1) }
/**
* Gets the framework version of this attribute. For example, the framework version of
@@ -52,29 +48,20 @@ class TargetFrameworkAttribute extends Attribute {
* is `"4.6.1"`. Note that you can use the `Version` class to compare versions, for example
* `target.getFrameworkVersion().isEarlierThan("4.6")`.
*/
Version getFrameworkVersion() {
result = this.frameworkCapture(2)
}
Version getFrameworkVersion() { result = this.frameworkCapture(2) }
/** Holds if the framework type is .NET Desktop. */
predicate isNetFramework() {
this.getFrameworkType() = ".NETFramework"
}
predicate isNetFramework() { this.getFrameworkType() = ".NETFramework" }
/** Holds if the framework type is .NET Standard. */
predicate isNetStandard() {
this.getFrameworkType() = ".NETStandard" }
predicate isNetStandard() { this.getFrameworkType() = ".NETStandard" }
/** Holds if the framework type is .NET Core. */
predicate isNetCore() {
this.getFrameworkType() = ".NETCoreApp"
}
predicate isNetCore() { this.getFrameworkType() = ".NETCoreApp" }
/**
* Holds if element `e` specifies this target version, because it is
* compiled in the assembly of this attribute.
*/
predicate hasElement(Element e) {
assembly = e.getALocation()
}
predicate hasElement(Element e) { assembly = e.getALocation() }
}

View File

@@ -8,9 +8,8 @@ class MainMethod extends Method {
this.hasName("Main") and
this.isStatic() and
(this.getReturnType() instanceof VoidType or this.getReturnType() instanceof IntType) and
if this.getNumberOfParameters() = 1 then
this.getParameter(0).getType().(ArrayType).getElementType() instanceof StringType
else
this.getNumberOfParameters() = 0
if this.getNumberOfParameters() = 1
then this.getParameter(0).getType().(ArrayType).getElementType() instanceof StringType
else this.getNumberOfParameters() = 0
}
}

View File

@@ -11,9 +11,7 @@ private import ControlFlow::SuccessorTypes
*/
class BasicBlock extends TBasicBlockStart {
/** Gets an immediate successor of this basic block, if any. */
BasicBlock getASuccessor() {
result.getFirstNode() = getLastNode().getASuccessor()
}
BasicBlock getASuccessor() { result.getFirstNode() = getLastNode().getASuccessor() }
/** Gets an immediate successor of this basic block of a given type, if any. */
BasicBlock getASuccessorByType(ControlFlow::SuccessorType t) {
@@ -21,9 +19,7 @@ class BasicBlock extends TBasicBlockStart {
}
/** Gets an immediate predecessor of this basic block, if any. */
BasicBlock getAPredecessor() {
result.getASuccessor() = this
}
BasicBlock getAPredecessor() { result.getASuccessor() = this }
/** Gets an immediate predecessor of this basic block of a given type, if any. */
BasicBlock getAPredecessorByType(ControlFlow::SuccessorType t) {
@@ -46,9 +42,7 @@ class BasicBlock extends TBasicBlockStart {
* The basic block on line 2 is an immediate `true` successor of the
* basic block on line 1.
*/
BasicBlock getATrueSuccessor() {
result.getFirstNode() = getLastNode().getATrueSuccessor()
}
BasicBlock getATrueSuccessor() { result.getFirstNode() = getLastNode().getATrueSuccessor() }
/**
* Gets an immediate `false` successor, if any.
@@ -66,9 +60,7 @@ class BasicBlock extends TBasicBlockStart {
* The basic block on line 2 is an immediate `false` successor of the
* basic block on line 1.
*/
BasicBlock getAFalseSuccessor() {
result.getFirstNode() = getLastNode().getAFalseSuccessor()
}
BasicBlock getAFalseSuccessor() { result.getFirstNode() = getLastNode().getAFalseSuccessor() }
/**
* Gets an immediate `null` successor, if any.
@@ -86,8 +78,7 @@ class BasicBlock extends TBasicBlockStart {
* The node on line 2 is an immediate `null` successor of the node
* `x` on line 1.
*/
deprecated
BasicBlock getANullSuccessor() {
deprecated BasicBlock getANullSuccessor() {
result.getFirstNode() = getLastNode().getANullSuccessor()
}
@@ -106,8 +97,7 @@ class BasicBlock extends TBasicBlockStart {
* The node `x?.M()`, representing the call to `M`, is a non-`null` successor
* of the node `x`.
*/
deprecated
BasicBlock getANonNullSuccessor() {
deprecated BasicBlock getANonNullSuccessor() {
result.getFirstNode() = getLastNode().getANonNullSuccessor()
}
@@ -115,29 +105,19 @@ class BasicBlock extends TBasicBlockStart {
ControlFlow::Node getNode(int pos) { bbIndex(getFirstNode(), result, pos) }
/** Gets a control flow node in this basic block. */
ControlFlow::Node getANode() {
result = getNode(_)
}
ControlFlow::Node getANode() { result = getNode(_) }
/** Gets the first control flow node in this basic block. */
ControlFlow::Node getFirstNode() {
this = TBasicBlockStart(result)
}
ControlFlow::Node getFirstNode() { this = TBasicBlockStart(result) }
/** Gets the last control flow node in this basic block. */
ControlFlow::Node getLastNode() {
result = getNode(length() - 1)
}
ControlFlow::Node getLastNode() { result = getNode(length() - 1) }
/** Gets the callable that this basic block belongs to. */
Callable getCallable() {
result = this.getAPredecessor().getCallable()
}
Callable getCallable() { result = this.getAPredecessor().getCallable() }
/** Gets the length of this basic block. */
int length() {
result = strictcount(getANode())
}
int length() { result = strictcount(getANode()) }
/**
* Holds if this basic block immediately dominates basic block `bb`.
@@ -160,9 +140,7 @@ class BasicBlock extends TBasicBlockStart {
* basic block on line 4 (all paths from the entry point of `M`
* to `return s.Length;` must go through the null check).
*/
predicate immediatelyDominates(BasicBlock bb) {
bbIDominates(this, bb)
}
predicate immediatelyDominates(BasicBlock bb) { bbIDominates(this, bb) }
/**
* Holds if this basic block strictly dominates basic block `bb`.
@@ -185,9 +163,7 @@ class BasicBlock extends TBasicBlockStart {
* basic block on line 4 (all paths from the entry point of `M`
* to `return s.Length;` must go through the null check).
*/
predicate strictlyDominates(BasicBlock bb) {
bbIDominates+(this, bb)
}
predicate strictlyDominates(BasicBlock bb) { bbIDominates+(this, bb) }
/**
* Holds if this basic block dominates basic block `bb`.
@@ -247,10 +223,7 @@ class BasicBlock extends TBasicBlockStart {
/**
* Holds if this basic block dominates a predecessor of `df`.
*/
private
predicate dominatesPredecessor(BasicBlock df) {
dominates(df.getAPredecessor())
}
private predicate dominatesPredecessor(BasicBlock df) { dominates(df.getAPredecessor()) }
/**
* Gets the basic block that immediately dominates this basic block, if any.
@@ -274,9 +247,7 @@ class BasicBlock extends TBasicBlockStart {
* to `return s.Length;` must go through the null check, and the null check
* is an immediate predecessor of `return s.Length;`).
*/
BasicBlock getImmediateDominator() {
bbIDominates(result, this)
}
BasicBlock getImmediateDominator() { bbIDominates(result, this) }
/**
* Holds if this basic block strictly post-dominates basic block `bb`.
@@ -302,9 +273,7 @@ class BasicBlock extends TBasicBlockStart {
* line 3 (all paths to the exit point of `M` from `return s.Length;`
* must go through the `WriteLine` call).
*/
predicate strictlyPostDominates(BasicBlock bb) {
bbIPostDominates+(this, bb)
}
predicate strictlyPostDominates(BasicBlock bb) { bbIPostDominates+(this, bb) }
/**
* Holds if this basic block post-dominates basic block `bb`.
@@ -343,28 +312,23 @@ class BasicBlock extends TBasicBlockStart {
* even if this basic block is syntactically inside a `while` loop if the
* necessary back edges are unreachable.
*/
predicate inLoop() {
this.getASuccessor+() = this
}
predicate inLoop() { this.getASuccessor+() = this }
/** Gets a textual representation of this basic block. */
string toString() {
result = getFirstNode().toString()
}
string toString() { result = getFirstNode().toString() }
/** Gets the location of this basic block. */
Location getLocation() {
result = getFirstNode().getLocation()
}
Location getLocation() { result = getFirstNode().getLocation() }
}
/**
* Internal implementation details.
*/
private cached module Internal {
cached
private module Internal {
/** Internal representation of basic blocks. */
cached newtype TBasicBlock =
TBasicBlockStart(ControlFlow::Node cfn) { startsBB(cfn) }
cached
newtype TBasicBlock = TBasicBlockStart(ControlFlow::Node cfn) { startsBB(cfn) }
/** Holds if `cfn` starts a new basic block. */
private predicate startsBB(ControlFlow::Node cfn) {
@@ -372,7 +336,9 @@ private cached module Internal {
or
cfn.isJoin()
or
exists(ControlFlow::Node pred | pred = cfn.getAPredecessor() | strictcount(pred.getASuccessor()) > 1)
exists(ControlFlow::Node pred | pred = cfn.getAPredecessor() |
strictcount(pred.getASuccessor()) > 1
)
}
/**
@@ -398,9 +364,7 @@ private cached module Internal {
* Holds if the first node of basic block `succ` is a control flow
* successor of the last node of basic block `pred`.
*/
private predicate succBB(BasicBlock pred, BasicBlock succ) {
succ = pred.getASuccessor()
}
private predicate succBB(BasicBlock pred, BasicBlock succ) { succ = pred.getASuccessor() }
/** Holds if `dom` is an immediate dominator of `bb`. */
cached
@@ -408,9 +372,7 @@ private cached module Internal {
idominance(entryBB/1, succBB/2)(_, dom, bb)
/** Holds if `pred` is a basic block predecessor of `succ`. */
private predicate predBB(BasicBlock succ, BasicBlock pred) {
succBB(pred, succ)
}
private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) }
/** Holds if `dom` is an immediate post-dominator of `bb`. */
cached
@@ -426,9 +388,7 @@ private import Internal
class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
override Callable getCallable() {
result.getEntryPoint() = this.getFirstNode()
}
override Callable getCallable() { result.getEntryPoint() = this.getFirstNode() }
}
/** Holds if `bb` is an entry basic block. */
@@ -440,32 +400,22 @@ private predicate entryBB(BasicBlock bb) {
* An exit basic block, that is, a basic block whose last node is
* the exit node of a callable.
*/
class ExitBasicBlock extends BasicBlock {
ExitBasicBlock() { exitBB(this) }
}
class ExitBasicBlock extends BasicBlock { ExitBasicBlock() { exitBB(this) } }
/** Holds if `bb` is an exit basic block. */
private predicate exitBB(BasicBlock bb) {
bb.getLastNode() instanceof ControlFlow::Nodes::ExitNode
}
private predicate exitBB(BasicBlock bb) { bb.getLastNode() instanceof ControlFlow::Nodes::ExitNode }
/** A basic block with more than one predecessor. */
class JoinBlock extends BasicBlock {
JoinBlock() { getFirstNode().isJoin() }
}
class JoinBlock extends BasicBlock { JoinBlock() { getFirstNode().isJoin() } }
/** A basic block that is an immediate predecessor of a join block. */
class JoinBlockPredecessor extends BasicBlock {
JoinBlockPredecessor() {
this.getASuccessor() instanceof JoinBlock
}
JoinBlockPredecessor() { this.getASuccessor() instanceof JoinBlock }
}
/** A basic block that terminates in a condition, splitting the subsequent control flow. */
class ConditionBlock extends BasicBlock {
ConditionBlock() {
this.getLastNode().isCondition()
}
ConditionBlock() { this.getLastNode().isCondition() }
/**
* Holds if basic block `succ` is immediately controlled by this basic
@@ -476,10 +426,7 @@ class ConditionBlock extends BasicBlock {
pragma[nomagic]
predicate immediatelyControls(BasicBlock succ, ConditionalSuccessor s) {
succ = this.getASuccessorByType(s) and
forall(BasicBlock pred |
pred = succ.getAPredecessor() and pred != this |
succ.dominates(pred)
)
forall(BasicBlock pred | pred = succ.getAPredecessor() and pred != this | succ.dominates(pred))
}
/**
@@ -521,10 +468,8 @@ class ConditionBlock extends BasicBlock {
* that `this` strictly dominates `controlled` so that isn't necessary to check
* directly.
*/
exists(BasicBlock succ |
this.immediatelyControls(succ, s) |
succ.dominates(controlled)
)
exists(BasicBlock succ | this.immediatelyControls(succ, s) | succ.dominates(controlled))
}
/**
@@ -533,8 +478,7 @@ class ConditionBlock extends BasicBlock {
* the callable entry point by going via the `null` edge (`isNull = true`)
* or non-`null` edge (`isNull = false`) out of this basic block.
*/
deprecated
predicate controlsNullness(BasicBlock controlled, boolean isNull) {
deprecated predicate controlsNullness(BasicBlock controlled, boolean isNull) {
this.controls(controlled, any(NullnessSuccessor s | s.getValue() = isNull))
}
@@ -573,8 +517,9 @@ class ConditionBlock extends BasicBlock {
//
// In the former case, `x` and `y` control `A`, in the latter case
// only `x & y` controls `A` if we do not take sub conditions into account.
deprecated
predicate controlsSubCond(BasicBlock controlled, boolean testIsTrue, Expr cond, boolean condIsTrue) {
deprecated predicate controlsSubCond(
BasicBlock controlled, boolean testIsTrue, Expr cond, boolean condIsTrue
) {
impliesSub(getLastNode().getElement(), cond, testIsTrue, condIsTrue) and
controls(controlled, any(BooleanSuccessor s | s.getValue() = testIsTrue))
}
@@ -584,22 +529,23 @@ class ConditionBlock extends BasicBlock {
* Holds if `e2` is a sub expression of (Boolean) expression `e1`, and
* if `e1` has value `b1` then `e2` must have value `b2`.
*/
deprecated
private predicate impliesSub(Expr e1, Expr e2, boolean b1, boolean b2) {
if e1 instanceof LogicalNotExpr then (
impliesSub(e1.(LogicalNotExpr).getOperand(), e2, b1.booleanNot(), b2)
)
else if e1 instanceof BitwiseAndExpr or e1 instanceof LogicalAndExpr then (
impliesSub(e1.(BinaryOperation).getAnOperand(), e2, b1, b2) and
b1 = true
)
else if e1 instanceof BitwiseOrExpr or e1 instanceof LogicalOrExpr then (
impliesSub(e1.(BinaryOperation).getAnOperand(), e2, b1, b2) and
b1 = false
) else (
e1.getType() instanceof BoolType and
e1 = e2 and
b1 = b2 and
(b1 = true or b1 = false)
)
deprecated private predicate impliesSub(Expr e1, Expr e2, boolean b1, boolean b2) {
if e1 instanceof LogicalNotExpr
then impliesSub(e1.(LogicalNotExpr).getOperand(), e2, b1.booleanNot(), b2)
else
if e1 instanceof BitwiseAndExpr or e1 instanceof LogicalAndExpr
then
impliesSub(e1.(BinaryOperation).getAnOperand(), e2, b1, b2) and
b1 = true
else
if e1 instanceof BitwiseOrExpr or e1 instanceof LogicalOrExpr
then (
impliesSub(e1.(BinaryOperation).getAnOperand(), e2, b1, b2) and
b1 = false
) else (
e1.getType() instanceof BoolType and
e1 = e2 and
b1 = b2 and
(b1 = true or b1 = false)
)
}

View File

@@ -25,41 +25,22 @@ private import semmle.code.csharp.frameworks.System
// Internal representation of completions
private newtype TCompletion =
TNormalCompletion()
or
TNormalCompletion() or
TBooleanCompletion(boolean outerValue, boolean innerValue) {
(outerValue = true or outerValue = false) and
(innerValue = true or innerValue = false)
}
or
TNullnessCompletion(boolean isNull) {
isNull = true or isNull = false
}
or
TMatchingCompletion(boolean isMatch) {
isMatch = true or isMatch = false
}
or
TEmptinessCompletion(boolean isEmpty) {
isEmpty = true or isEmpty = false
}
or
TReturnCompletion()
or
TBreakCompletion()
or
TBreakNormalCompletion()
or
TContinueCompletion()
or
TGotoLabelCompletion(GotoLabelStmt goto)
or
TGotoCaseCompletion(GotoCaseStmt goto)
or
TGotoDefaultCompletion()
or
TThrowCompletion(ExceptionClass ec)
or
} or
TNullnessCompletion(boolean isNull) { isNull = true or isNull = false } or
TMatchingCompletion(boolean isMatch) { isMatch = true or isMatch = false } or
TEmptinessCompletion(boolean isEmpty) { isEmpty = true or isEmpty = false } or
TReturnCompletion() or
TBreakCompletion() or
TBreakNormalCompletion() or
TContinueCompletion() or
TGotoLabelCompletion(GotoLabelStmt goto) or
TGotoCaseCompletion(GotoCaseStmt goto) or
TGotoDefaultCompletion() or
TThrowCompletion(ExceptionClass ec) or
TExitCompletion()
/**
@@ -81,9 +62,9 @@ class Completion extends TCompletion {
predicate isValidFor(ControlFlowElement cfe) {
this.(ThrowCompletion).getExceptionClass() = cfe.(TriedControlFlowElement).getAThrownException()
or
if mustHaveBooleanCompletion(cfe) then
exists(boolean value |
isBooleanConstant(cfe, value) |
if mustHaveBooleanCompletion(cfe)
then
exists(boolean value | isBooleanConstant(cfe, value) |
this = TBooleanCompletion(value, value)
)
or
@@ -95,26 +76,24 @@ class Completion extends TCompletion {
// non-`null` completion)
mustHaveNullnessCompletion(cfe) and
this = TNullnessCompletion(true)
else if mustHaveNullnessCompletion(cfe) then
exists(boolean value |
isNullnessConstant(cfe, value) |
this = TNullnessCompletion(value)
)
or
not isNullnessConstant(cfe, _) and
this = TNullnessCompletion(_)
else if mustHaveMatchingCompletion(cfe) then
exists(boolean value |
isMatchingConstant(cfe, value) |
this = TMatchingCompletion(value)
)
or
not isMatchingConstant(cfe, _) and
this = TMatchingCompletion(_)
else if mustHaveEmptinessCompletion(cfe) then
this = TEmptinessCompletion(_)
else
this = TNormalCompletion()
if mustHaveNullnessCompletion(cfe)
then
exists(boolean value | isNullnessConstant(cfe, value) | this = TNullnessCompletion(value))
or
not isNullnessConstant(cfe, _) and
this = TNullnessCompletion(_)
else
if mustHaveMatchingCompletion(cfe)
then
exists(boolean value | isMatchingConstant(cfe, value) | this = TMatchingCompletion(value))
or
not isMatchingConstant(cfe, _) and
this = TMatchingCompletion(_)
else
if mustHaveEmptinessCompletion(cfe)
then this = TEmptinessCompletion(_)
else this = TNormalCompletion()
}
/**
@@ -147,14 +126,13 @@ private predicate isBooleanConstant(Expr e, boolean value) {
*/
private predicate isNullnessConstant(Expr e, boolean value) {
mustHaveNullnessCompletion(e) and
exists(Expr stripped |
stripped = e.stripCasts() |
exists(Expr stripped | stripped = e.stripCasts() |
stripped.getType() = any(ValueType t |
not t instanceof NullableType and
// Extractor bug: the type of `x?.Length` is reported as `int`, but it should
// be `int?`
not getQualifier*(stripped).(QualifiableExpr).isConditional()
) and
not t instanceof NullableType and
// Extractor bug: the type of `x?.Length` is reported as `int`, but it should
// be `int?`
not getQualifier*(stripped).(QualifiableExpr).isConditional()
) and
value = false
or
stripped instanceof NullLiteral and
@@ -176,22 +154,17 @@ private Expr getQualifier(QualifiableExpr e) {
* non-matches (`value = false`).
*/
private predicate isMatchingConstant(Expr e, boolean value) {
exists(SwitchStmt ss |
mustHaveMatchingCompletion(ss, e) |
exists(Expr stripped |
stripped = ss.getCondition().stripCasts() |
exists(SwitchStmt ss | mustHaveMatchingCompletion(ss, e) |
exists(Expr stripped | stripped = ss.getCondition().stripCasts() |
exists(ConstCase cc, string strippedValue |
cc = ss.getAConstCase() and
e = cc.getExpr() and
strippedValue = stripped.getValue() |
if strippedValue = e.getValue() then
value = true
else
value = false
strippedValue = stripped.getValue()
|
if strippedValue = e.getValue() then value = true else value = false
)
or
exists(TypeCase tc, Type t, Type strippedType |
tc = ss.getATypeCase() |
exists(TypeCase tc, Type t, Type strippedType | tc = ss.getATypeCase() |
e = tc.getTypeAccess() and
t = e.getType() and
strippedType = stripped.getType() and
@@ -207,36 +180,34 @@ private predicate isMatchingConstant(Expr e, boolean value) {
/** A control flow element that is inside a `try` block. */
private class TriedControlFlowElement extends ControlFlowElement {
TriedControlFlowElement() {
this = any(TryStmt try).getATriedElement()
}
TriedControlFlowElement() { this = any(TryStmt try).getATriedElement() }
/**
* Gets an exception class that is potentially thrown by this element, if any.
*/
ExceptionClass getAThrownException() {
this = any(UnaryOperation uo |
not uo instanceof UnaryBitwiseOperation and
uo.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
)
not uo instanceof UnaryBitwiseOperation and
uo.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
)
or
this = any(CastExpr ce |
ce.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
or
invalidCastCandidate(ce) and
result instanceof SystemInvalidCastExceptionClass
)
ce.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
or
invalidCastCandidate(ce) and
result instanceof SystemInvalidCastExceptionClass
)
or
this instanceof Call and
result instanceof SystemExceptionClass
or
this = any(MemberAccess ma |
not ma.isConditional() and
ma.hasQualifier() and
result instanceof SystemNullReferenceExceptionClass
)
not ma.isConditional() and
ma.hasQualifier() and
result instanceof SystemNullReferenceExceptionClass
)
or
this instanceof DelegateCreation and
result instanceof SystemOutOfMemoryExceptionClass
@@ -245,27 +216,27 @@ private class TriedControlFlowElement extends ControlFlowElement {
result instanceof SystemOutOfMemoryExceptionClass
or
this = any(AddExpr ae |
ae.getType() instanceof StringType and
result instanceof SystemOutOfMemoryExceptionClass
or
ae.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
)
ae.getType() instanceof StringType and
result instanceof SystemOutOfMemoryExceptionClass
or
ae.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
)
or
this = any(SubExpr se |
se.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
)
se.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
)
or
this = any(MulExpr me |
me.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
)
me.getType() instanceof IntegralType and
result instanceof SystemOverflowExceptionClass
)
or
this = any(DivExpr de |
not de.getDenominator().getValue().toInt() != 0 and
result instanceof SystemDivideByZeroExceptionClass
)
not de.getDenominator().getValue().toInt() != 0 and
result instanceof SystemDivideByZeroExceptionClass
)
or
this instanceof RemExpr and
result instanceof SystemDivideByZeroExceptionClass
@@ -278,7 +249,7 @@ private class TriedControlFlowElement extends ControlFlowElement {
}
}
pragma [noinline]
pragma[noinline]
private predicate invalidCastCandidate(CastExpr ce) {
ce.getType() = ce.getExpr().getType().(ValueOrRefType).getASubType+()
}
@@ -301,28 +272,15 @@ private predicate mustHaveBooleanCompletion(Expr e) {
* `B` is the Boolean completion of `A && B`.
*/
private predicate inBooleanContext(Expr e, boolean isBooleanCompletionForParent) {
exists(IfStmt is |
is.getCondition() = e |
isBooleanCompletionForParent = false
)
exists(IfStmt is | is.getCondition() = e | isBooleanCompletionForParent = false)
or
exists(LoopStmt ls |
ls.getCondition() = e |
isBooleanCompletionForParent = false
)
exists(LoopStmt ls | ls.getCondition() = e | isBooleanCompletionForParent = false)
or
exists(CaseStmt cs |
cs.getCondition() = e |
isBooleanCompletionForParent = false
)
exists(CaseStmt cs | cs.getCondition() = e | isBooleanCompletionForParent = false)
or
exists(SpecificCatchClause scc |
scc.getFilterClause() = e |
isBooleanCompletionForParent = false
)
exists(SpecificCatchClause scc | scc.getFilterClause() = e | isBooleanCompletionForParent = false)
or
exists(LogicalNotExpr lne |
lne.getAnOperand() = e |
exists(LogicalNotExpr lne | lne.getAnOperand() = e |
inBooleanContext(lne, _) and
isBooleanCompletionForParent = true
)
@@ -354,8 +312,7 @@ private predicate inBooleanContext(Expr e, boolean isBooleanCompletionForParent)
isBooleanCompletionForParent = true
)
or
exists(NullCoalescingExpr nce |
nce.getAnOperand() = e |
exists(NullCoalescingExpr nce | nce.getAnOperand() = e |
inBooleanContext(nce, _) and
isBooleanCompletionForParent = true
)
@@ -379,25 +336,19 @@ private predicate mustHaveNullnessCompletion(Expr e) {
* is the nullness completion of `A ?? B`.
*/
private predicate inNullnessContext(Expr e, boolean isNullnessCompletionForParent) {
exists(NullCoalescingExpr nce |
e = nce.getLeftOperand() |
isNullnessCompletionForParent = false
)
exists(NullCoalescingExpr nce | e = nce.getLeftOperand() | isNullnessCompletionForParent = false)
or
exists(QualifiableExpr qe |
qe.isConditional() |
exists(QualifiableExpr qe | qe.isConditional() |
e = qe.getChildExpr(-1) and
isNullnessCompletionForParent = false
)
or
exists(ConditionalExpr ce |
inNullnessContext(ce, _) |
exists(ConditionalExpr ce | inNullnessContext(ce, _) |
(e = ce.getThen() or e = ce.getElse()) and
isNullnessCompletionForParent = true
)
or
exists(NullCoalescingExpr nce |
inNullnessContext(nce, _) |
exists(NullCoalescingExpr nce | inNullnessContext(nce, _) |
e = nce.getRightOperand() and
isNullnessCompletionForParent = true
)
@@ -442,9 +393,7 @@ predicate foreachEmptiness(ForeachStmt fs, ControlFlowElement cfe) {
* Holds if a normal completion of `cfe` must be an emptiness completion. Thats is,
* whether `cfe` determines whether to execute the body of a `foreach` statement.
*/
private predicate mustHaveEmptinessCompletion(ControlFlowElement cfe) {
foreachEmptiness(_, cfe)
}
private predicate mustHaveEmptinessCompletion(ControlFlowElement cfe) { foreachEmptiness(_, cfe) }
/**
* A completion that represents normal evaluation of a statement or an
@@ -456,9 +405,7 @@ abstract class NormalCompletion extends Completion { }
* A class to make `TNormalCompletion` a `NormalCompletion`
*/
class SimpleCompletion extends NormalCompletion, TNormalCompletion {
override string toString() {
result = "normal"
}
override string toString() { result = "normal" }
}
/**
@@ -480,20 +427,14 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion {
/** Gets the value that this expression completes with. */
boolean getOuterValue() { this = TBooleanCompletion(result, _) }
override string toString() {
result = getOuterValue() + "/" + getInnerValue()
}
override string toString() { result = getOuterValue() + "/" + getInnerValue() }
}
/** A Boolean `true` completion. */
class TrueCompletion extends BooleanCompletion {
TrueCompletion() { getOuterValue() = true }
}
class TrueCompletion extends BooleanCompletion { TrueCompletion() { getOuterValue() = true } }
/** A Boolean `false` completion. */
class FalseCompletion extends BooleanCompletion {
FalseCompletion() { getOuterValue() = false }
}
class FalseCompletion extends BooleanCompletion { FalseCompletion() { getOuterValue() = false } }
/**
* A completion that represents evaluation of an expression that is either
@@ -503,12 +444,7 @@ class NullnessCompletion extends ConditionalCompletion, TNullnessCompletion {
/** Holds if the last sub expression of this expression evaluates to `null`. */
predicate isNull() { this = TNullnessCompletion(true) }
override string toString() {
if this.isNull() then
result = "null"
else
result = "non-null"
}
override string toString() { if this.isNull() then result = "null" else result = "non-null" }
}
/**
@@ -519,12 +455,7 @@ class MatchingCompletion extends ConditionalCompletion, TMatchingCompletion {
/** Holds if there is a match. */
predicate isMatch() { this = TMatchingCompletion(true) }
override string toString() {
if this.isMatch() then
result = "match"
else
result = "no-match"
}
override string toString() { if this.isMatch() then result = "match" else result = "no-match" }
}
/**
@@ -535,12 +466,7 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
/** Holds if the emptiness test evaluates to `true`. */
predicate isEmpty() { this = TEmptinessCompletion(true) }
override string toString() {
if this.isEmpty() then
result = "empty"
else
result = "non-empty"
}
override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" }
}
/**

View File

@@ -28,9 +28,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
* several `ControlFlow::Node`s, for example to represent the continuation
* flow in a `try/catch/finally` construction.
*/
Node getAControlFlowNode() {
result.getElement() = this
}
Node getAControlFlowNode() { result.getElement() = this }
/**
* Gets a first control flow node executed within this element.
@@ -50,14 +48,10 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
* Holds if this element is live, that is this element can be reached
* from the entry point of its enclosing callable.
*/
predicate isLive() {
exists(this.getAControlFlowNode())
}
predicate isLive() { exists(this.getAControlFlowNode()) }
/** Holds if the current element is reachable from `src`. */
predicate reachableFrom(ControlFlowElement src) {
this = src.getAReachableElement()
}
predicate reachableFrom(ControlFlowElement src) { this = src.getAReachableElement() }
/** Gets an element that is reachable from this element. */
ControlFlowElement getAReachableElement() {
@@ -96,11 +90,11 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
// Only calculate dominance by explicit recursion for split nodes;
// all other nodes can use regular CFG dominance
this instanceof ControlFlow::Internal::SplitControlFlowElement and
exists(ConditionBlock cb |
cb.getLastNode() = this.getAControlFlowNode() |
exists(ConditionBlock cb | cb.getLastNode() = this.getAControlFlowNode() |
succ = cb.getASuccessorByType(s) and
forall(BasicBlock pred, SuccessorType t |
pred = succ.getAPredecessorByType(t) and pred != cb |
forall(BasicBlock pred, SuccessorType t |
pred = succ.getAPredecessorByType(t) and pred != cb
|
succ.dominates(pred)
or
// `pred` might be another split of `cfe`
@@ -112,9 +106,10 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
}
pragma[nomagic]
private JoinBlockPredecessor getAPossiblyControlledPredecessor(JoinBlock controlled, ConditionalSuccessor s) {
exists(BasicBlock mid |
this.immediatelyControlsBlockSplit(mid, s) |
private JoinBlockPredecessor getAPossiblyControlledPredecessor(
JoinBlock controlled, ConditionalSuccessor s
) {
exists(BasicBlock mid | this.immediatelyControlsBlockSplit(mid, s) |
result = mid.getASuccessor*()
) and
result.getASuccessor() = controlled and
@@ -124,8 +119,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
pragma[nomagic]
private predicate isPossiblyControlledJoinBlock(JoinBlock controlled, ConditionalSuccessor s) {
exists(this.getAPossiblyControlledPredecessor(controlled, s)) and
forall(BasicBlock pred |
pred = controlled.getAPredecessor() |
forall(BasicBlock pred | pred = controlled.getAPredecessor() |
pred = this.getAPossiblyControlledPredecessor(controlled, s)
or
controlled.dominates(pred)
@@ -136,14 +130,13 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
private predicate controlsBlockSplit(BasicBlock controlled, ConditionalSuccessor s) {
this.immediatelyControlsBlockSplit(controlled, s)
or
if controlled instanceof JoinBlock then
if controlled instanceof JoinBlock
then
this.isPossiblyControlledJoinBlock(controlled, s) and
forall(BasicBlock pred |
pred = this.getAPossiblyControlledPredecessor(controlled, s) |
forall(BasicBlock pred | pred = this.getAPossiblyControlledPredecessor(controlled, s) |
this.controlsBlock(pred, s)
)
else
this.controlsBlockSplit(controlled.getAPredecessor(), s)
else this.controlsBlockSplit(controlled.getAPredecessor(), s)
}
/**
@@ -166,8 +159,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
predicate controlsBlock(BasicBlock controlled, ConditionalSuccessor s) {
this.controlsBlockSplit(controlled, s)
or
exists(ConditionBlock cb |
cb.getLastNode() = this.getAControlFlowNode() |
exists(ConditionBlock cb | cb.getLastNode() = this.getAControlFlowNode() |
cb.controls(controlled, s)
)
}
@@ -188,10 +180,10 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
*
* as control flow splitting is taken into account.
*/
pragma[inline] // potentially very large predicate, so must be inlined
// potentially very large predicate, so must be inlined
pragma[inline]
predicate controlsElement(ControlFlowElement controlled, ConditionalSuccessor s) {
forex(BasicBlock bb |
bb = controlled.getAControlFlowNode().getBasicBlock() |
forex(BasicBlock bb | bb = controlled.getAControlFlowNode().getBasicBlock() |
this.controlsBlock(bb, s)
)
}

View File

@@ -7,17 +7,11 @@ private import semmle.code.csharp.dataflow.DelegateDataFlow
private import dotnet
// Internal representation of call contexts
cached private newtype TCallContext =
TEmptyCallContext()
or
TArgCallContext(DotNet::Call c, int i) {
exists(c.getArgument(i))
}
or
TDynamicAccessorArgCallContext(DynamicAccessorCall dac, int i) {
exists(dac.getArgument(i))
}
or
cached
private newtype TCallContext =
TEmptyCallContext() or
TArgCallContext(DotNet::Call c, int i) { exists(c.getArgument(i)) } or
TDynamicAccessorArgCallContext(DynamicAccessorCall dac, int i) { exists(dac.getArgument(i)) } or
TDelegateToLibraryCallableArgCallContext(DelegateArgumentToLibraryCallable arg, int i) {
exists(arg.getDelegateType().getParameter(i))
}
@@ -55,47 +49,37 @@ abstract class ArgumentCallContext extends CallContext {
/** An argument of an ordinary call. */
class CallArgumentCallContext extends ArgumentCallContext, TArgCallContext {
DotNet::Call c;
int arg;
CallArgumentCallContext() {
this = TArgCallContext(c, arg)
}
CallArgumentCallContext() { this = TArgCallContext(c, arg) }
override predicate isArgument(DotNet::Expr call, int i) {
call = c and
i = arg
}
override string toString() {
result = c.getArgument(arg).toString()
}
override string toString() { result = c.getArgument(arg).toString() }
override Location getLocation() {
result = c.getArgument(arg).getLocation()
}
override Location getLocation() { result = c.getArgument(arg).getLocation() }
}
/** An argument of a dynamic accessor call. */
class DynamicAccessorArgumentCallContext extends ArgumentCallContext, TDynamicAccessorArgCallContext {
DynamicAccessorCall dac;
int arg;
DynamicAccessorArgumentCallContext() {
this = TDynamicAccessorArgCallContext(dac, arg)
}
DynamicAccessorArgumentCallContext() { this = TDynamicAccessorArgCallContext(dac, arg) }
override predicate isArgument(DotNet::Expr call, int i) {
call = dac and
i = arg
}
override string toString() {
result = dac.getArgument(arg).toString()
}
override string toString() { result = dac.getArgument(arg).toString() }
override Location getLocation() {
result = dac.getArgument(arg).getLocation()
}
override Location getLocation() { result = dac.getArgument(arg).getLocation() }
}
/**
@@ -107,8 +91,10 @@ class DynamicAccessorArgumentCallContext extends ArgumentCallContext, TDynamicAc
* in the database, so the delegate argument `y => y` is used to
* represent the call.
*/
class DelegateArgumentToLibraryCallableArgumentContext extends ArgumentCallContext, TDelegateToLibraryCallableArgCallContext {
class DelegateArgumentToLibraryCallableArgumentContext extends ArgumentCallContext,
TDelegateToLibraryCallableArgCallContext {
DotNet::Expr delegate;
int arg;
DelegateArgumentToLibraryCallableArgumentContext() {
@@ -120,11 +106,7 @@ class DelegateArgumentToLibraryCallableArgumentContext extends ArgumentCallConte
i = arg
}
override string toString() {
result = "argument " + arg + " of " + delegate.toString()
}
override string toString() { result = "argument " + arg + " of " + delegate.toString() }
override Location getLocation() {
result = delegate.getLocation()
}
override Location getLocation() { result = delegate.getLocation() }
}

View File

@@ -16,19 +16,17 @@ private class DelegateFlowSource extends DataFlow::ExprNode {
DelegateFlowSource() {
this.getExpr() = any(Expr e |
c = e.(AnonymousFunctionExpr) or
c = e.(CallableAccess).getTarget().getSourceDeclaration()
)
c = e.(AnonymousFunctionExpr) or
c = e.(CallableAccess).getTarget().getSourceDeclaration()
)
}
/** Gets the callable that is referenced in this delegate flow source. */
Callable getCallable() {
result = c
}
Callable getCallable() { result = c }
}
/** A sink of flow for a delegate expression. */
private abstract class DelegateFlowSink extends DataFlow::ExprNode {
abstract private class DelegateFlowSink extends DataFlow::ExprNode {
/**
* Gets an actual run-time target of this delegate call in the given call
* context, if any. The call context records the *last* call required to
@@ -93,19 +91,16 @@ private abstract class DelegateFlowSink extends DataFlow::ExprNode {
library class DelegateCallExpr extends DelegateFlowSink {
DelegateCall dc;
DelegateCallExpr() {
this.getExpr() = dc.getDelegateExpr()
}
DelegateCallExpr() { this.getExpr() = dc.getDelegateExpr() }
/** Gets the delegate call that this expression belongs to. */
DelegateCall getDelegateCall() {
result = dc
}
DelegateCall getDelegateCall() { result = dc }
}
/** A delegate expression that is passed as the argument to a library callable. */
library class DelegateArgumentToLibraryCallable extends Expr {
DelegateType dt;
Call call;
DelegateArgumentToLibraryCallable() {
@@ -118,14 +113,10 @@ library class DelegateArgumentToLibraryCallable extends Expr {
}
/** Gets the call that this argument belongs to. */
Call getCall() {
result = call
}
Call getCall() { result = call }
/** Gets the delegate type of this argument. */
DelegateType getDelegateType() {
result = dt
}
DelegateType getDelegateType() { result = dt }
/**
* Gets an actual run-time target of this delegate call in the given call
@@ -133,8 +124,7 @@ library class DelegateArgumentToLibraryCallable extends Expr {
* resolve the target, if any. Example:
*/
Callable getARuntimeTarget(CallContext context) {
exists(DelegateArgumentToLibraryCallableSink sink |
sink.getExpr() = this |
exists(DelegateArgumentToLibraryCallableSink sink | sink.getExpr() = this |
result = sink.getARuntimeTarget(context)
)
}
@@ -151,14 +141,10 @@ private class DelegateArgumentToLibraryCallableSink extends DelegateFlowSink {
library class AddEventSource extends DelegateFlowSink {
AddEventExpr ae;
AddEventSource() {
this.getExpr() = ae.getRValue()
}
AddEventSource() { this.getExpr() = ae.getRValue() }
/** Gets the event that this delegate is added to. */
Event getEvent() {
result = ae.getTarget()
}
Event getEvent() { result = ae.getTarget() }
}
/**
@@ -169,15 +155,16 @@ library class AddEventSource extends DelegateFlowSink {
* `node` goes through a returned expression. The call context `lastCall`
* records the last call on the path from `node` to `sink`, if any.
*/
private predicate flowsFrom(DelegateFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall) {
private predicate flowsFrom(
DelegateFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall
) {
// Base case
sink = node and
isReturned = false and
lastCall instanceof EmptyCallContext
or
// Local flow
exists(DataFlow::Node mid |
flowsFrom(sink, mid, isReturned, lastCall) |
exists(DataFlow::Node mid | flowsFrom(sink, mid, isReturned, lastCall) |
DataFlow::localFlowStep(node, mid) or
node.asExpr() = mid.asExpr().(DelegateCreation).getArgument()
)
@@ -191,7 +178,9 @@ private predicate flowsFrom(DelegateFlowSink sink, DataFlow::Node node, boolean
)
or
// Flow into a callable (non-delegate call)
exists(DataFlow::Internal::ExplicitParameterNode mid, CallContext prevLastCall, Expr call, Parameter p |
exists(
DataFlow::Internal::ExplicitParameterNode mid, CallContext prevLastCall, Expr call, Parameter p
|
flowsFrom(sink, mid, isReturned, prevLastCall) and
isReturned = false and
p = mid.getParameter() and
@@ -200,7 +189,10 @@ private predicate flowsFrom(DelegateFlowSink sink, DataFlow::Node node, boolean
)
or
// Flow into a callable (delegate call)
exists(DataFlow::Internal::ExplicitParameterNode mid, CallContext prevLastCall, DelegateCall dc, Callable c, Parameter p, int i |
exists(
DataFlow::Internal::ExplicitParameterNode mid, CallContext prevLastCall, DelegateCall dc,
Callable c, Parameter p, int i
|
flowsFrom(sink, mid, isReturned, prevLastCall) and
isReturned = false and
flowIntoDelegateCall(dc, c, node.asExpr(), i) and
@@ -229,7 +221,7 @@ private predicate flowsFrom(DelegateFlowSink sink, DataFlow::Node node, boolean
* `prevLastCall` is the previous last call, so the result is the
* previous call if it exists, otherwise `call` is the last call.
*/
bindingset [call, i]
bindingset[call, i]
private CallContext getLastCall(CallContext prevLastCall, Expr call, int i) {
prevLastCall instanceof EmptyCallContext and
result.(ArgumentCallContext).isArgument(call, i)

View File

@@ -50,9 +50,9 @@ class AlwaysNullExpr extends Expr {
this instanceof NullLiteral
or
this = any(ConditionalExpr ce |
ce.getThen() instanceof AlwaysNullExpr and
ce.getElse() instanceof AlwaysNullExpr
)
ce.getThen() instanceof AlwaysNullExpr and
ce.getElse() instanceof AlwaysNullExpr
)
or
this.(AssignExpr).getRValue() instanceof AlwaysNullExpr
or
@@ -65,9 +65,7 @@ class NonNullExpr extends Expr {
NonNullExpr() {
G::Internal::nonNullValue(this)
or
exists(NonNullExpr mid |
G::Internal::nonNullValueImplied(mid, this)
)
exists(NonNullExpr mid | G::Internal::nonNullValueImplied(mid, this))
or
this instanceof G::NullGuardedExpr
or
@@ -79,17 +77,16 @@ class NonNullExpr extends Expr {
private predicate nonNullDef(Ssa::Definition v) {
v.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof NonNullExpr
or
exists(AssignableDefinition ad |
ad = v.(Ssa::ExplicitDefinition).getADefinition() |
exists(AssignableDefinition ad | ad = v.(Ssa::ExplicitDefinition).getADefinition() |
ad instanceof AssignableDefinitions::IsPatternDefinition
or
ad instanceof AssignableDefinitions::TypeCasePatternDefinition
or
ad = any(AssignableDefinitions::LocalVariableDefinition d |
d.getExpr() = any(SpecificCatchClause scc).getVariableDeclExpr()
or
d.getExpr() = any(ForeachStmt fs).getAVariableDeclExpr()
)
d.getExpr() = any(SpecificCatchClause scc).getVariableDeclExpr()
or
d.getExpr() = any(ForeachStmt fs).getAVariableDeclExpr()
)
)
}
@@ -105,9 +102,10 @@ private predicate dereferenceAt(BasicBlock bb, int i, Ssa::Definition def, Deref
* Holds if `e` having abstract value `vExpr` implies that SSA definition `def`
* has abstract value `vDef`.
*/
private predicate exprImpliesSsaDef(Expr e, G::AbstractValue vExpr, Ssa::Definition def, G::AbstractValue vDef) {
exists(G::Internal::Guard g |
G::Internal::impliesSteps(e, vExpr, g, vDef) |
private predicate exprImpliesSsaDef(
Expr e, G::AbstractValue vExpr, Ssa::Definition def, G::AbstractValue vDef
) {
exists(G::Internal::Guard g | G::Internal::impliesSteps(e, vExpr, g, vDef) |
g = def.getARead()
or
g = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess()
@@ -120,7 +118,8 @@ private predicate exprImpliesSsaDef(Expr e, G::AbstractValue vExpr, Ssa::Definit
*/
private predicate ensureNotNullAt(BasicBlock bb, int i, Ssa::Definition def) {
exists(Expr e, G::AbstractValue v, NullValue nv |
G::Internal::asserts(bb.getNode(i).getElement(), e, v) |
G::Internal::asserts(bb.getNode(i).getElement(), e, v)
|
exprImpliesSsaDef(e, v, def, nv) and
not nv.isNull()
)
@@ -130,7 +129,9 @@ private predicate ensureNotNullAt(BasicBlock bb, int i, Ssa::Definition def) {
* Holds if the `i`th node of basic block `bb` is a dereference `d` of SSA
* definition `def`, and `def` may potentially be `null`.
*/
private predicate potentialNullDereferenceAt(BasicBlock bb, int i, Ssa::Definition def, Dereference d) {
private predicate potentialNullDereferenceAt(
BasicBlock bb, int i, Ssa::Definition def, Dereference d
) {
dereferenceAt(bb, i, def, d) and
not exists(int j | ensureNotNullAt(bb, j, def) | j < i)
}
@@ -142,16 +143,16 @@ private predicate potentialNullDereferenceAt(BasicBlock bb, int i, Ssa::Definiti
* If the returned element takes the `s` branch, then `def` is guaranteed to be
* `null` if `nv.isNull()` holds, and non-`null` otherwise.
*/
private ControlFlowElement getANullCheck(Ssa::Definition def, SuccessorTypes::ConditionalSuccessor s, NullValue nv) {
exists(Expr e, G::AbstractValue v |
v.branch(result, s, e) |
exprImpliesSsaDef(e, v, def, nv)
)
private ControlFlowElement getANullCheck(
Ssa::Definition def, SuccessorTypes::ConditionalSuccessor s, NullValue nv
) {
exists(Expr e, G::AbstractValue v | v.branch(result, s, e) | exprImpliesSsaDef(e, v, def, nv))
}
private predicate isMaybeNullArgument(Ssa::ExplicitDefinition def, MaybeNullExpr arg) {
exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p |
pdef = def.getADefinition() |
pdef = def.getADefinition()
|
p = pdef.getParameter().getSourceDeclaration() and
p.getAnAssignedArgument() = arg and
not arg.getEnclosingCallable().getEnclosingCallable*() instanceof TestMethod
@@ -161,14 +162,11 @@ private predicate isMaybeNullArgument(Ssa::ExplicitDefinition def, MaybeNullExpr
/** Holds if `def` is an SSA definition that may be `null`. */
private predicate defMaybeNull(Ssa::Definition def, string msg, Element reason) {
// A variable compared to `null` might be `null`
exists(G::DereferenceableExpr de |
de = def.getARead() |
exists(G::DereferenceableExpr de | de = def.getARead() |
reason = de.getANullCheck(_, true) and
msg = "as suggested by $@ null check" and
not de = any(Ssa::PseudoDefinition pdef).getARead() and
strictcount(Element e |
e = any(Ssa::Definition def0 | de = def0.getARead()).getElement()
) = 1 and
strictcount(Element e | e = any(Ssa::Definition def0 | de = def0.getARead()).getElement()) = 1 and
not nonNullDef(def) and
// Don't use a check as reason if there is a `null` assignment
// or argument
@@ -181,16 +179,14 @@ private predicate defMaybeNull(Ssa::Definition def, string msg, Element reason)
msg = "because of $@ null argument"
or
// If the source of a variable is `null` then the variable may be `null`
exists(AssignableDefinition adef |
adef = def.(Ssa::ExplicitDefinition).getADefinition() |
exists(AssignableDefinition adef | adef = def.(Ssa::ExplicitDefinition).getADefinition() |
adef.getSource() instanceof MaybeNullExpr and
reason = adef.getExpr() and
msg = "because of $@ assignment"
)
or
// A variable of nullable type may be null
exists(Dereference d |
dereferenceAt(_, _, def, d) |
exists(Dereference d | dereferenceAt(_, _, def, d) |
d.hasNullableType() and
not def instanceof Ssa::PseudoDefinition and
reason = def.getSourceVariable().getAssignable() and
@@ -203,7 +199,9 @@ private predicate defMaybeNull(Ssa::Definition def, string msg, Element reason)
* be `null` in basic block `bb2`. The SSA definitions share the same source
* variable.
*/
private predicate defNullImpliesStep(Ssa::Definition def1, BasicBlock bb1, Ssa::Definition def2, BasicBlock bb2) {
private predicate defNullImpliesStep(
Ssa::Definition def1, BasicBlock bb1, Ssa::Definition def2, BasicBlock bb2
) {
exists(Ssa::SourceVariable v |
defMaybeNull(v.getAnSsaDefinition(), _, _) and
def1.getSourceVariable() = v
@@ -221,7 +219,8 @@ private predicate defNullImpliesStep(Ssa::Definition def1, BasicBlock bb1, Ssa::
not ensureNotNullAt(bb1, _, def1) and
bb2 = bb1.getASuccessor() and
not exists(SuccessorTypes::ConditionalSuccessor s, NullValue nv |
bb1.getLastNode() = getANullCheck(def1, s, nv).getAControlFlowNode() |
bb1.getLastNode() = getANullCheck(def1, s, nv).getAControlFlowNode()
|
bb2 = bb1.getASuccessorByType(s) and
not nv.isNull()
)
@@ -235,8 +234,7 @@ private predicate defMaybeNullInBlock(Ssa::Definition def, BasicBlock bb) {
defMaybeNull(def, _, _) and
bb = def.getBasicBlock()
or
exists(BasicBlock mid, Ssa::Definition midDef |
defMaybeNullInBlock(midDef, mid) |
exists(BasicBlock mid, Ssa::Definition midDef | defMaybeNullInBlock(midDef, mid) |
defNullImpliesStep(midDef, mid, def, bb)
)
}
@@ -246,8 +244,7 @@ private predicate defMaybeNullInBlock(Ssa::Definition def, BasicBlock bb) {
* dereference.
*/
private predicate nullDerefCandidateVariable(Ssa::SourceVariable v) {
exists(Ssa::Definition def, BasicBlock bb |
potentialNullDereferenceAt(bb, _, def, _) |
exists(Ssa::Definition def, BasicBlock bb | potentialNullDereferenceAt(bb, _, def, _) |
defMaybeNullInBlock(def, bb) and
v = def.getSourceVariable()
)
@@ -272,14 +269,12 @@ private newtype TPathNode =
nullDerefCandidateVariable(def.getSourceVariable()) and
defMaybeNull(def, msg, reason) and
if isMaybeNullArgument(def, reason) then isNullArgument = true else isNullArgument = false
}
or
} or
TInternalPathNode(Ssa::Definition def, BasicBlock bb) {
succStep(_, def, bb)
or
succNullArgument(_, def, bb)
}
or
} or
TSinkPathNode(Ssa::Definition def, BasicBlock bb, int i, Dereference d) {
potentialNullDereferenceAt(bb, i, def, d) and
(
@@ -314,8 +309,11 @@ abstract class PathNode extends TPathNode {
private class SourcePathNode extends PathNode, TSourcePathNode {
private Ssa::Definition def;
private string msg;
private Element reason;
private boolean isNullArgument;
SourcePathNode() { this = TSourcePathNode(def, msg, reason, isNullArgument) }
@@ -341,22 +339,17 @@ private class SourcePathNode extends PathNode, TSourcePathNode {
}
override string toString() {
if isNullArgument = true then
result = reason.toString()
else
result = def.toString()
if isNullArgument = true then result = reason.toString() else result = def.toString()
}
override Location getLocation() {
if isNullArgument = true then
result = reason.getLocation()
else
result = def.getLocation()
if isNullArgument = true then result = reason.getLocation() else result = def.getLocation()
}
}
private class InternalPathNode extends PathNode, TInternalPathNode {
private Ssa::Definition def;
private BasicBlock bb;
InternalPathNode() { this = TInternalPathNode(def, bb) }
@@ -376,8 +369,11 @@ private class InternalPathNode extends PathNode, TInternalPathNode {
private class SinkPathNode extends PathNode, TSinkPathNode {
private Ssa::Definition def;
private BasicBlock bb;
private int i;
private Dereference d;
SinkPathNode() { this = TSinkPathNode(def, bb, i, d) }
@@ -400,10 +396,8 @@ private class SinkPathNode extends PathNode, TSinkPathNode {
* for `Dereference::is[First]MaybeNull()`.
*/
module PathGraph {
query predicate nodes(PathNode n) {
n.getASuccessor*() instanceof SinkPathNode
}
query predicate nodes(PathNode n) { n.getASuccessor*() instanceof SinkPathNode }
query predicate edges(PathNode pred, PathNode succ) {
nodes(pred) and
nodes(succ) and
@@ -431,12 +425,13 @@ private predicate defReaches(Ssa::Definition def, ControlFlow::Node cfn, boolean
exists(def.getAFirstReadAtNode(cfn)) and
(always = true or always = false)
or
exists(ControlFlow::Node mid |
defReaches(def, mid, always) |
exists(ControlFlow::Node mid | defReaches(def, mid, always) |
Ssa::Internal::adjacentReadPairSameVar(mid, cfn) and
not mid = any(Dereference d |
if always = true then d.isAlwaysNull(def.getSourceVariable()) else d.isMaybeNull(def, _, _, _, _)
).getAControlFlowNode()
if always = true
then d.isAlwaysNull(def.getSourceVariable())
else d.isMaybeNull(def, _, _, _, _)
).getAControlFlowNode()
)
}
@@ -446,20 +441,21 @@ private predicate defReaches(Ssa::Definition def, ControlFlow::Node cfn, boolean
*/
class Dereference extends G::DereferenceableExpr {
Dereference() {
if this.hasNullableType() then (
if this.hasNullableType()
then (
// Strictly speaking, these throw `InvalidOperationException`s and not
// `NullReferenceException`s
this = any(PropertyAccess pa | pa.getTarget().hasName("Value")).getQualifier()
or
exists(Type underlyingType |
this = any(CastExpr ce | ce.getTargetType() = underlyingType).getExpr() |
this = any(CastExpr ce | ce.getTargetType() = underlyingType).getExpr()
|
underlyingType = this.getType().(NullableType).getUnderlyingType()
or
underlyingType = this.getType() and
not underlyingType instanceof NullableType
)
)
else (
) else (
this = any(QualifiableExpr qe | not qe.isConditional()).getQualifier() and
not this instanceof ThisAccess and
not this instanceof BaseAccess and
@@ -472,11 +468,15 @@ class Dereference extends G::DereferenceableExpr {
exists(ExtensionMethodCall emc, Parameter p |
this = emc.getArgumentForParameter(p) and
p.hasExtensionMethodModifier() and
not emc.isConditional() |
not emc.isConditional()
|
p.fromSource() // assume all non-source extension methods perform a dereference
implies
exists(Ssa::ExplicitDefinition def, AssignableDefinitions::ImplicitParameterDefinition pdef |
pdef = def.getADefinition() |
exists(
Ssa::ExplicitDefinition def, AssignableDefinitions::ImplicitParameterDefinition pdef
|
pdef = def.getADefinition()
|
p.getSourceDeclaration() = pdef.getParameter() and
def.getARead() instanceof Dereference
)
@@ -485,8 +485,7 @@ class Dereference extends G::DereferenceableExpr {
}
private predicate isAlwaysNull0(Ssa::Definition def) {
forall(Ssa::Definition input |
input = getAnUltimateDefinition(def) |
forall(Ssa::Definition input | input = getAnUltimateDefinition(def) |
input.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof AlwaysNullExpr
) and
not nonNullDef(def) and
@@ -503,15 +502,12 @@ class Dereference extends G::DereferenceableExpr {
// Exclude fields, properties, and captured variables, as they may not have an
// accurate SSA representation
v.getAssignable() = any(LocalScopeVariable lsv |
strictcount(Callable c |
c = any(AssignableDefinition ad | ad.getTarget() = lsv).getEnclosingCallable()
) = 1
) and
strictcount(Callable c |
c = any(AssignableDefinition ad | ad.getTarget() = lsv).getEnclosingCallable()
) = 1
) and
(
forex(Ssa::Definition def0 |
this = def0.getARead() |
this.isAlwaysNull0(def0)
)
forex(Ssa::Definition def0 | this = def0.getARead() | this.isAlwaysNull0(def0))
or
exists(NullValue nv |
this.(G::GuardedExpr).mustHaveValue(nv) and
@@ -535,7 +531,9 @@ class Dereference extends G::DereferenceableExpr {
* Holds if this expression dereferences SSA definition `def`, which may
* be `null`.
*/
predicate isMaybeNull(Ssa::Definition def, SourcePathNode source, SinkPathNode sink, string msg, Element reason) {
predicate isMaybeNull(
Ssa::Definition def, SourcePathNode source, SinkPathNode sink, string msg, Element reason
) {
source.getASuccessor*() = sink and
msg = source.getMessage() and
reason = source.getReason() and
@@ -549,7 +547,9 @@ class Dereference extends G::DereferenceableExpr {
* be `null`, and this expression can be reached from `def` without passing
* through another such dereference.
*/
predicate isFirstMaybeNull(Ssa::Definition def, SourcePathNode source, SinkPathNode sink, string msg, Element reason) {
predicate isFirstMaybeNull(
Ssa::Definition def, SourcePathNode source, SinkPathNode sink, string msg, Element reason
) {
this.isMaybeNull(def, source, sink, msg, reason) and
defReaches(def, this.getAControlFlowNode(), false)
}

File diff suppressed because it is too large Load Diff

View File

@@ -27,8 +27,7 @@ module BaseSsa {
bb.getNode(i) = def.getAControlFlowNode() and
v = def.getTarget() and
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second |
first = def |
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
second.getAssignment() = first.getAssignment() and
second.getEvaluationOrder() > first.getEvaluationOrder() and
second.getTarget() = v
@@ -40,14 +39,15 @@ module BaseSsa {
* variable `v` in an SSA representation.
*/
private predicate needsPhiNode(BasicBlock bb, SimpleLocalScopeVariable v) {
exists(BasicBlock def |
def.inDominanceFrontier(bb) |
exists(BasicBlock def | def.inDominanceFrontier(bb) |
defAt(def, _, _, v) or
needsPhiNode(def, v)
)
}
private newtype SsaRefKind = SsaRead() or SsaDef()
private newtype SsaRefKind =
SsaRead() or
SsaDef()
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
@@ -80,11 +80,10 @@ module BaseSsa {
* `bb` reaches the reference at rank `rnk`, without passing through another
* definition of `v`, including phi nodes.
*/
private predicate defReachesRank(BasicBlock bb, AssignableDefinition def, SimpleLocalScopeVariable v, int rnk) {
exists(int i |
rnk = ssaRefRank(bb, i, v, SsaDef()) |
defAt(bb, i, def, v)
)
private predicate defReachesRank(
BasicBlock bb, AssignableDefinition def, SimpleLocalScopeVariable v, int rnk
) {
exists(int i | rnk = ssaRefRank(bb, i, v, SsaDef()) | defAt(bb, i, def, v))
or
defReachesRank(bb, def, v, rnk - 1) and
rnk = ssaRefRank(bb, _, v, SsaRead())
@@ -112,7 +111,8 @@ module BaseSsa {
* Gets a read of the SSA definition for variable `v` at definition `def`. That is,
* a read that is guaranteed to read the value assigned at definition `def`.
*/
cached AssignableRead getARead(AssignableDefinition def, SimpleLocalScopeVariable v) {
cached
AssignableRead getARead(AssignableDefinition def, SimpleLocalScopeVariable v) {
exists(BasicBlock bb, int i, int rnk |
result.getAControlFlowNode() = bb.getNode(i) and
rnk = ssaRefRank(bb, i, v, SsaRead())

View File

@@ -18,8 +18,7 @@ module Steps {
private AssignableRead getARead(AssignableDefinition def) {
result = BaseSsa::getARead(def, _)
or
exists(LocalScopeVariable v |
def.getTarget() = v |
exists(LocalScopeVariable v | def.getTarget() = v |
result = v.getAnAccess() and
strictcount(AssignableDefinition def0 | def0.getTarget() = v) = 1
)
@@ -27,7 +26,8 @@ module Steps {
exists(Field f |
def.getTarget() = f and
result = f.getAnAccess() and
strictcount(AssignableDefinition def0 | def0.getTarget() = f) = 1 |
strictcount(AssignableDefinition def0 | def0.getTarget() = f) = 1
|
f.isReadOnly() or
f.isConst() or
isEffectivelyInternalOrPrivate(f)
@@ -53,29 +53,26 @@ module Steps {
}
private predicate flowIn(Parameter p, Expr pred, AssignableRead succ) {
exists(AssignableDefinitions::ImplicitParameterDefinition def, Call c |
succ = getARead(def) |
exists(AssignableDefinitions::ImplicitParameterDefinition def, Call c | succ = getARead(def) |
pred = getArgumentForOverridderParameter(c, p) and
p.getSourceDeclaration() = def.getParameter()
)
}
private Expr getArgumentForOverridderParameter(Call call, Parameter p) {
exists(Parameter base, Callable callable |
result = call.getArgumentForParameter(base) |
exists(Parameter base, Callable callable | result = call.getArgumentForParameter(base) |
base = callable.getAParameter() and
isOverriderParameter(callable, p, base.getPosition())
)
}
pragma [noinline]
pragma[noinline]
private predicate isOverriderParameter(Callable c, Parameter p, int i) {
(
p = c.getAParameter() or
p = c.(Method).getAnOverrider+().getAParameter() or
p = c.(Method).getAnUltimateImplementor().getAParameter()
)
and
) and
i = p.getPosition()
}
@@ -130,13 +127,9 @@ module Steps {
* ```
*/
predicate stepOpen(Expr pred, Expr succ) {
exists(AssignableDefinition def |
succ = getARead(def) |
pred = def.getSource()
)
exists(AssignableDefinition def | succ = getARead(def) | pred = def.getSource())
or
exists(Parameter p |
flowIn(p, pred, succ) |
exists(Parameter p | flowIn(p, pred, succ) |
isEffectivelyInternalOrPrivateCallable(p.getCallable())
)
or

View File

@@ -39,35 +39,29 @@ class DispatchCall extends Internal::TDispatchCall {
/** Internal implementation details. */
private module Internal {
private cached module Cached {
cached
private module Cached {
/** Internal representation of calls. */
cached
newtype TDispatchCall =
TDispatchMethodCall(MethodCall mc) {
not isReflectionCall(mc, _, _, _, _) and
not mc.isLateBound()
}
or
TDispatchAccessorCall(AccessorCall ac)
or
} or
TDispatchAccessorCall(AccessorCall ac) or
TDispatchReflectionCall(MethodCall mc, string name, Expr object, Expr qualifier, int args) {
isReflectionCall(mc, name, object, qualifier, args)
}
or
TDispatchDynamicMethodCall(DynamicMethodCall dmc)
or
TDispatchDynamicOperatorCall(DynamicOperatorCall doc)
or
TDispatchDynamicMemberAccess(DynamicMemberAccess dma)
or
TDispatchDynamicElementAccess(DynamicElementAccess dea)
or
TDispatchDynamicEventAccess(AssignArithmeticOperation aao, DynamicMemberAccess dma, string name) {
} or
TDispatchDynamicMethodCall(DynamicMethodCall dmc) or
TDispatchDynamicOperatorCall(DynamicOperatorCall doc) or
TDispatchDynamicMemberAccess(DynamicMemberAccess dma) or
TDispatchDynamicElementAccess(DynamicElementAccess dea) or
TDispatchDynamicEventAccess(
AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
) {
isPotentialEventCall(aao, dma, name)
}
or
TDispatchDynamicObjectCreation(DynamicObjectCreation doc)
or
} or
TDispatchDynamicObjectCreation(DynamicObjectCreation doc) or
TDispatchStaticCall(Call c) {
c = any(ObjectCreation oc | not oc.isLateBound())
or
@@ -79,19 +73,13 @@ private module Internal {
}
cached
Expr getCall(DispatchCall dc) {
result = dc.(DispatchCallImpl).getCall()
}
Expr getCall(DispatchCall dc) { result = dc.(DispatchCallImpl).getCall() }
cached
Expr getArgument(DispatchCall dc, int i) {
result = dc.(DispatchCallImpl).getArgument(i)
}
Expr getArgument(DispatchCall dc, int i) { result = dc.(DispatchCallImpl).getArgument(i) }
cached
Expr getQualifier(DispatchCall dc) {
result = dc.(DispatchCallImpl).getQualifier()
}
Expr getQualifier(DispatchCall dc) { result = dc.(DispatchCallImpl).getQualifier() }
cached
RuntimeCallable getADynamicTarget(DispatchCall dc) {
@@ -100,9 +88,7 @@ private module Internal {
}
import Cached
Callable getAStaticTarget(DispatchCall dc) {
result = dc.(DispatchCallImpl).getAStaticTarget()
}
Callable getAStaticTarget(DispatchCall dc) { result = dc.(DispatchCallImpl).getAStaticTarget() }
/**
* Holds if `mc` is a reflection call to a method named `name`, where
@@ -110,7 +96,9 @@ private module Internal {
* static method is invoked) and `qualifier` is the qualifier of the
* reflection call.
*/
private predicate isReflectionCall(MethodCall mc, string name, Expr object, Expr qualifier, int args) {
private predicate isReflectionCall(
MethodCall mc, string name, Expr object, Expr qualifier, int args
) {
exists(SystemTypeClass stc |
mc.getTarget() = stc.getInvokeMemberMethod() and
mc.getArgument(0).getValue() = name and
@@ -155,11 +143,14 @@ private module Internal {
* potential event access and `name` is the name of the relevant event
* accessor.
*/
private predicate isPotentialEventCall(AssignArithmeticOperation aao, DynamicMemberAccess dma, string name) {
private predicate isPotentialEventCall(
AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
) {
exists(DynamicOperatorCall doc, AssignExpr ae |
ae = aao.getExpandedAssignment() and
dma = ae.getLValue() and
doc = ae.getRValue() |
doc = ae.getRValue()
|
aao instanceof AssignAddExpr and
name = "add_" + dma.getLateBoundTargetName()
or
@@ -169,7 +160,7 @@ private module Internal {
}
/** A call. */
private abstract class DispatchCallImpl extends TDispatchCall {
abstract private class DispatchCallImpl extends TDispatchCall {
/** Gets a textual representation of this call. */
string toString() { none() }
@@ -180,9 +171,7 @@ private module Internal {
abstract Expr getArgument(int i);
/** Gets the number of arguments of this call. */
int getNumberOfArguments() {
result = count(int i | exists(getArgument(i)))
}
int getNumberOfArguments() { result = count(int i | exists(getArgument(i))) }
/** Gets the qualifier of this call, if any. */
abstract Expr getQualifier();
@@ -199,8 +188,7 @@ private module Internal {
* the qualifier is guaranteed not to be a subtype of `qualifierType`.
*/
predicate hasQualifierType(Type qualifierType, boolean isExactType) {
exists(Type trackedType |
trackedType = getAPossibleType(this.getQualifier(), isExactType) |
exists(Type trackedType | trackedType = getAPossibleType(this.getQualifier(), isExactType) |
qualifierType = trackedType and
not qualifierType instanceof TypeParameter
or
@@ -213,18 +201,15 @@ private module Internal {
* that does not contain type parameters.
*/
TypeWithoutTypeParameters getANonExactQualifierTypeWithoutTypeParameters() {
exists(Type qualifierType |
hasQualifierType(qualifierType, false) |
exists(Type qualifierType | hasQualifierType(qualifierType, false) |
// Qualifier type contains no type parameters: use it
result = qualifierType
or
// Qualifier type is a constructed type where all type arguments are type
// parameters: use the unbound generic type
exists(ConstructedType ct |
ct = qualifierType
and
forex(Type arg | arg = ct.getATypeArgument() | arg instanceof TypeParameter)
and
ct = qualifierType and
forex(Type arg | arg = ct.getATypeArgument() | arg instanceof TypeParameter) and
result = ct.getUnboundGeneric()
)
or
@@ -249,8 +234,13 @@ private module Internal {
*/
private Type getAPossibleType(Expr e, boolean isExact) {
exists(ValueOrRefType qualifierType, FieldOrProperty fp, boolean qualifierTypeIsExact |
qualifierType = getAPossibleTypeDynamicMemberAccessQualifier(e, qualifierTypeIsExact, fp) |
(if qualifierTypeIsExact = true then qualifierType.hasMember(fp) else fp.getDeclaringType().isImplicitlyConvertibleTo(qualifierType)) and
qualifierType = getAPossibleTypeDynamicMemberAccessQualifier(e, qualifierTypeIsExact, fp)
|
(
if qualifierTypeIsExact = true
then qualifierType.hasMember(fp)
else fp.getDeclaringType().isImplicitlyConvertibleTo(qualifierType)
) and
result = fp.getType() and
isExact = false
)
@@ -259,7 +249,9 @@ private module Internal {
result = getASourceType(e, isExact)
}
private Type getAPossibleTypeDynamicMemberAccessQualifier(DynamicMemberAccess dma, boolean isExact, FieldOrProperty fp) {
private Type getAPossibleTypeDynamicMemberAccessQualifier(
DynamicMemberAccess dma, boolean isExact, FieldOrProperty fp
) {
result = getAPossibleType(dma.getQualifier(), isExact) and
fp.getName() = dma.getLateBoundTargetName()
}
@@ -278,8 +270,7 @@ private module Internal {
or
t.getAChild*() instanceof DynamicType
or
exists(Type other |
other != t |
exists(Type other | other != t |
not other instanceof DynamicType and
other.isImplicitlyConvertibleTo(t)
)
@@ -299,7 +290,8 @@ private module Internal {
or
exists(Assignable a |
a instanceof Field or
a instanceof Property |
a instanceof Property
|
succ.(AssignableRead) = a.getAnAccess() and
pred = a.getAnAssignedValue() and
a = any(Modifiable m | m.isEffectivelyInternal() or m.isEffectivelyPrivate())
@@ -314,12 +306,9 @@ private module Internal {
typeMayBeImprecise(succ.getType())
}
private predicate stepTC(Expr succ, Expr pred) =
fastTC(stepExpr/2)(succ, pred)
private predicate stepTC(Expr succ, Expr pred) = fastTC(stepExpr/2)(succ, pred)
private class Source extends Expr {
Source() { not stepExpr(this, _) }
}
private class Source extends Expr { Source() { not stepExpr(this, _) } }
private class Sink extends Expr {
Sink() {
@@ -329,7 +318,8 @@ private module Internal {
or
this = any(DispatchReflectionOrDynamicCall c).getArgument(_)
or
this = any(MethodCall mc | mc.getTarget() = any(SystemObjectClass c).getGetTypeMethod()).getQualifier()
this = any(MethodCall mc | mc.getTarget() = any(SystemObjectClass c).getGetTypeMethod())
.getQualifier()
or
this = any(DispatchCallImpl c).getQualifier()
}
@@ -347,7 +337,8 @@ private module Internal {
Type getASourceType(Sink e, boolean isExact) {
exists(Source s |
s = e.getASource() or
s = e |
s = e
|
result = s.getType() and
if hasExactType(s) then isExact = true else isExact = false
)
@@ -362,25 +353,18 @@ private module Internal {
* into account.
*/
private class DispatchMethodCall extends DispatchCallImpl, TDispatchMethodCall {
override MethodCall getCall() {
this = TDispatchMethodCall(result)
}
override MethodCall getCall() { this = TDispatchMethodCall(result) }
override Expr getArgument(int i) {
exists(Call call, Parameter p |
call = this.getCall() |
exists(Call call, Parameter p | call = this.getCall() |
p = call.getTarget().getParameter(i) and
result = call.getArgumentForParameter(p)
)
}
override Expr getQualifier() {
result = getCall().getQualifier()
}
override Expr getQualifier() { result = getCall().getQualifier() }
override Method getAStaticTarget() {
result = getCall().getTarget()
}
override Method getAStaticTarget() { result = getCall().getTarget() }
override RuntimeMethod getADynamicTarget() {
result = getViableInherited()
@@ -489,29 +473,19 @@ private module Internal {
* into account.
*/
private class DispatchAccessorCall extends DispatchCallImpl, TDispatchAccessorCall {
override AccessorCall getCall() {
this = TDispatchAccessorCall(result)
}
override AccessorCall getCall() { this = TDispatchAccessorCall(result) }
override Expr getArgument(int i) {
result = getCall().getArgument(i)
}
override Expr getArgument(int i) { result = getCall().getArgument(i) }
override Expr getQualifier() {
result = getCall().(MemberAccess).getQualifier()
}
override Expr getQualifier() { result = getCall().(MemberAccess).getQualifier() }
override Accessor getAStaticTarget() {
result = getCall().getTarget()
}
override Accessor getAStaticTarget() { result = getCall().getTarget() }
override RuntimeAccessor getADynamicTarget() {
result = getADynamicTargetCandidate()
and
result = getADynamicTargetCandidate() and
// Calls to accessors may have `dynamic` expression arguments,
// so we need to check that the types match
forall(Type argumentType, int i |
hasDynamicArg(i, argumentType) |
forall(Type argumentType, int i | hasDynamicArg(i, argumentType) |
argumentType.isImplicitlyConvertibleTo(result.getParameter(i).getType())
)
}
@@ -576,7 +550,7 @@ private module Internal {
)
}
pragma [noinline]
pragma[noinline]
private predicate hasQualifierTypeSourceDecl(SourceDeclarationType t) {
exists(Type qualifierType |
this.hasQualifierType(qualifierType, _) and
@@ -629,7 +603,7 @@ private module Internal {
}
/** An internal helper class for comparing two types modulo type parameters. */
private abstract class StructurallyComparedModuloTypeParameters extends Type {
abstract private class StructurallyComparedModuloTypeParameters extends Type {
/** Gets a candidate for comparison against this type. */
abstract Type getACandidate();
@@ -657,9 +631,7 @@ private module Internal {
* by different types at different positions. For example,
* `C<int, string>` is considered a potential instantiation of `C<T, T>`.
*/
TypeWithoutTypeParameters getAPotentialInstance() {
equalsModuloTypeParameters(result)
}
TypeWithoutTypeParameters getAPotentialInstance() { equalsModuloTypeParameters(result) }
}
private Type candidateInternal(Type t) {
@@ -674,8 +646,7 @@ private module Internal {
/** Holds if types `x` and `y` are equal modulo type parameters. */
private predicate sameModuloTypeParameters(Type x, Type y) {
y = candidateInternal(x)
and
y = candidateInternal(x) and
(
x = y
or
@@ -683,21 +654,18 @@ private module Internal {
or
y instanceof TypeParameter
or
// They must have the same kind.
(
// They must have the same kind.
(
x instanceof PointerType and y instanceof PointerType
or
x instanceof NullableType and y instanceof NullableType
or
x.(ArrayType).hasSameShapeAs((ArrayType)y)
or
x.(ConstructedType).getUnboundGeneric() = y.(ConstructedType).getUnboundGeneric()
)
and
// All of their corresponding children must be structurally equal
sameChildrenModuloTypeParameters(x, y, x.getNumberOfChildren() - 1)
)
x instanceof PointerType and y instanceof PointerType
or
x instanceof NullableType and y instanceof NullableType
or
x.(ArrayType).hasSameShapeAs(y.(ArrayType))
or
x.(ConstructedType).getUnboundGeneric() = y.(ConstructedType).getUnboundGeneric()
) and
// All of their corresponding children must be structurally equal
sameChildrenModuloTypeParameters(x, y, x.getNumberOfChildren() - 1)
)
}
@@ -713,8 +681,7 @@ private module Internal {
sameModuloTypeParameters(xChild, yChild)
)
or
exists(Type xChild, Type yChild |
sameChildrenModuloTypeParameters(x, y, i - 1) |
exists(Type xChild, Type yChild | sameChildrenModuloTypeParameters(x, y, i - 1) |
candidateChildren(x, i, xChild, yChild) and
yChild = y.getChild(i) and
sameModuloTypeParameters(xChild, yChild)
@@ -722,8 +689,7 @@ private module Internal {
}
private predicate candidateChildren(Type x, int i, Type xChild, Type yChild) {
exists(Type y |
y = candidateInternal(x) |
exists(Type y | y = candidateInternal(x) |
xChild = x.getChild(i) and
yChild = y.getChild(i)
)
@@ -735,22 +701,19 @@ private module Internal {
*/
private class QualifierTypeWithTypeParameters extends StructurallyComparedModuloTypeParameters {
QualifierTypeWithTypeParameters() {
containsTypeParameters()
and
any(DispatchCallImpl dc).hasQualifierType(this, false)
and
containsTypeParameters() and
any(DispatchCallImpl dc).hasQualifierType(this, false) and
exists(Type arg | arg = getAChild() | not arg instanceof TypeParameter)
}
override ConstructedType getACandidate() {
not result.containsTypeParameters()
and
not result.containsTypeParameters() and
this.(ConstructedType).getUnboundGeneric() = result.getUnboundGeneric()
}
}
/** A reflection-based call or a call using dynamic types. */
private abstract class DispatchReflectionOrDynamicCall extends DispatchCallImpl {
abstract private class DispatchReflectionOrDynamicCall extends DispatchCallImpl {
/** Gets the name of the callable being called in this call. */
abstract string getName();
@@ -792,8 +755,7 @@ private module Internal {
this.hasQualifierType(result, true)
or
// Non-exact qualifier type
exists(Type qualifierType |
this.hasNonExactQualifierType(qualifierType) |
exists(Type qualifierType | this.hasNonExactQualifierType(qualifierType) |
result = getANonExactQualifierSubType(qualifierType)
)
}
@@ -807,8 +769,7 @@ private module Internal {
* `dynamic`).
*/
private predicate hasUnknownQualifierType() {
exists(Type qualifierType |
this.hasNonExactQualifierType(qualifierType) |
exists(Type qualifierType | this.hasNonExactQualifierType(qualifierType) |
isUnknownType(qualifierType)
)
}
@@ -818,18 +779,16 @@ private module Internal {
* names and number of parameters. This set is further reduced in
* `getADynamicTarget()` by taking type information into account.
*/
override Callable getAStaticTarget() {
result = getACallableWithMatchingName()
and
result = getACallableWithMatchingName() and
exists(int minArgs |
minArgs = count(Parameter p |
p = result.getAParameter() and
not p.hasDefaultValue() and
not p.isParams()
)
and
getNumberOfArguments() >= minArgs
and
p = result.getAParameter() and
not p.hasDefaultValue() and
not p.isParams()
) and
getNumberOfArguments() >= minArgs and
(result.(Method).hasParams() or getNumberOfArguments() <= result.getNumberOfParameters())
)
}
@@ -857,13 +816,12 @@ private module Internal {
* conflicting types (for example, `Tuple<int, string>` is considered
* compatible with `Tuple<T, T>`).
*/
override RuntimeCallable getADynamicTarget() {
// Condition 1
result = getADynamicTargetCandidate()
and
result = getADynamicTargetCandidate() and
// Condition 2
forall(int i |
i in [0 .. getNumberOfArguments() - 1] |
forall(int i | i in [0 .. getNumberOfArguments() - 1] |
result = getADynamicTargetCandidateWithCompatibleArg(i)
)
}
@@ -873,13 +831,13 @@ private module Internal {
result = getADynamicTargetCandidateWithCompatibleArg2(i)
}
pragma [noinline]
pragma[noinline]
private RuntimeCallable getADynamicTargetCandidateWithCompatibleArg1(int i) {
result = this.getADynamicTargetCandidate()
and
result = this.getADynamicTargetCandidate() and
exists(Type parameterType, Type argumentType |
parameterType = this.getAParameterType(result, i) and
argumentType = getAPossibleType(this.getArgument(i), _) |
argumentType = getAPossibleType(this.getArgument(i), _)
|
argumentType.isImplicitlyConvertibleTo(parameterType)
or
argumentType instanceof NullType and
@@ -891,10 +849,8 @@ private module Internal {
}
private Type getAParameterType(RuntimeCallable c, int i) {
exists(this.getArgument(i))
and
c = this.getADynamicTargetCandidate()
and
exists(this.getArgument(i)) and
c = this.getADynamicTargetCandidate() and
(
result = c.getParameter(i).getType()
or
@@ -903,18 +859,16 @@ private module Internal {
)
}
pragma [noinline]
pragma[noinline]
private RuntimeCallable getADynamicTargetCandidateWithCompatibleArg2(int i) {
result = this.getADynamicTargetCandidate()
and
exists(Type parameterType, Type t |
parameterType = this.getAParameterType(result, i) |
result = this.getADynamicTargetCandidate() and
exists(Type parameterType, Type t | parameterType = this.getAParameterType(result, i) |
this.argumentConvConstExpr(i, t) and
t.isImplicitlyConvertibleTo(parameterType)
)
}
pragma [noinline]
pragma[noinline]
private predicate argumentConvConstExpr(int i, Type t) {
convConstantExpr(this.getArgument(i), t)
}
@@ -931,8 +885,7 @@ private module Internal {
* type of one of the arguments.
*/
RuntimeCallable getADynamicTargetCandidate() {
result = getAStaticTarget()
and
result = getAStaticTarget() and
(
result = getADynamicTargetCandidateInstanceMethod(this.getAQualifierType())
or
@@ -948,14 +901,14 @@ private module Internal {
)
}
pragma [noinline]
pragma[noinline]
private RuntimeOperator getADynamicTargetCandidateOperator() {
result = getAStaticTarget() and
result.getDeclaringType() = result.getAParameter().getType()
}
}
pragma [noinline]
pragma[noinline]
private RuntimeInstanceMethod getADynamicTargetCandidateInstanceMethod(RefType qualifierType) {
exists(DispatchReflectionOrDynamicCall c |
result = c.getAStaticTarget() and
@@ -963,7 +916,7 @@ private module Internal {
)
}
pragma [noinline]
pragma[noinline]
private RuntimeInstanceAccessor getADynamicTargetCandidateInstanceAccessor(RefType qualifierType) {
exists(DispatchReflectionOrDynamicCall c |
result = c.getAStaticTarget() and
@@ -976,7 +929,7 @@ private module Internal {
t instanceof ObjectType
}
pragma [noinline]
pragma[noinline]
private RefType getANonExactQualifierSubType(Type qualifierType) {
isRelevantReflectionOrDynamicQualifierType(result) and
result.isImplicitlyConvertibleTo(qualifierType) and
@@ -984,29 +937,32 @@ private module Internal {
not result instanceof NullType // null types are implicitly convertible to all types, but not actual subtypes
}
pragma [noinline]
pragma[noinline]
private predicate isRelevantReflectionOrDynamicQualifierType(RefType rt) {
rt.hasCallable(any(DispatchReflectionOrDynamicCall c).getAStaticTarget())
}
private predicate reflectionOrDynamicArgEqualsParamModuloTypeParameters(Type argumentType, Type parameterType) {
exists(Type t |
reflectionOrDynamicArgumentTypeIsImplicitlyConvertibleTo(argumentType,t) |
t.(ReflectionOrDynamicCallArgumentWithTypeParameters).equalsModuloTypeParameters(parameterType)
private predicate reflectionOrDynamicArgEqualsParamModuloTypeParameters(
Type argumentType, Type parameterType
) {
exists(Type t | reflectionOrDynamicArgumentTypeIsImplicitlyConvertibleTo(argumentType, t) |
t
.(ReflectionOrDynamicCallArgumentWithTypeParameters)
.equalsModuloTypeParameters(parameterType)
)
}
pragma [noinline]
private predicate reflectionOrDynamicArgumentTypeIsImplicitlyConvertibleTo(Type argumentType, Type t) {
pragma[noinline]
private predicate reflectionOrDynamicArgumentTypeIsImplicitlyConvertibleTo(
Type argumentType, Type t
) {
isReflectionOrDynamicArgumentType(argumentType) and
argumentType.isImplicitlyConvertibleTo(t)
}
pragma [noinline]
pragma[noinline]
private predicate isReflectionOrDynamicArgumentType(Type t) {
exists(DispatchReflectionOrDynamicCall c |
t = getAPossibleType(c.getArgument(_), _)
)
exists(DispatchReflectionOrDynamicCall c | t = getAPossibleType(c.getArgument(_), _))
}
/**
@@ -1017,17 +973,19 @@ private module Internal {
*/
private predicate isReflectionOrDynamicCallArgumentWithTypeParameters(Type argType, Type paramType) {
exists(DispatchReflectionOrDynamicCall call, Parameter p, int i, int j |
p = call.getAStaticTarget().getParameter(i)
and
if p.isParams() then (
j >= i and
paramType = p.getType().(ArrayType).getElementType()
) else (
i = j and
paramType = p.getType()
)
and
argType = getAPossibleType(call.getArgument(j), _) |
p = call.getAStaticTarget().getParameter(i) and
(
if p.isParams()
then (
j >= i and
paramType = p.getType().(ArrayType).getElementType()
) else (
i = j and
paramType = p.getType()
)
) and
argType = getAPossibleType(call.getArgument(j), _)
|
argType.containsTypeParameters()
or
paramType.containsTypeParameters()
@@ -1050,14 +1008,11 @@ private module Internal {
}
/** A call using reflection. */
private class DispatchReflectionCall extends DispatchReflectionOrDynamicCall, TDispatchReflectionCall {
override MethodCall getCall() {
this = TDispatchReflectionCall(result, _, _, _, _)
}
private class DispatchReflectionCall extends DispatchReflectionOrDynamicCall,
TDispatchReflectionCall {
override MethodCall getCall() { this = TDispatchReflectionCall(result, _, _, _, _) }
override string getName() {
this = TDispatchReflectionCall(_, result, _, _, _)
}
override string getName() { this = TDispatchReflectionCall(_, result, _, _, _) }
override Expr getQualifier() {
this = TDispatchReflectionCall(_, _, result, _, _) and
@@ -1067,10 +1022,8 @@ private module Internal {
/** Gets the type containing the static callable being called, if any. */
private ValueOrRefType getStaticType() {
exists(Expr object, Expr qualifier |
this = TDispatchReflectionCall(_, _, object, qualifier, _)
and
object instanceof NullLiteral
and
this = TDispatchReflectionCall(_, _, object, qualifier, _) and
object instanceof NullLiteral and
(
result = getAMethodCallArgSource(qualifier).(TypeofExpr).getTypeAccess().getType()
or
@@ -1095,48 +1048,38 @@ private module Internal {
// Does not take named arguments into account
override Expr getArgument(int i) {
exists(int args, ArrayCreation ac |
this = TDispatchReflectionCall(_, _, _, _, args)
and
ac = getAMethodCallArgSource(getCall().getArgument(args))
and
this = TDispatchReflectionCall(_, _, _, _, args) and
ac = getAMethodCallArgSource(getCall().getArgument(args)) and
result = ac.getInitializer().getElement(i)
)
}
}
/** A method call using dynamic types. */
private class DispatchDynamicMethodCall extends DispatchReflectionOrDynamicCall, TDispatchDynamicMethodCall {
override DynamicMethodCall getCall() {
this = TDispatchDynamicMethodCall(result)
}
private class DispatchDynamicMethodCall extends DispatchReflectionOrDynamicCall,
TDispatchDynamicMethodCall {
override DynamicMethodCall getCall() { this = TDispatchDynamicMethodCall(result) }
override string getName() {
result = getCall().getLateBoundTargetName()
}
override string getName() { result = getCall().getLateBoundTargetName() }
override Expr getQualifier() {
result = getCall().getQualifier()
}
override Expr getQualifier() { result = getCall().getQualifier() }
override RuntimeMethod getADynamicTargetCandidate() {
if exists(getCall().getTarget()) then
if exists(getCall().getTarget())
then
// static method call
result = getCall().getTarget()
else
result = DispatchReflectionOrDynamicCall.super.getADynamicTargetCandidate()
else result = DispatchReflectionOrDynamicCall.super.getADynamicTargetCandidate()
}
// Does not take named arguments into account
override Expr getArgument(int i) {
result = getCall().getArgument(i)
}
override Expr getArgument(int i) { result = getCall().getArgument(i) }
}
/** An operator call using dynamic types. */
private class DispatchDynamicOperatorCall extends DispatchReflectionOrDynamicCall, TDispatchDynamicOperatorCall {
override DynamicOperatorCall getCall() {
this = TDispatchDynamicOperatorCall(result)
}
private class DispatchDynamicOperatorCall extends DispatchReflectionOrDynamicCall,
TDispatchDynamicOperatorCall {
override DynamicOperatorCall getCall() { this = TDispatchDynamicOperatorCall(result) }
override string getName() {
exists(Operator o |
@@ -1145,33 +1088,25 @@ private module Internal {
)
}
override Expr getQualifier() {
none()
}
override Expr getQualifier() { none() }
override Expr getArgument(int i) {
result = getCall().getArgument(i)
}
override Expr getArgument(int i) { result = getCall().getArgument(i) }
}
/** A (potential) call to a property accessor using dynamic types. */
private class DispatchDynamicMemberAccess extends DispatchReflectionOrDynamicCall, TDispatchDynamicMemberAccess {
override DynamicMemberAccess getCall() {
this = TDispatchDynamicMemberAccess(result)
}
private class DispatchDynamicMemberAccess extends DispatchReflectionOrDynamicCall,
TDispatchDynamicMemberAccess {
override DynamicMemberAccess getCall() { this = TDispatchDynamicMemberAccess(result) }
override string getName() {
exists(DynamicMemberAccess dma |
dma = getCall() |
exists(DynamicMemberAccess dma | dma = getCall() |
result = "get_" + dma.(DynamicMemberRead).getLateBoundTargetName()
or
result = "set_" + dma.(DynamicMemberWrite).getLateBoundTargetName()
)
}
override Expr getQualifier() {
result = getCall().getQualifier()
}
override Expr getQualifier() { result = getCall().getQualifier() }
override Expr getArgument(int i) {
// Only calls to setters have an argument
@@ -1184,27 +1119,22 @@ private module Internal {
}
/** A (potential) call to an indexer accessor using dynamic types. */
private class DispatchDynamicElementAccess extends DispatchReflectionOrDynamicCall, TDispatchDynamicElementAccess {
override DynamicElementAccess getCall() {
this = TDispatchDynamicElementAccess(result)
}
private class DispatchDynamicElementAccess extends DispatchReflectionOrDynamicCall,
TDispatchDynamicElementAccess {
override DynamicElementAccess getCall() { this = TDispatchDynamicElementAccess(result) }
override string getName() {
exists(DynamicElementAccess dea |
dea = getCall() |
exists(DynamicElementAccess dea | dea = getCall() |
dea instanceof DynamicElementRead and result = "get_Item"
or
dea instanceof DynamicElementWrite and result = "set_Item"
)
}
override Expr getQualifier() {
result = getCall().getQualifier()
}
override Expr getQualifier() { result = getCall().getQualifier() }
override Expr getArgument(int i) {
exists(DynamicElementAccess dea |
dea = getCall() |
exists(DynamicElementAccess dea | dea = getCall() |
result = dea.getIndex(i)
or
// Calls to setters have an extra argument
@@ -1216,71 +1146,51 @@ private module Internal {
}
/** A (potential) call to an event accessor using dynamic types. */
private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall, TDispatchDynamicEventAccess {
private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall,
TDispatchDynamicEventAccess {
override AssignArithmeticOperation getCall() {
this = TDispatchDynamicEventAccess(result, _, _)
}
override string getName() {
this = TDispatchDynamicEventAccess(_, _, result)
}
override string getName() { this = TDispatchDynamicEventAccess(_, _, result) }
override Expr getQualifier() {
result = any(DynamicMemberAccess dma | this = TDispatchDynamicEventAccess(_, dma, _)).getQualifier()
result = any(DynamicMemberAccess dma | this = TDispatchDynamicEventAccess(_, dma, _))
.getQualifier()
}
override Expr getArgument(int i) {
i = 0 and result = getCall().getRValue()
}
override Expr getArgument(int i) { i = 0 and result = getCall().getRValue() }
}
/** A call to a constructor using dynamic types. */
private class DispatchDynamicObjectCreation extends DispatchReflectionOrDynamicCall, TDispatchDynamicObjectCreation {
override DynamicObjectCreation getCall() {
this = TDispatchDynamicObjectCreation(result)
}
private class DispatchDynamicObjectCreation extends DispatchReflectionOrDynamicCall,
TDispatchDynamicObjectCreation {
override DynamicObjectCreation getCall() { this = TDispatchDynamicObjectCreation(result) }
override string getName() {
none()
}
override string getName() { none() }
override Expr getQualifier() {
none()
}
override Expr getQualifier() { none() }
override Expr getArgument(int i) {
result = getCall().getArgument(i)
}
override Expr getArgument(int i) { result = getCall().getArgument(i) }
override RuntimeCallable getADynamicTargetCandidate() {
result = getCall().getTarget()
}
override RuntimeCallable getADynamicTargetCandidate() { result = getCall().getTarget() }
}
/** A call where the target can be resolved statically. */
private class DispatchStaticCall extends DispatchCallImpl, TDispatchStaticCall {
override Call getCall() {
this = TDispatchStaticCall(result)
}
override Call getCall() { this = TDispatchStaticCall(result) }
override Expr getQualifier() {
none()
}
override Expr getQualifier() { none() }
override Expr getArgument(int i) {
exists(Call call, Parameter p |
call = this.getCall() |
exists(Call call, Parameter p | call = this.getCall() |
p = call.getTarget().getParameter(i) and
result = call.getArgumentForParameter(p)
)
}
override Callable getAStaticTarget() {
result = getCall().getTarget()
}
override Callable getAStaticTarget() { result = getCall().getTarget() }
override RuntimeCallable getADynamicTarget() {
result = getCall().getTarget()
}
override RuntimeCallable getADynamicTarget() { result = getCall().getTarget() }
}
}

View File

@@ -2,6 +2,7 @@
* Provides classes that define callables that can be overridden or
* implemented.
*/
import csharp
/**
@@ -134,8 +135,7 @@ class OverridableCallable extends Callable {
* - `C2.M = C2.M.getInherited(C3)`.
*/
Callable getInherited(SourceDeclarationType t) {
exists(Callable sourceDecl |
result = getInherited1(t, sourceDecl) |
exists(Callable sourceDecl | result = getInherited1(t, sourceDecl) |
hasSourceDeclarationCallable(t, sourceDecl)
)
}
@@ -159,13 +159,13 @@ class OverridableCallable extends Callable {
sourceDecl = result.getSourceDeclaration()
}
pragma [noinline]
pragma[noinline]
private ValueOrRefType hasOverrider(Callable c) {
c = this.getAnOverrider*() and
result = c.getDeclaringType()
}
pragma [noinline]
pragma[noinline]
private ValueOrRefType hasOverridingImplementor(Callable c) {
c = this.getAnOverridingImplementor() and
result = c.getDeclaringType()
@@ -207,10 +207,8 @@ class OverridableCallable extends Callable {
}
private TypeWithoutTypeParameters getAnOverriderBaseType(ValueOrRefType t) {
exists(getAnOverriderAux(t))
and
exists(Type t0 |
t0 = t.getABaseType*() |
exists(getAnOverriderAux(t)) and
exists(Type t0 | t0 = t.getABaseType*() |
result = t0
or
result = t0.(ConstructedType).getUnboundGeneric()
@@ -238,8 +236,7 @@ class OverridableCallable extends Callable {
}
private predicate declaredInTypeWithTypeParameters() {
exists(ValueOrRefType t |
t = getDeclaringType() |
exists(ValueOrRefType t | t = getDeclaringType() |
t.containsTypeParameters()
or
// Access to a local callable, `this.M()`, in a generic class
@@ -250,27 +247,18 @@ class OverridableCallable extends Callable {
}
}
pragma [noinline]
pragma[noinline]
private predicate hasSourceDeclarationCallable(ValueOrRefType t, Callable sourceDecl) {
exists(Callable c |
t.hasCallable(c) |
sourceDecl = c.getSourceDeclaration()
)
exists(Callable c | t.hasCallable(c) | sourceDecl = c.getSourceDeclaration())
}
/** An overridable method. */
class OverridableMethod extends Method, OverridableCallable {
override Method getAnOverrider() {
result = Method.super.getAnOverrider()
}
override Method getAnOverrider() { result = Method.super.getAnOverrider() }
override Method getAnImplementor(ValueOrRefType t) {
result = Method.super.getAnImplementor(t)
}
override Method getAnImplementor(ValueOrRefType t) { result = Method.super.getAnImplementor(t) }
override Method getAnUltimateImplementor() {
result = Method.super.getAnUltimateImplementor()
}
override Method getAnUltimateImplementor() { result = Method.super.getAnUltimateImplementor() }
override Method getInherited(SourceDeclarationType t) {
result = OverridableCallable.super.getInherited(t)
@@ -283,9 +271,7 @@ class OverridableMethod extends Method, OverridableCallable {
/** An overridable accessor. */
class OverridableAccessor extends Accessor, OverridableCallable {
override Accessor getAnOverrider() {
overrides(result, this)
}
override Accessor getAnOverrider() { overrides(result, this) }
override Accessor getAnImplementor(ValueOrRefType t) {
exists(Virtualizable implementor, int kind |
@@ -337,14 +323,10 @@ private int getAccessorKind(Accessor a) {
/** A type not containing type parameters. */
class TypeWithoutTypeParameters extends Type {
TypeWithoutTypeParameters() {
not containsTypeParameters()
}
TypeWithoutTypeParameters() { not containsTypeParameters() }
}
/** A source declared type. */
class SourceDeclarationType extends TypeWithoutTypeParameters {
SourceDeclarationType() {
this = getSourceDeclaration()
}
SourceDeclarationType() { this = getSourceDeclaration() }
}

View File

@@ -3,6 +3,7 @@
* those callables that may actually be called at run-time (that is, neither
* abstract callables nor callables defined in an interface).
*/
import csharp
private import cil
private import dotnet
@@ -25,17 +26,11 @@ class RuntimeMethod extends RuntimeCallable {
this instanceof CIL::Method
}
predicate isStatic() {
this.(Method).isStatic() or this.(CIL::Method).isStatic()
}
predicate isStatic() { this.(Method).isStatic() or this.(CIL::Method).isStatic() }
}
/** A run-time instance method. */
class RuntimeInstanceMethod extends RuntimeMethod {
RuntimeInstanceMethod() {
not isStatic()
}
}
class RuntimeInstanceMethod extends RuntimeMethod { RuntimeInstanceMethod() { not isStatic() } }
/** A run-time operator. */
class RuntimeOperator extends Operator, RuntimeCallable { }
@@ -45,7 +40,5 @@ class RuntimeAccessor extends Accessor, RuntimeCallable { }
/** A run-time instance accessor. */
class RuntimeInstanceAccessor extends RuntimeAccessor {
RuntimeInstanceAccessor() {
not isStatic()
}
RuntimeInstanceAccessor() { not isStatic() }
}

View File

@@ -23,16 +23,17 @@ class Access extends Expr, @access_expr {
/**
* An internal helper module to calculate accesses and their targets.
*/
private cached module AccessImpl {
cached predicate isAccess(@access_expr ae) {
cached
private module AccessImpl {
cached
predicate isAccess(@access_expr ae) {
isLocalVariableAccess(ae) implies exists(getLocalVariableAccessTarget(ae))
}
private predicate isLocalVariableAccess(@local_variable_access a) {
any()
}
private predicate isLocalVariableAccess(@local_variable_access a) { any() }
cached LocalVariable getLocalVariableAccessTarget(@local_variable_access a) {
cached
LocalVariable getLocalVariableAccessTarget(@local_variable_access a) {
result = getLocalVariableAccessTargetNoDecl(a) or
result = getLocalVariableAccessTargetDecl(a)
}
@@ -74,9 +75,7 @@ private cached module AccessImpl {
* ```
*/
class ThisAccess extends Access, @this_access_expr {
override Class getTarget() {
result = this.getEnclosingCallable().getDeclaringType()
}
override Class getTarget() { result = this.getEnclosingCallable().getDeclaringType() }
override string toString() { result = "this access" }
}
@@ -108,8 +107,7 @@ class BaseAccess extends Access, @base_access_expr {
*/
class MemberAccess extends Access, QualifiableExpr, @member_access_expr {
override predicate hasImplicitThisQualifier() {
QualifiableExpr.super.hasImplicitThisQualifier()
and
QualifiableExpr.super.hasImplicitThisQualifier() and
not exists(MemberInitializer mi | mi.getLValue() = this)
}
@@ -132,17 +130,13 @@ class AssignableAccess extends Access, @assignable_access_expr {
* Holds if this access passes the assignable being accessed as an `out`
* argument in a method call.
*/
predicate isOutArgument() {
expr_argument(this, 2)
}
predicate isOutArgument() { expr_argument(this, 2) }
/**
* Holds if this access passes the assignable being accessed as a `ref`
* argument in a method call.
*/
predicate isRefArgument() {
expr_argument(this, 1)
}
predicate isRefArgument() { expr_argument(this, 1) }
/**
* Holds if this access passes the assignable being accessed as an `out`
@@ -157,9 +151,7 @@ class AssignableAccess extends Access, @assignable_access_expr {
* Holds if this access passes the assignable being accessed as an `in`
* argument in a method call.
*/
predicate isInArgument() {
expr_argument(this, 3)
}
predicate isInArgument() { expr_argument(this, 3) }
}
/**
@@ -167,9 +159,7 @@ class AssignableAccess extends Access, @assignable_access_expr {
* (`LocalScopeVariableAccess`) or an access to a field (`FieldAccess`).
*/
class VariableAccess extends AssignableAccess, @variable_access_expr {
override Variable getTarget() {
expr_access(this, result)
}
override Variable getTarget() { expr_access(this, result) }
}
/**
@@ -178,13 +168,9 @@ class VariableAccess extends AssignableAccess, @variable_access_expr {
* access to a field (`FieldRead`).
*/
class VariableRead extends VariableAccess, AssignableRead {
override VariableRead getANextRead() {
result = AssignableRead.super.getANextRead()
}
override VariableRead getANextRead() { result = AssignableRead.super.getANextRead() }
override VariableRead getAReachableRead() {
result = AssignableRead.super.getAReachableRead()
}
override VariableRead getAReachableRead() { result = AssignableRead.super.getAReachableRead() }
}
/**
@@ -199,9 +185,7 @@ class VariableWrite extends VariableAccess, AssignableWrite { }
* (`ParameterAccess`) or an access to a local variable (`LocalVariableAccess`).
*/
class LocalScopeVariableAccess extends VariableAccess, @local_scope_variable_access_expr {
override LocalScopeVariable getTarget() {
expr_access(this, result)
}
override LocalScopeVariable getTarget() { expr_access(this, result) }
}
/**
@@ -210,9 +194,7 @@ class LocalScopeVariableAccess extends VariableAccess, @local_scope_variable_acc
* (`LocalVariableRead`).
*/
class LocalScopeVariableRead extends LocalScopeVariableAccess, VariableRead {
override LocalScopeVariableRead getANextRead() {
result = VariableRead.super.getANextRead()
}
override LocalScopeVariableRead getANextRead() { result = VariableRead.super.getANextRead() }
override LocalScopeVariableRead getAReachableRead() {
result = VariableRead.super.getAReachableRead()
@@ -236,13 +218,9 @@ class LocalScopeVariableWrite extends LocalScopeVariableAccess, VariableWrite {
* ```
*/
class ParameterAccess extends LocalScopeVariableAccess, @parameter_access_expr {
override Parameter getTarget() {
expr_access(this, result)
}
override Parameter getTarget() { expr_access(this, result) }
override string toString() {
result = "access to parameter " + this.getTarget().getName()
}
override string toString() { result = "access to parameter " + this.getTarget().getName() }
}
/**
@@ -256,9 +234,7 @@ class ParameterAccess extends LocalScopeVariableAccess, @parameter_access_expr {
* ```
*/
class ParameterRead extends ParameterAccess, LocalScopeVariableRead {
override ParameterRead getANextRead() {
result = LocalScopeVariableRead.super.getANextRead()
}
override ParameterRead getANextRead() { result = LocalScopeVariableRead.super.getANextRead() }
override ParameterRead getAReachableRead() {
result = LocalScopeVariableRead.super.getAReachableRead()
@@ -289,9 +265,7 @@ class ParameterWrite extends ParameterAccess, VariableWrite { }
* ```
*/
class LocalVariableAccess extends LocalScopeVariableAccess, @local_variable_access {
override LocalVariable getTarget() {
result = AccessImpl::getLocalVariableAccessTarget(this)
}
override LocalVariable getTarget() { result = AccessImpl::getLocalVariableAccessTarget(this) }
override string toString() {
// If this access is also a local variable declaration (that is, an `out` declared
@@ -313,9 +287,7 @@ class LocalVariableAccess extends LocalScopeVariableAccess, @local_variable_acce
* ```
*/
class LocalVariableRead extends LocalVariableAccess, LocalScopeVariableRead {
override LocalVariableRead getANextRead() {
result = LocalScopeVariableRead.super.getANextRead()
}
override LocalVariableRead getANextRead() { result = LocalScopeVariableRead.super.getANextRead() }
override LocalVariableRead getAReachableRead() {
result = LocalScopeVariableRead.super.getAReachableRead()
@@ -350,13 +322,9 @@ class LocalVariableWrite extends LocalVariableAccess, VariableWrite { }
* ```
*/
class FieldAccess extends AssignableMemberAccess, VariableAccess, @field_access_expr {
override Field getTarget() {
expr_access(this, result)
}
override Field getTarget() { expr_access(this, result) }
override string toString() {
result = "access to field " + this.getTarget().getName()
}
override string toString() { result = "access to field " + this.getTarget().getName() }
}
/**
@@ -420,9 +388,7 @@ library class PropertyAccessExpr extends Expr, @property_access_expr {
/** Gets the target of this property access. */
Property getProperty() { expr_access(this, result) }
override string toString() {
result = "access to property " + this.getProperty().getName()
}
override string toString() { result = "access to property " + this.getProperty().getName() }
}
/**
@@ -457,13 +423,9 @@ class PropertyAccess extends AssignableMemberAccess, PropertyAccessExpr {
* ```
*/
class PropertyRead extends PropertyAccess, AssignableRead {
override PropertyRead getANextRead() {
result = AssignableRead.super.getANextRead()
}
override PropertyRead getANextRead() { result = AssignableRead.super.getANextRead() }
override PropertyRead getAReachableRead() {
result = AssignableRead.super.getAReachableRead()
}
override PropertyRead getAReachableRead() { result = AssignableRead.super.getAReachableRead() }
}
/**
@@ -497,9 +459,7 @@ class PropertyWrite extends PropertyAccess, AssignableWrite { }
* ```
*/
class TrivialPropertyAccess extends PropertyAccess {
TrivialPropertyAccess() {
this.getTarget() instanceof TrivialProperty
}
TrivialPropertyAccess() { this.getTarget() instanceof TrivialProperty }
}
/**
@@ -517,9 +477,7 @@ class TrivialPropertyAccess extends PropertyAccess {
* ```
*/
class VirtualPropertyAccess extends PropertyAccess {
VirtualPropertyAccess() {
this.targetIsOverridableOrImplementable()
}
VirtualPropertyAccess() { this.targetIsOverridableOrImplementable() }
}
/**
@@ -582,9 +540,7 @@ library class IndexerAccessExpr extends Expr, @indexer_access_expr {
* ```
*/
class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccessExpr {
override Indexer getTarget() {
result = getIndexer()
}
override Indexer getTarget() { result = getIndexer() }
override Indexer getQualifiedDeclaration() {
result = ElementAccess.super.getQualifiedDeclaration()
@@ -606,13 +562,9 @@ class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccess
* ```
*/
class IndexerRead extends IndexerAccess, AssignableRead {
override IndexerRead getANextRead() {
result = AssignableRead.super.getANextRead()
}
override IndexerRead getANextRead() { result = AssignableRead.super.getANextRead() }
override IndexerRead getAReachableRead() {
result = AssignableRead.super.getAReachableRead()
}
override IndexerRead getAReachableRead() { result = AssignableRead.super.getAReachableRead() }
}
/**
@@ -645,9 +597,7 @@ class IndexerWrite extends IndexerAccess, AssignableWrite { }
* }
*/
class VirtualIndexerAccess extends IndexerAccess {
VirtualIndexerAccess() {
targetIsOverridableOrImplementable()
}
VirtualIndexerAccess() { targetIsOverridableOrImplementable() }
}
/**
@@ -656,13 +606,9 @@ class VirtualIndexerAccess extends IndexerAccess {
*/
library class EventAccessExpr extends Expr, @event_access_expr {
/** Gets the target of this event access. */
Event getEvent() {
expr_access(this, result)
}
Event getEvent() { expr_access(this, result) }
override string toString() {
result = "access to event " + this.getEvent().getName()
}
override string toString() { result = "access to event " + this.getEvent().getName() }
}
/**
@@ -741,9 +687,7 @@ class EventWrite extends EventAccess, AssignableWrite { }
* ```
*/
class VirtualEventAccess extends EventAccess {
VirtualEventAccess() {
targetIsOverridableOrImplementable()
}
VirtualEventAccess() { targetIsOverridableOrImplementable() }
}
/**
@@ -753,9 +697,7 @@ class VirtualEventAccess extends EventAccess {
* Note that a callable access is *not* the same as a call.
*/
class CallableAccess extends Access, @method_access_expr {
override Callable getTarget() {
expr_access(this, result)
}
override Callable getTarget() { expr_access(this, result) }
}
/**
@@ -774,17 +716,11 @@ class CallableAccess extends Access, @method_access_expr {
* Note that a method access is *not* the same as a method call (`MethodCall`).
*/
class MethodAccess extends MemberAccess, CallableAccess {
MethodAccess() {
expr_access(this, any(Method m))
}
MethodAccess() { expr_access(this, any(Method m)) }
override Method getTarget() {
expr_access(this, result)
}
override Method getTarget() { expr_access(this, result) }
override string toString() {
result = "access to method " + this.getTarget().getName()
}
override string toString() { result = "access to method " + this.getTarget().getName() }
}
/**
@@ -803,17 +739,11 @@ class MethodAccess extends MemberAccess, CallableAccess {
* (`LocalFunctionCall`).
*/
class LocalFunctionAccess extends CallableAccess {
LocalFunctionAccess() {
expr_access(this, any(LocalFunction f))
}
LocalFunctionAccess() { expr_access(this, any(LocalFunction f)) }
override LocalFunction getTarget() {
expr_access(this, result)
}
override LocalFunction getTarget() { expr_access(this, result) }
override string toString() {
result = "access to local function " + this.getTarget().getName()
}
override string toString() { result = "access to local function " + this.getTarget().getName() }
}
/**
@@ -833,9 +763,7 @@ class LocalFunctionAccess extends CallableAccess {
* ```
*/
class VirtualMethodAccess extends MethodAccess {
VirtualMethodAccess() {
targetIsOverridableOrImplementable()
}
VirtualMethodAccess() { targetIsOverridableOrImplementable() }
}
/**
@@ -852,9 +780,7 @@ class VirtualMethodAccess extends MethodAccess {
class TypeAccess extends MemberAccess, @type_access_expr {
override Type getTarget() { result = this.getType() }
override string toString() {
result = "access to type " + this.getTarget().getName()
}
override string toString() { result = "access to type " + this.getTarget().getName() }
}
/**

View File

@@ -3,6 +3,7 @@
*
* All arithmetic operations have the common base class `ArithmeticOperation`.
*/
import Expr
/**
@@ -71,14 +72,14 @@ class PreDecrExpr extends DecrementOperation, @pre_decr_expr { }
* A postfix increment operation, for example `x++`.
*/
class PostIncrExpr extends IncrementOperation, @post_incr_expr {
override string toString() { result = "..." + this.getOperator() }
override string toString() { result = "..." + this.getOperator() }
}
/**
* A postfix decrement operation, for example `x--`.
*/
class PostDecrExpr extends DecrementOperation, @post_decr_expr {
override string toString() { result = "..." + this.getOperator() }
override string toString() { result = "..." + this.getOperator() }
}
/**
@@ -131,4 +132,3 @@ class DivExpr extends BinaryArithmeticOperation, @div_expr {
class RemExpr extends BinaryArithmeticOperation, @rem_expr {
override string getOperator() { result = "%" }
}

View File

@@ -13,7 +13,8 @@ import Expr
*/
class Assignment extends Operation, @assign_expr {
Assignment() {
this instanceof LocalVariableDeclExpr implies
this instanceof LocalVariableDeclExpr
implies
// Same as `this.(LocalVariableDeclExpr).hasInitializer()` but avoids
// negative recursion
expr_parent(_, 0, this)
@@ -37,17 +38,11 @@ class Assignment extends Operation, @assign_expr {
class LocalVariableDeclAndInitExpr extends LocalVariableDeclExpr, Assignment {
override string getOperator() { result = "=" }
override LocalVariable getTargetVariable() {
result = getVariable()
}
override LocalVariable getTargetVariable() { result = getVariable() }
override LocalVariableAccess getLValue() {
result = Assignment.super.getLValue()
}
override LocalVariableAccess getLValue() { result = Assignment.super.getLValue() }
override string toString() {
result = LocalVariableDeclExpr.super.toString() + " = ..."
}
override string toString() { result = LocalVariableDeclExpr.super.toString() + " = ..." }
}
/**
@@ -76,9 +71,7 @@ class AssignOperation extends Assignment, @assign_op_expr {
* If an expanded version exists, then it is used in the control
* flow graph.
*/
AssignExpr getExpandedAssignment() {
expr_parent(result, 2, this)
}
AssignExpr getExpandedAssignment() { expr_parent(result, 2, this) }
/**
* Holds if this assignment operation has an expanded version.
@@ -89,9 +82,7 @@ class AssignOperation extends Assignment, @assign_op_expr {
* If an expanded version exists, then it is used in the control
* flow graph.
*/
predicate hasExpandedAssignment() {
exists(getExpandedAssignment())
}
predicate hasExpandedAssignment() { exists(getExpandedAssignment()) }
override string toString() { result = "... " + this.getOperator() + " ..." }
}
@@ -140,7 +131,6 @@ class AssignRemExpr extends AssignArithmeticOperation, @assign_rem_expr {
override string getOperator() { result = "%=" }
}
/**
* A bitwise assignment operation. Either a bitwise-and assignment
* operation (`AssignAndExpr`), a bitwise-or assignment
@@ -149,8 +139,7 @@ class AssignRemExpr extends AssignArithmeticOperation, @assign_rem_expr {
* operation (`AssignLShiftExpr`), or a right-shift assignment
* operation (`AssignRShiftExpr`).
*/
class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr {
}
class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { }
/**
* A bitwise-and assignment operation, for example `x &= y`.
@@ -162,7 +151,7 @@ class AssignAndExpr extends AssignBitwiseOperation, @assign_and_expr {
/**
* A bitwise-or assignment operation, for example `x |= y`.
*/
class AssignOrExpr extends AssignBitwiseOperation, @assign_or_expr {
class AssignOrExpr extends AssignBitwiseOperation, @assign_or_expr {
override string getOperator() { result = "|=" }
}
@@ -176,14 +165,14 @@ class AssignXorExpr extends AssignBitwiseOperation, @assign_xor_expr {
/**
* A left-shift assignment operation, for example `x <<= y`.
*/
class AssignLShiftExpr extends AssignBitwiseOperation, @assign_lshift_expr {
class AssignLShiftExpr extends AssignBitwiseOperation, @assign_lshift_expr {
override string getOperator() { result = "<<=" }
}
/**
* A right-shift assignment operation, for example `x >>= y`.
*/
class AssignRShiftExpr extends AssignBitwiseOperation, @assign_rshift_expr {
class AssignRShiftExpr extends AssignBitwiseOperation, @assign_rshift_expr {
override string getOperator() { result = ">>=" }
}

View File

@@ -3,6 +3,7 @@
*
* All bitwise operations have the common base class `BitwiseOperation`.
*/
import Expr
/**

View File

@@ -3,6 +3,7 @@
*
* All calls have the common base class `Call`.
*/
import Expr
import semmle.code.csharp.Callable
import semmle.code.csharp.dataflow.CallContext as CallContext
@@ -40,27 +41,17 @@ class Call extends DotNet::Call, Expr, @call {
*/
override Callable getTarget() { none() }
override Expr getArgument(int i) {
result = this.getChild(i) and i >= 0
}
override Expr getArgument(int i) { result = this.getChild(i) and i >= 0 }
override Expr getRawArgument(int i) {
result = this.getArgument(i)
}
override Expr getRawArgument(int i) { result = this.getArgument(i) }
override Expr getAnArgument() {
result = getArgument(_)
}
override Expr getAnArgument() { result = getArgument(_) }
/** Gets the number of arguments of this call. */
int getNumberOfArguments() {
result = count(this.getAnArgument())
}
int getNumberOfArguments() { result = count(this.getAnArgument()) }
/** Holds if this call has no arguments. */
predicate hasNoArguments() {
not exists(this.getAnArgument())
}
predicate hasNoArguments() { not exists(this.getAnArgument()) }
/**
* Gets the argument for this call associated with the parameter `p`, if any.
@@ -86,8 +77,7 @@ class Call extends DotNet::Call, Expr, @call {
* ```
*/
override Expr getArgumentForParameter(DotNet::Parameter p) {
getTarget().getAParameter() = p
and
getTarget().getAParameter() = p and
(
// Appears in the positional part of the call
result = this.getImplicitArgument(p.getPosition()) and
@@ -111,20 +101,21 @@ class Call extends DotNet::Call, Expr, @call {
* of the targeted callable.
*/
private predicate hasMultipleParamsArguments() {
exists(Parameter p |
p = this.getTarget().getAParameter() |
exists(Parameter p | p = this.getTarget().getAParameter() |
p.isParams() and
exists(this.getArgument(any(int i | i > p.getPosition())))
)
}
pragma [noinline] // predicate folding to get proper join-order
// predicate folding to get proper join-order
pragma[noinline]
private Expr getImplicitArgument(int pos) {
result = getArgument(pos) and
not exists(result.getExplicitArgumentName())
}
pragma [noinline] // predicate folding to get proper join-order
// predicate folding to get proper join-order
pragma[noinline]
private Expr getExplicitArgument(string name) {
result = getAnArgument() and
result.getExplicitArgumentName() = name
@@ -248,25 +239,19 @@ class Call extends DotNet::Call, Expr, @call {
* Gets an argument that corresponds to a parameter of a potential
* run-time target of this call.
*/
Expr getARuntimeArgument() {
result = getRuntimeArgument(_)
}
Expr getARuntimeArgument() { result = getRuntimeArgument(_) }
/**
* Gets the number of arguments that correspond to a parameter of a potential
* run-time target of this call.
*/
int getNumberOfRuntimeArguments() {
result = count(getARuntimeArgument())
}
int getNumberOfRuntimeArguments() { result = count(getARuntimeArgument()) }
/**
* Holds if this call has no arguments that correspond to a parameter of a
* potential (run-time) target of this call.
*/
predicate hasNoRuntimeArguments() {
not exists(getARuntimeArgument())
}
predicate hasNoRuntimeArguments() { not exists(getARuntimeArgument()) }
override string toString() { result = "call" }
}
@@ -307,21 +292,18 @@ private predicate isValidExplicitParamsType(Parameter p, Type t) {
* ```
*/
class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invocation_expr {
override Method getTarget() {
expr_call(this, result)
}
override Method getTarget() { expr_call(this, result) }
override Method getQualifiedDeclaration() {
result = getTarget()
}
override Method getQualifiedDeclaration() { result = getTarget() }
override string toString() {
result = "call to method " + this.getTarget().getName()
}
override string toString() { result = "call to method " + this.getTarget().getName() }
override Expr getRawArgument(int i) {
if exists(getQualifier())
then (i=0 and result = getQualifier() or result = getArgument(i-1))
then
i = 0 and result = getQualifier()
or
result = getArgument(i - 1)
else result = getArgument(i)
}
}
@@ -345,21 +327,13 @@ class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invoca
* 6), in order to be properly matched with the parameter `i` on line 2.
*/
class ExtensionMethodCall extends MethodCall {
ExtensionMethodCall() {
this.getTarget() instanceof ExtensionMethod
}
ExtensionMethodCall() { this.getTarget() instanceof ExtensionMethod }
override TypeAccess getQualifier() {
result = this.getChildExpr(-1)
}
override TypeAccess getQualifier() { result = this.getChildExpr(-1) }
override Expr getArgument(int i) {
exists(int j |
result = this.getChildExpr(j) |
if isOrdinaryStaticCall() then
(j = i and j >= 0)
else
(j = i - 1 and j >= -1)
exists(int j | result = this.getChildExpr(j) |
if isOrdinaryStaticCall() then (j = i and j >= 0) else (j = i - 1 and j >= -1)
)
}
@@ -401,13 +375,10 @@ class ExtensionMethodCall extends MethodCall {
* ```
*/
class VirtualMethodCall extends MethodCall {
VirtualMethodCall() {
not getQualifier() instanceof BaseAccess
and
not getQualifier() instanceof BaseAccess and
getTarget().isOverridableOrImplementable()
}
}
/**
@@ -427,17 +398,11 @@ class VirtualMethodCall extends MethodCall {
* ```
*/
class ConstructorInitializer extends Call, @constructor_init_expr {
override Constructor getTarget() {
expr_call(this, result)
}
override Constructor getTarget() { expr_call(this, result) }
override Constructor getARuntimeTarget() {
result = Call.super.getARuntimeTarget()
}
override Constructor getARuntimeTarget() { result = Call.super.getARuntimeTarget() }
override string toString() {
result = "call to constructor " + this.getTarget().getName()
}
override string toString() { result = "call to constructor " + this.getTarget().getName() }
/**
* Gets the constructor that this initializer call belongs to. For example,
@@ -460,7 +425,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr {
override Expr getRawArgument(int i) {
if this.getTarget().isStatic()
then result = this.getArgument(i)
else result = this.getArgument(i-1)
else result = this.getArgument(i - 1)
}
}
@@ -481,17 +446,11 @@ class ConstructorInitializer extends Call, @constructor_init_expr {
* ```
*/
class OperatorCall extends Call, LateBindableExpr, @operator_invocation_expr {
override Operator getTarget() {
expr_call(this, result)
}
override Operator getTarget() { expr_call(this, result) }
override Operator getARuntimeTarget() {
result = Call.super.getARuntimeTarget()
}
override Operator getARuntimeTarget() { result = Call.super.getARuntimeTarget() }
override string toString() {
result = "call to operator " + this.getTarget().getName()
}
override string toString() { result = "call to operator " + this.getTarget().getName() }
}
/**
@@ -511,13 +470,13 @@ class OperatorCall extends Call, LateBindableExpr, @operator_invocation_expr {
* ```
*/
class MutatorOperatorCall extends OperatorCall {
MutatorOperatorCall() { mutator_invocation_mode(this,_) }
MutatorOperatorCall() { mutator_invocation_mode(this, _) }
/** Holds if the operator is in prefix position. */
predicate isPrefix() { mutator_invocation_mode(this,1) }
predicate isPrefix() { mutator_invocation_mode(this, 1) }
/** Holds if the operator is in postfix position. */
predicate isPostfix() { mutator_invocation_mode(this,2) }
predicate isPostfix() { mutator_invocation_mode(this, 2) }
}
/**
@@ -548,7 +507,8 @@ class DelegateCall extends Call, @delegate_invocation_expr {
or
exists(AddEventSource aes, CallContext::CallContext cc2 |
aes = this.getAnAddEventSource() and
result = aes.getARuntimeTarget(cc2) |
result = aes.getARuntimeTarget(cc2)
|
aes = this.getAnAddEventSourceSameEnclosingCallable() and
cc = cc2
or
@@ -572,13 +532,9 @@ class DelegateCall extends Call, @delegate_invocation_expr {
result.getExpr().getEnclosingCallable() != this.getEnclosingCallable()
}
override Callable getARuntimeTarget() {
result = getARuntimeTarget(_)
}
override Callable getARuntimeTarget() { result = getARuntimeTarget(_) }
override Expr getRuntimeArgument(int i) {
result = getArgument(i)
}
override Expr getRuntimeArgument(int i) { result = getArgument(i) }
/**
* Gets the delegate expression of this delegate call. For example, the
@@ -594,13 +550,9 @@ class DelegateCall extends Call, @delegate_invocation_expr {
* }
* ```
*/
Expr getDelegateExpr() {
result = this.getChild(-1)
}
Expr getDelegateExpr() { result = this.getChild(-1) }
override string toString() {
result = "delegate call"
}
override string toString() { result = "delegate call" }
}
/**
@@ -613,9 +565,7 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr {
override Expr getArgument(int i) { none() }
override Accessor getARuntimeTarget() {
result = Call.super.getARuntimeTarget()
}
override Accessor getARuntimeTarget() { result = Call.super.getARuntimeTarget() }
}
/**
@@ -634,8 +584,7 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr {
*/
class PropertyCall extends AccessorCall, PropertyAccessExpr {
override Accessor getTarget() {
exists(PropertyAccess pa, Property p |
pa = this and p = getProperty() |
exists(PropertyAccess pa, Property p | pa = this and p = getProperty() |
pa instanceof AssignableRead and result = p.getGetter()
or
pa instanceof AssignableWrite and result = p.getSetter()
@@ -647,9 +596,7 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
result = AssignableInternal::getAccessorCallValueArgument(this)
}
override string toString() {
result = PropertyAccessExpr.super.toString()
}
override string toString() { result = PropertyAccessExpr.super.toString() }
}
/**
@@ -670,8 +617,7 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
*/
class IndexerCall extends AccessorCall, IndexerAccessExpr {
override Accessor getTarget() {
exists(IndexerAccess ia, Indexer i |
ia = this and i = getIndexer() |
exists(IndexerAccess ia, Indexer i | ia = this and i = getIndexer() |
ia instanceof AssignableRead and result = i.getGetter()
or
ia instanceof AssignableWrite and result = i.getSetter()
@@ -713,7 +659,8 @@ class EventCall extends AccessorCall, EventAccessExpr {
override EventAccessor getTarget() {
exists(Event e, AddOrRemoveEventExpr aoree |
e = getEvent() and
aoree.getLValue() = this |
aoree.getLValue() = this
|
aoree instanceof AddEventExpr and result = e.getAddEventAccessor()
or
aoree instanceof RemoveEventExpr and result = e.getRemoveEventAccessor()
@@ -728,9 +675,7 @@ class EventCall extends AccessorCall, EventAccessExpr {
)
}
override string toString() {
result = EventAccessExpr.super.toString()
}
override string toString() { result = EventAccessExpr.super.toString() }
}
/**
@@ -747,11 +692,7 @@ class EventCall extends AccessorCall, EventAccessExpr {
* ```
*/
class LocalFunctionCall extends Call, @local_function_invocation_expr {
override LocalFunction getTarget() {
expr_call(this, result)
}
override LocalFunction getTarget() { expr_call(this, result) }
override string toString() {
result = "call to local function " + getTarget().getName()
}
override string toString() { result = "call to local function " + getTarget().getName() }
}

View File

@@ -21,16 +21,12 @@ class EqualityOperation extends ComparisonOperation, @equality_op_expr { }
/**
* An equals operation, for example `x == y`.
*/
class EQExpr extends EqualityOperation, @eq_expr {
override string getOperator() { result = "==" }
}
class EQExpr extends EqualityOperation, @eq_expr { override string getOperator() { result = "==" } }
/**
* A not-equals operation, for example `x != y`.
*/
class NEExpr extends EqualityOperation, @ne_expr {
override string getOperator() { result = "!=" }
}
class NEExpr extends EqualityOperation, @ne_expr { override string getOperator() { result = "!=" } }
/**
* A relational operation. Either a greater-than operation (`GTExpr`),
@@ -60,7 +56,9 @@ class RelationalOperation extends ComparisonOperation, @rel_op_expr {
*/
class GTExpr extends RelationalOperation, @gt_expr {
override string getOperator() { result = ">" }
override Expr getGreaterOperand() { result = getLeftOperand() }
override Expr getLesserOperand() { result = getRightOperand() }
}
@@ -69,7 +67,9 @@ class GTExpr extends RelationalOperation, @gt_expr {
*/
class LTExpr extends RelationalOperation, @lt_expr {
override string getOperator() { result = "<" }
override Expr getGreaterOperand() { result = getRightOperand() }
override Expr getLesserOperand() { result = getLeftOperand() }
}
@@ -78,7 +78,9 @@ class LTExpr extends RelationalOperation, @lt_expr {
*/
class GEExpr extends RelationalOperation, @ge_expr {
override string getOperator() { result = ">=" }
override Expr getGreaterOperand() { result = getLeftOperand() }
override Expr getLesserOperand() { result = getRightOperand() }
}
@@ -87,6 +89,8 @@ class GEExpr extends RelationalOperation, @ge_expr {
*/
class LEExpr extends RelationalOperation, @le_expr {
override string getOperator() { result = "<=" }
override Expr getGreaterOperand() { result = getRightOperand() }
override Expr getLesserOperand() { result = getLeftOperand() }
}

View File

@@ -1,6 +1,7 @@
/**
* Provides expression classes for creating various types of object.
*/
import Expr
import semmle.code.csharp.Callable
@@ -43,9 +44,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr
* }
* ```
*/
MemberInitializer getAMemberInitializer() {
result = getMemberInitializer(_)
}
MemberInitializer getAMemberInitializer() { result = getMemberInitializer(_) }
/**
* Gets the `i`th member initializer of this object initializer. For example,
@@ -69,14 +68,10 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr
}
/** Gets the number of member initializers of this object initializer. */
int getNumberOfMemberInitializers() {
result = count(this.getAMemberInitializer())
}
int getNumberOfMemberInitializers() { result = count(this.getAMemberInitializer()) }
/** Holds if this object initializer has no member initializers. */
predicate hasNoMemberInitializers() {
not exists(this.getAMemberInitializer())
}
predicate hasNoMemberInitializers() { not exists(this.getAMemberInitializer()) }
}
/**
@@ -94,14 +89,10 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr
* ```
*/
class MemberInitializer extends AssignExpr {
MemberInitializer() {
this.getParent() instanceof ObjectInitializer
}
MemberInitializer() { this.getParent() instanceof ObjectInitializer }
/** Gets the initialized member. */
Member getInitializedMember() {
result.getAnAccess() = this.getLValue()
}
Member getInitializedMember() { result.getAnAccess() = this.getLValue() }
}
/**
@@ -126,9 +117,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i
* };
* ```
*/
ElementInitializer getAnElementInitializer() {
result = getElementInitializer(_)
}
ElementInitializer getAnElementInitializer() { result = getElementInitializer(_) }
/**
* Gets the `i`th element initializer of this collection initializer, for
@@ -148,14 +137,10 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i
}
/** Gets the number of element initializers of this collection initializer. */
int getNumberOfElementInitializers() {
result = count(this.getAnElementInitializer())
}
int getNumberOfElementInitializers() { result = count(this.getAnElementInitializer()) }
/** Holds if this collection initializer has no element initializers. */
predicate hasNoElementInitializers() {
not exists(this.getAnElementInitializer())
}
predicate hasNoElementInitializers() { not exists(this.getAnElementInitializer()) }
}
/**
@@ -190,9 +175,7 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr {
override Constructor getTarget() { expr_call(this, result) }
override Constructor getARuntimeTarget() {
result = Call.super.getARuntimeTarget()
}
override Constructor getARuntimeTarget() { result = Call.super.getARuntimeTarget() }
/**
* Holds if this constructor call includes an object initializer or an
@@ -213,14 +196,12 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr {
*/
ObjectOrCollectionInitializer getInitializer() { result = this.getChild(-1) }
override string toString() {
result = "object creation of type " + this.getType().getName()
}
override string toString() { result = "object creation of type " + this.getType().getName() }
override Expr getRawArgument(int i) {
if this.getTarget().isStatic()
then result = this.getArgument(i)
else result = this.getArgument(i-1)
else result = this.getArgument(i - 1)
}
}
@@ -236,13 +217,9 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr {
* ```
*/
class AnonymousObjectCreation extends ObjectCreation {
AnonymousObjectCreation() {
this.getObjectType() instanceof AnonymousClass
}
AnonymousObjectCreation() { this.getObjectType() instanceof AnonymousClass }
override ObjectInitializer getInitializer() {
result = this.getChild(-1)
}
override ObjectInitializer getInitializer() { result = this.getChild(-1) }
}
/**
@@ -252,9 +229,7 @@ class AnonymousObjectCreation extends ObjectCreation {
*/
class DelegateCreation extends Expr, @delegate_creation_expr {
/** Gets the delegate type of this delegate creation. */
DelegateType getDelegateType() {
result = this.getType()
}
DelegateType getDelegateType() { result = this.getType() }
/**
* Gets the argument of this delegate creation. Either a callable access
@@ -263,9 +238,7 @@ class DelegateCreation extends Expr, @delegate_creation_expr {
*/
Expr getArgument() { result = this.getAChild() }
override string toString() {
result = "delegate creation of type " + this.getType().getName()
}
override string toString() { result = "delegate creation of type " + this.getType().getName() }
}
/**
@@ -322,9 +295,7 @@ class ArrayInitializer extends Expr, @array_init_expr {
* };
* ```
*/
Expr getAnElement() {
result = getElement(_)
}
Expr getAnElement() { result = getElement(_) }
/**
* Gets the `i`th element of this array initializer, for example the second
@@ -344,9 +315,7 @@ class ArrayInitializer extends Expr, @array_init_expr {
}
/** Gets the number of elements in this array initializer. */
int getNumberOfElements() {
result = count(this.getAnElement())
}
int getNumberOfElements() { result = count(this.getAnElement()) }
/** Holds if this array initializer has no elements. */
predicate hasNoElements() { not exists(this.getAnElement()) }
@@ -369,9 +338,7 @@ class ArrayCreation extends Expr, @array_creation_expr {
* new int[5, 10]
* ```
*/
Expr getALengthArgument() {
result = getLengthArgument(_)
}
Expr getALengthArgument() { result = getLengthArgument(_) }
/**
* Gets the `i`th dimension's length argument of this array creation, for
@@ -387,9 +354,7 @@ class ArrayCreation extends Expr, @array_creation_expr {
}
/** Gets the number of length arguments of this array creation. */
int getNumberOfLengthArguments() {
result = count(this.getALengthArgument())
}
int getNumberOfLengthArguments() { result = count(this.getALengthArgument()) }
/** Holds if the created array is implicitly sized by the initializer. */
predicate isImplicitlySized() { not explicitly_sized_array_creation(this) }
@@ -403,9 +368,7 @@ class ArrayCreation extends Expr, @array_creation_expr {
/** Holds if the type of the created array is inferred from its initializer. */
predicate isImplicitlyTyped() { implicitly_typed_array_creation(this) }
override string toString() {
result = "array creation of type " + this.getType().getName()
}
override string toString() { result = "array creation of type " + this.getType().getName() }
}
/**
@@ -415,9 +378,7 @@ class ArrayCreation extends Expr, @array_creation_expr {
class AnonymousFunctionExpr extends Expr, Callable, @anonymous_function_expr {
override string getName() { result = "<anonymous>" }
override Type getReturnType() {
result = getType().(DelegateType).getReturnType()
}
override Type getReturnType() { result = getType().(DelegateType).getReturnType() }
override AnonymousFunctionExpr getSourceDeclaration() { result = this }

View File

@@ -14,11 +14,7 @@ private import semmle.code.csharp.dispatch.Dispatch
* dynamic member access (`DynamicMemberAccess`), a dynamic accessor call
* (`DynamicAccessorCall`), or a dynamic element access (`DynamicElementAccess`).
*/
class DynamicExpr extends LateBindableExpr {
DynamicExpr() {
isLateBound()
}
}
class DynamicExpr extends LateBindableExpr { DynamicExpr() { isLateBound() } }
/**
* A constructor call where one of the arguments is a `dynamic` expression, for
@@ -67,9 +63,7 @@ class DynamicObjectCreation extends DynamicExpr, ObjectCreation {
* may not be known at compile-time (as in the example above).
*/
class DynamicMethodCall extends DynamicExpr, MethodCall {
override string toString() {
result = "dynamic call to method " + getLateBoundTargetName()
}
override string toString() { result = "dynamic call to method " + getLateBoundTargetName() }
}
/**
@@ -97,9 +91,7 @@ class DynamicMethodCall extends DynamicExpr, MethodCall {
* target operator may not be known at compile-time (as in the example above).
*/
class DynamicOperatorCall extends DynamicExpr, OperatorCall {
override string toString() {
result = "dynamic call to operator " + getLateBoundTargetName()
}
override string toString() { result = "dynamic call to operator " + getLateBoundTargetName() }
}
/**
@@ -187,10 +179,9 @@ class DynamicAccess extends DynamicExpr {
* of the member being accessed may not be known (it can be either a field, a
* property, or an event).
*/
class DynamicMemberAccess extends DynamicAccess, MemberAccess, AssignableAccess, @dynamic_member_access_expr {
override string toString() {
result = "dynamic access to member " + getLateBoundTargetName()
}
class DynamicMemberAccess extends DynamicAccess, MemberAccess, AssignableAccess,
@dynamic_member_access_expr {
override string toString() { result = "dynamic access to member " + getLateBoundTargetName() }
// The target is unknown when the qualifier is a `dynamic` expression
override DynamicMember getTarget() { none() }
@@ -303,10 +294,7 @@ class DynamicAccessorCall extends DynamicAccess {
Accessor target;
DynamicAccessorCall() {
exists(DispatchCall dc |
dc.getCall() = this |
target = dc.getADynamicTarget()
)
exists(DispatchCall dc | dc.getCall() = this | target = dc.getADynamicTarget())
}
/** Gets an actual run-time target of this dynamic accessor call. */

View File

@@ -47,20 +47,16 @@ class Expr extends DotNet::Expr, ControlFlowElement, @expr {
override Type getType() { expressions(this, _, getTypeRef(result)) }
/** Gets the value of this expression, if any */
override string getValue() { expr_value(this,result) }
override string getValue() { expr_value(this, result) }
/** Holds if this expression has a value. */
predicate hasValue() { exists(getValue()) }
/** Gets the enclosing statement of this expression, if any. */
final Stmt getEnclosingStmt() {
enclosingStmt(this, result)
}
final Stmt getEnclosingStmt() { enclosingStmt(this, result) }
/** Gets the enclosing callable of this expression, if any. */
override Callable getEnclosingCallable() {
exprEnclosingCallable(this, result)
}
override Callable getEnclosingCallable() { exprEnclosingCallable(this, result) }
/**
* Holds if this expression is generated by the compiler and does not appear
@@ -87,9 +83,7 @@ class Expr extends DotNet::Expr, ControlFlowElement, @expr {
* argument for, if any. For example, if this expression is `0` in
* `M(second: 1, first: 0)` then the result is `"first"`.
*/
string getExplicitArgumentName() {
expr_argument_name(this, result)
}
string getExplicitArgumentName() { expr_argument_name(this, result) }
override Element getParent() { result = ControlFlowElement.super.getParent() }
}
@@ -110,9 +104,7 @@ class LateBindableExpr extends Expr, @late_bindable_expr {
}
/** Gets the name of the target that is late bound, if any. */
string getLateBoundTargetName() {
dynamic_member_name(this, result)
}
string getLateBoundTargetName() { dynamic_member_name(this, result) }
}
private predicate isDynamicMemberAccess(@dynamic_member_access_expr e) { any() }
@@ -124,7 +116,7 @@ private predicate isDynamicElementAccess(@dynamic_element_access_expr e) { any()
*/
class LocalVariableDeclExpr extends Expr, @local_var_decl_expr {
/** Gets the local variable being declared. */
LocalVariable getVariable() { localvars(result,_,_,_,_,this) }
LocalVariable getVariable() { localvars(result, _, _, _, _, this) }
/** Gets the name of the variable being declared. */
string getName() { result = this.getVariable().getName() }
@@ -155,22 +147,16 @@ class LocalVariableDeclExpr extends Expr, @local_var_decl_expr {
* Holds if this variable declaration is defined as an `out` argument,
* for example `M(out int x)`.
*/
predicate isOutArgument() {
expr_argument(this, 2)
}
predicate isOutArgument() { expr_argument(this, 2) }
}
/**
* A local constant declaration, for example `const int i = 0`.
*/
class LocalConstantDeclExpr extends LocalVariableDeclExpr {
LocalConstantDeclExpr() {
super.getVariable() instanceof LocalConstant
}
LocalConstantDeclExpr() { super.getVariable() instanceof LocalConstant }
override LocalConstant getVariable() {
localvars(result,_,_,_,_,this)
}
override LocalConstant getVariable() { localvars(result, _, _, _, _, this) }
}
/**
@@ -281,9 +267,9 @@ class IsExpr extends Expr, @is_expr {
/**
* An `is` type expression, for example, `x is string` or `x is string s`.
*/
class IsTypeExpr extends IsExpr
{
class IsTypeExpr extends IsExpr {
TypeAccess typeAccess;
IsTypeExpr() { typeAccess = this.getChild(1) }
/**
@@ -302,9 +288,9 @@ class IsTypeExpr extends IsExpr
/**
* An `is` pattern expression, for example `x is string s`.
*/
class IsPatternExpr extends IsTypeExpr
{
class IsPatternExpr extends IsTypeExpr {
LocalVariableDeclExpr typeDecl;
IsPatternExpr() { typeDecl = this.getChild(2) }
/**
@@ -317,9 +303,9 @@ class IsPatternExpr extends IsTypeExpr
/**
* An `is` constant expression, for example `x is 5`.
*/
class IsConstantExpr extends IsExpr
{
class IsConstantExpr extends IsExpr {
Expr constant;
IsConstantExpr() { constant = this.getChild(3) }
/** Gets the constant expression, for example `5` in `x is 5`. */
@@ -353,10 +339,7 @@ class Cast extends Expr {
override Expr stripCasts() { result = this.getExpr().stripCasts() }
override Expr stripImplicitCasts() {
if this.isImplicit() then
result = this.getExpr().stripImplicitCasts()
else
result = this
if this.isImplicit() then result = this.getExpr().stripImplicitCasts() else result = this
}
}
@@ -371,11 +354,7 @@ class Cast extends Expr {
* }
* ```
*/
class ImplicitCast extends Cast {
ImplicitCast() {
this.isImplicit()
}
}
class ImplicitCast extends Cast { ImplicitCast() { this.isImplicit() } }
/**
* An explicit cast. For example, the explicit cast from `object` to `string`
@@ -387,25 +366,17 @@ class ImplicitCast extends Cast {
* }
* ```
*/
class ExplicitCast extends Cast {
ExplicitCast() {
not this instanceof ImplicitCast
}
}
class ExplicitCast extends Cast { ExplicitCast() { not this instanceof ImplicitCast } }
/**
* An `as` expression, for example `x as string`.
*/
class AsExpr extends Cast, @as_expr {
override string toString() { result = "... as ..." }
}
class AsExpr extends Cast, @as_expr { override string toString() { result = "... as ..." } }
/**
* A cast expression, for example `(string) x`.
*/
class CastExpr extends Cast, @cast_expr {
override string toString() { result = "(...) ..." }
}
class CastExpr extends Cast, @cast_expr { override string toString() { result = "(...) ..." } }
/**
* A `typeof` expression, for example `typeof(string)`.
@@ -431,9 +402,7 @@ class DefaultValueExpr extends Expr, @default_expr {
TypeAccess getTypeAccess() { result = this.getChild(0) }
override string toString() {
if exists(getTypeAccess())
then result = "default(...)"
else result = "default"
if exists(getTypeAccess()) then result = "default(...)" else result = "default"
}
}
@@ -449,9 +418,7 @@ class SizeofExpr extends UnaryOperation, @sizeof_expr {
override string getOperator() { result = "sizeof(..)" }
override string toString() {
result = "sizeof(..)"
}
override string toString() { result = "sizeof(..)" }
}
/**
@@ -514,13 +481,9 @@ class AddressOfExpr extends UnaryOperation, @address_of_expr {
*/
class AwaitExpr extends Expr, @await_expr {
/** Gets the expression being awaited. */
Expr getExpr() {
result = getChild(0)
}
Expr getExpr() { result = getChild(0) }
override string toString() {
result = "await ..."
}
override string toString() { result = "await ..." }
}
/**
@@ -535,17 +498,13 @@ class AwaitExpr extends Expr, @await_expr {
* ```
*/
class NameOfExpr extends Expr, @nameof_expr {
override string toString() {
result = "nameof(...)"
}
override string toString() { result = "nameof(...)" }
/**
* Gets the access in this `nameof` expression, for example `x.F` in
* `nameof(x.F)`.
*/
Access getAccess() {
result = this.getChild(0)
}
Access getAccess() { result = this.getChild(0) }
}
/**
@@ -558,9 +517,7 @@ class NameOfExpr extends Expr, @nameof_expr {
* ```
*/
class InterpolatedStringExpr extends Expr, @interpolated_string_expr {
override string toString() {
result = "$\"...\""
}
override string toString() { result = "$\"...\"" }
/**
* Gets the insert at index `i` in this interpolated string, if any. For
@@ -579,19 +536,13 @@ class InterpolatedStringExpr extends Expr, @interpolated_string_expr {
* `$"Hello, {name}!"`. Note that there is no text element at index `i = 1`,
* but instead an insert (`getInsert(1)` gets the insert).
*/
StringLiteral getText(int i) {
result = getChild(i)
}
StringLiteral getText(int i) { result = getChild(i) }
/** Gets an insert in this interpolated string. */
Expr getAnInsert() {
result = getInsert(_)
}
Expr getAnInsert() { result = getInsert(_) }
/** Gets a text element in this interpolated string. */
StringLiteral getAText() {
result = getText(_)
}
StringLiteral getAText() { result = getText(_) }
}
/**
@@ -621,9 +572,7 @@ class ThrowElement extends ControlFlowElement, DotNet::Throw, @throw_element {
* `return i != 0 ? 1 / i : throw new ArgumentException("i");`
*/
class ThrowExpr extends Expr, ThrowElement, @throw_expr {
override string toString() {
result = "throw ..."
}
override string toString() { result = "throw ..." }
/**
* Gets the expression of the exception being thrown.
@@ -655,9 +604,7 @@ class QualifiableExpr extends Expr, @qualifiable_expr {
final predicate hasQualifier() { exists(getQualifier()) }
/** Holds if this expression has an implicit `this` qualifier. */
predicate hasImplicitThisQualifier() {
this.getQualifier().(ThisAccess).isImplicit()
}
predicate hasImplicitThisQualifier() { this.getQualifier().(ThisAccess).isImplicit() }
/** Holds if this call has an implicit or explicit `this` qualifier. */
predicate hasThisQualifier() {
@@ -691,15 +638,12 @@ class QualifiableExpr extends Expr, @qualifiable_expr {
* Holds if the target of this expression can be overridden or implemented.
*/
predicate targetIsOverridableOrImplementable() {
not this.getQualifier() instanceof BaseAccess
and
not this.getQualifier() instanceof BaseAccess and
this.getQualifiedDeclaration().(Virtualizable).isOverridableOrImplementable()
}
/** Holds if this expression has a conditional qualifier `?.` */
predicate isConditional() {
conditional_access(this)
}
predicate isConditional() { conditional_access(this) }
}
/**
@@ -717,22 +661,16 @@ class QualifiableExpr extends Expr, @qualifiable_expr {
* ```
*/
class TupleExpr extends Expr, @tuple_expr {
override string toString() { result="(..., ...)" }
override string toString() { result = "(..., ...)" }
/** Gets the `i`th argument of this tuple. */
Expr getArgument(int i) {
result = getChild(i)
}
Expr getArgument(int i) { result = getChild(i) }
/** Gets an argument of this tuple. */
Expr getAnArgument() {
result = getArgument(_)
}
Expr getAnArgument() { result = getArgument(_) }
/** Holds if this tuple is a read access. */
predicate isReadAccess() {
not exists(AssignExpr e | this = e.getLValue().getAChildExpr*())
}
predicate isReadAccess() { not exists(AssignExpr e | this = e.getLValue().getAChildExpr*()) }
}
/**
@@ -745,19 +683,12 @@ class TupleExpr extends Expr, @tuple_expr {
* ```
*/
class RefExpr extends Expr, @ref_expr {
/** Gets the expression being referenced. */
Expr getExpr() {
result = getChild(0)
}
Expr getExpr() { result = getChild(0) }
override string toString() {
result = "ref ..."
}
override string toString() { result = "ref ..." }
override Type getType() {
result = getExpr().getType()
}
override Type getType() { result = getExpr().getType() }
}
/**
@@ -767,6 +698,4 @@ class RefExpr extends Expr, @ref_expr {
* (var name, _, _) = GetDetails();
* ```
*/
class DiscardExpr extends Expr, @discard_expr {
override string toString() { result="_" }
}
class DiscardExpr extends Expr, @discard_expr { override string toString() { result = "_" } }

View File

@@ -15,6 +15,7 @@ private import dotnet
*/
class Literal extends DotNet::Literal, Expr, @literal_expr {
override string toString() { result = this.getValue() }
override string getValue() { result = Expr.super.getValue() }
}
@@ -88,8 +89,7 @@ class DecimalLiteral extends RealLiteral, @decimal_literal_expr { }
* A `string` literal, for example `"Hello, World!"`.
*/
class StringLiteral extends DotNet::StringLiteral, Literal, @string_literal_expr {
override string toString() {
result = "\"" + getValue().replaceAll("\"", "\\\"") + "\"" }
override string toString() { result = "\"" + getValue().replaceAll("\"", "\\\"") + "\"" }
}
/**

View File

@@ -3,6 +3,7 @@
*
* All logical operations have the common base class `LogicalOperation`.
*/
import Expr
/**
@@ -10,9 +11,7 @@ import Expr
* a binary logical operation (`BinaryLogicalOperation`), or a ternary logical
* operation (`TernaryLogicalOperation`).
*/
class LogicalOperation extends Operation, @log_expr {
override string getOperator() { none() }
}
class LogicalOperation extends Operation, @log_expr { override string getOperator() { none() } }
/**
* A unary logical operation, that is, a logical 'not' (`LogicalNotExpr`).
@@ -31,7 +30,7 @@ class LogicalNotExpr extends UnaryLogicalOperation, @log_not_expr {
* a logical 'or' (`LogicalAndExpr`), or a null-coalescing operation
* (`NullCoalescingExpr`).
*/
class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_op_expr{
class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_op_expr {
override string getOperator() { none() }
}
@@ -66,7 +65,7 @@ class NullCoalescingExpr extends BinaryLogicalOperation, @null_coalescing_expr {
* A ternary logical operation, that is, a ternary conditional expression
* (`ConditionalExpr`).
*/
class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_op_expr{ }
class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_op_expr { }
/**
* A conditional expression, for example `s != null ? s.Length : -1`
@@ -83,12 +82,12 @@ class ConditionalExpr extends TernaryLogicalOperation, @conditional_expr {
Expr getCondition() { result = this.getChild(0) }
/** Gets the "then" expression of this conditional expression. */
Expr getThen() {result = this.getChild(1) }
Expr getThen() { result = this.getChild(1) }
/** Gets the "else" expression of this conditional expression. */
Expr getElse() { result = this.getChild(2) }
override string getOperator() { result = "?" }
override string toString() { result = "... ? ... : ..." }
override string toString() { result = "... ? ... : ..." }
}

View File

@@ -9,8 +9,7 @@ private import semmle.code.csharp.frameworks.system.Text
/** A method that formats a string, for example `string.Format()`. */
class FormatMethod extends Method {
FormatMethod() {
exists(Class declType |
declType = this.getDeclaringType() |
exists(Class declType | declType = this.getDeclaringType() |
this.getParameter(0).getType() instanceof SystemIFormatProviderInterface and
this.getParameter(1).getType() instanceof StringType and
this.getNumberOfParameters() >= 3 and
@@ -27,20 +26,22 @@ class FormatMethod extends Method {
or
this = any(SystemTextStringBuilderClass c).getAppendFormatMethod()
or
(this.hasName("Write") or this.hasName("WriteLine")) and
(
(this.hasName("Write") or this.hasName("WriteLine")) and
(
declType.hasQualifiedName("System.Console")
or
declType.hasQualifiedName("System.IO.TextWriter")
or
declType.hasQualifiedName("System.Diagnostics.Debug") and
this.getParameter(1).getType() instanceof ArrayType
)
declType.hasQualifiedName("System.Console")
or
declType.hasQualifiedName("System.IO.TextWriter")
or
declType.hasQualifiedName("System.Diagnostics.Debug") and
this.getParameter(1).getType() instanceof ArrayType
)
or
declType.hasQualifiedName("System.Diagnostics.Trace") and
(this.hasName("TraceError") or this.hasName("TraceInformation") or this.hasName("TraceWarning"))
(
this.hasName("TraceError") or
this.hasName("TraceInformation") or
this.hasName("TraceWarning")
)
or
this.hasName("TraceInformation") and
declType.hasQualifiedName("System.Diagnostics.TraceSource")
@@ -60,13 +61,14 @@ class FormatMethod extends Method {
* `string.Format(IFormatProvider, String, Object)` is `1`.
*/
int getFormatArgument() {
if this.getParameter(0).getType() instanceof SystemIFormatProviderInterface then
result = 1
if this.getParameter(0).getType() instanceof SystemIFormatProviderInterface
then result = 1
else
if this.hasName("Assert") and this.getDeclaringType().hasQualifiedName("System.Diagnostics.Debug") then
result = 2
else
result = 0
if
this.hasName("Assert") and
this.getDeclaringType().hasQualifiedName("System.Diagnostics.Debug")
then result = 2
else result = 0
}
}
@@ -78,14 +80,16 @@ class FormatMethod extends Method {
class StringFormatItemParameter extends Parameter {
StringFormatItemParameter() {
// Parameter of a format method
exists(FormatMethod m, int pos |
m = this.getCallable() |
exists(FormatMethod m, int pos | m = this.getCallable() |
pos = this.getPosition() and
pos > m.getFormatArgument()
)
or
// Parameter of a source method that forwards to `string.Format()`
exists(AssignableDefinitions::ImplicitParameterDefinition def, ParameterRead pr, StringFormatItemParameter other |
exists(
AssignableDefinitions::ImplicitParameterDefinition def, ParameterRead pr,
StringFormatItemParameter other
|
def.getParameter() = this and
pr = def.getAReachableRead() and
pr.getAControlFlowNode().postDominates(this.getCallable().getEntryPoint()) and
@@ -96,16 +100,11 @@ class StringFormatItemParameter extends Parameter {
}
private Type getParameterType(Parameter p) {
if p.isParams() then
result = p.getType().(ArrayType).getElementType()
else
result = p.getType()
if p.isParams() then result = p.getType().(ArrayType).getElementType() else result = p.getType()
}
/** Regex for a valid insert. */
private string getFormatInsertRegex() {
result = "\\{(\\d+)\\s*(,\\s*-?\\d+\\s*)?(:[^{}]+)?\\}"
}
private string getFormatInsertRegex() { result = "\\{(\\d+)\\s*(,\\s*-?\\d+\\s*)?(:[^{}]+)?\\}" }
/**
* Regex for a valid token in the string.
@@ -113,35 +112,28 @@ private string getFormatInsertRegex() {
* Note that the format string can be tokenised using this regex.
*/
private string getValidFormatTokenRegex() {
result="[^{}]|\\{\\{|\\}\\}|" + getFormatInsertRegex()
result = "[^{}]|\\{\\{|\\}\\}|" + getFormatInsertRegex()
}
/** Regex for the entire format string */
private string getValidFormatRegex() {
result = "(" + getValidFormatTokenRegex() + ")*+"
}
private string getValidFormatRegex() { result = "(" + getValidFormatTokenRegex() + ")*+" }
/** A literal with a valid format string. */
class ValidFormatString extends StringLiteral {
ValidFormatString() {
this.getValue().regexpMatch(getValidFormatRegex())
}
ValidFormatString() { this.getValue().regexpMatch(getValidFormatRegex()) }
/** Gets the token at the given position in the string. */
string getToken(int outPosition) {
result = this.getValue().regexpFind(getValidFormatTokenRegex(), _, outPosition)
}
/**Gets the insert number at the given position in the string.*/
/**Gets the insert number at the given position in the string. */
int getInsert(int position) {
result = this.getToken(position).regexpCapture(getFormatInsertRegex(), 1).toInt()
}
/** Gets any insert number in the string.*/
int getAnInsert(){
result = this.getInsert(_)
}
/** Gets any insert number in the string. */
int getAnInsert() { result = this.getInsert(_) }
}
/**
@@ -150,20 +142,22 @@ class ValidFormatString extends StringLiteral {
* Such a literal would cause `string.Format()` to throw an exception.
*/
class InvalidFormatString extends StringLiteral {
InvalidFormatString() {
not this.getValue().regexpMatch(getValidFormatRegex())
}
InvalidFormatString() { not this.getValue().regexpMatch(getValidFormatRegex()) }
/** Gets the offset of the first error. */
int getInvalidOffset() {
result = this.getValue().regexpFind(getValidFormatRegex(),0,0).length()
result = this.getValue().regexpFind(getValidFormatRegex(), 0, 0).length()
}
override string getURL() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn, int oldstartcolumn, int padding |
exists(
string filepath, int startline, int startcolumn, int endline, int endcolumn,
int oldstartcolumn, int padding
|
this.getLocation().hasLocationInfo(filepath, startline, oldstartcolumn, endline, endcolumn) and
startcolumn = padding + oldstartcolumn + getInvalidOffset() and
toUrl(filepath, startline, startcolumn, endline, endcolumn, result) |
toUrl(filepath, startline, startcolumn, endline, endcolumn, result)
|
// Single-line string literal beginning " or @"
// Figure out the correct indent.
startline = endline and
@@ -183,9 +177,7 @@ private module FormatFlow {
private class FormatConfiguration extends DataFlow::Configuration {
FormatConfiguration() { this = "format" }
override predicate isSource(DataFlow::Node n) {
n.asExpr() instanceof StringLiteral
}
override predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
override predicate isSink(DataFlow::Node n) {
exists(FormatCall c | n.asExpr() = c.getFormatExpr())
@@ -194,7 +186,8 @@ private module FormatFlow {
predicate hasFlow(StringLiteral lit, Expr format) {
exists(DataFlow::Node n1, DataFlow::Node n2, FormatConfiguration conf |
n1.asExpr() = lit and n2.asExpr() = format |
n1.asExpr() = lit and n2.asExpr() = format
|
conf.hasFlow(n1, n2)
)
}
@@ -205,24 +198,16 @@ private module FormatFlow {
* to `string.Format()`.
*/
class FormatCall extends MethodCall {
FormatCall() {
this.getTarget() instanceof FormatMethod
}
FormatCall() { this.getTarget() instanceof FormatMethod }
/** Gets the expression used as the format string. */
Expr getFormatExpr() {
result = this.getArgument(this.getFormatArgument())
}
Expr getFormatExpr() { result = this.getArgument(this.getFormatArgument()) }
/** Gets the argument number containing the format string. */
int getFormatArgument() {
result = this.getTarget().(FormatMethod).getFormatArgument()
}
int getFormatArgument() { result = this.getTarget().(FormatMethod).getFormatArgument() }
/** Gets the argument number of the first supplied insert. */
int getFirstArgument() {
result = this.getFormatArgument() + 1
}
int getFirstArgument() { result = this.getFormatArgument() + 1 }
/** Holds if the arguments are supplied in an array, not individually. */
predicate hasArrayExpr() {
@@ -234,9 +219,7 @@ class FormatCall extends MethodCall {
* Gets a format string. Global data flow analysis is applied to retrieve all
* sources that can reach this method call.
*/
StringLiteral getAFormatSource() {
FormatFlow::hasFlow(result, this.getFormatExpr())
}
StringLiteral getAFormatSource() { FormatFlow::hasFlow(result, this.getFormatExpr()) }
/**
* Gets the number of supplied arguments (excluding the format string and format
@@ -249,9 +232,7 @@ class FormatCall extends MethodCall {
}
/** Gets an index if a supplied argument. */
int getASuppliedArgument() {
result in [0 .. this.getSuppliedArguments() - 1]
}
int getASuppliedArgument() { result in [0 .. this.getSuppliedArguments() - 1] }
/** Get the expression supplied at the given position. */
Expr getSuppliedExpr(int index) {

View File

@@ -1,4 +1,5 @@
/** Provides definitions related to the namespace `Microsoft`. */
import csharp
/** The `Microsoft` namespace. */

View File

@@ -1,11 +1,10 @@
/** Provides definitions related to the namespace `Moq`. */
import csharp
/** The `Moq.Language` Namespace. */
class MoqLanguageNamespace extends Namespace {
MoqLanguageNamespace() {
this.hasQualifiedName("Moq.Language")
}
MoqLanguageNamespace() { this.hasQualifiedName("Moq.Language") }
}
/**
@@ -23,11 +22,9 @@ class ReturnsMethod extends Method {
Expr getAReturnedExpr() {
exists(MethodCall mc, Expr arg |
mc = getACall() and
arg = mc.getArgument(0) |
if arg instanceof LambdaExpr then
arg.(LambdaExpr).canReturn(result)
else
result = arg
arg = mc.getArgument(0)
|
if arg instanceof LambdaExpr then arg.(LambdaExpr).canReturn(result) else result = arg
)
}
}
@@ -35,8 +32,7 @@ class ReturnsMethod extends Method {
/** An object creation that is returned by a mock. */
class ReturnedByMockObject extends ObjectCreation {
ReturnedByMockObject() {
exists(Variable v |
this = v.getAnAssignedValue() |
exists(Variable v | this = v.getAnAssignedValue() |
v.getAnAccess() = any(ReturnsMethod rm).getAReturnedExpr().getAChild*()
)
}
@@ -45,6 +41,6 @@ class ReturnedByMockObject extends ObjectCreation {
* Gets a value used to initialize a member of this object creation.
*/
Expr getAMemberInitializationValue() {
result = this.getInitializer().(ObjectInitializer).getAMemberInitializer().getRValue()
result = this.getInitializer().(ObjectInitializer).getAMemberInitializer().getRValue()
}
}

View File

@@ -1,4 +1,5 @@
/** Provides definitions related to SQL frameworks. */
import csharp
private import semmle.code.csharp.frameworks.system.Data
private import semmle.code.csharp.frameworks.system.data.Entity
@@ -15,44 +16,38 @@ class CommandTextAssignmentSqlExpr extends SqlExpr, AssignExpr {
CommandTextAssignmentSqlExpr() {
exists(Property p, SystemDataIDbCommandInterface i, Property text |
p = this.getLValue().(PropertyAccess).getTarget() and
text = i.getCommandTextProperty() |
text = i.getCommandTextProperty()
|
p.overridesOrImplementsOrEquals(text)
)
}
override
Expr getSql() { result = getRValue() }
override Expr getSql() { result = getRValue() }
}
/** A construction of an `IDbCommand` object. */
class IDbCommandConstructionSqlExpr extends SqlExpr, ObjectCreation {
IDbCommandConstructionSqlExpr() {
exists(InstanceConstructor ic |
ic = this.getTarget() |
ic.getDeclaringType().getABaseType*() instanceof SystemDataIDbCommandInterface
and
exists(InstanceConstructor ic | ic = this.getTarget() |
ic.getDeclaringType().getABaseType*() instanceof SystemDataIDbCommandInterface and
ic.getParameter(0).getType() instanceof StringType
)
}
override
Expr getSql() { result = getArgument(0) }
override Expr getSql() { result = getArgument(0) }
}
/** A construction of an `SqlDataAdapter` object. */
class SqlDataAdapterConstructionSqlExpr extends SqlExpr, ObjectCreation {
SqlDataAdapterConstructionSqlExpr() {
exists(InstanceConstructor ic |
ic = this.getTarget()
and
ic.getDeclaringType() instanceof SystemDataSqlClientSqlDataAdapterClass
and
ic = this.getTarget() and
ic.getDeclaringType() instanceof SystemDataSqlClientSqlDataAdapterClass and
ic.getParameter(0).getType() instanceof StringType
)
}
override
Expr getSql() { result = getArgument(0) }
override Expr getSql() { result = getArgument(0) }
}
/** A `MySql.Data.MySqlClient.MySqlHelper` method. */
@@ -61,8 +56,7 @@ class MySqlHelperMethodCallSqlExpr extends SqlExpr, MethodCall {
this.getQualifier().getType().(Class).hasQualifiedName("MySql.Data.MySqlClient", "MySqlHelper")
}
override
Expr getSql() {
override Expr getSql() {
exists(int i |
result = getArgument(i) and
this.getTarget().getParameter(i).hasName("commandText") and
@@ -74,11 +68,14 @@ class MySqlHelperMethodCallSqlExpr extends SqlExpr, MethodCall {
/** A `Microsoft.ApplicationBlocks.Data.SqlHelper` method. */
class MicrosoftSqlHelperMethodCallSqlExpr extends SqlExpr, MethodCall {
MicrosoftSqlHelperMethodCallSqlExpr() {
this.getQualifier().getType().(Class).hasQualifiedName("Microsoft.ApplicationBlocks.Data", "SqlHelper")
this
.getQualifier()
.getType()
.(Class)
.hasQualifiedName("Microsoft.ApplicationBlocks.Data", "SqlHelper")
}
override
Expr getSql() {
override Expr getSql() {
exists(int i |
result = getArgument(i) and
this.getTarget().getParameter(i).hasName("commandText") and
@@ -93,10 +90,7 @@ class SystemDataEntityDbSetSqlExpr extends SqlExpr, MethodCall {
this.getTarget() = any(SystemDataEntity::DbSet dbSet).getSqlQueryMethod()
}
override
Expr getSql() {
result = getArgumentForName("sql")
}
override Expr getSql() { result = getArgumentForName("sql") }
}
/** A call to a method in `System.Data.Entity.Database` that executes SQL. */
@@ -109,8 +103,5 @@ class SystemDataEntityDatabaseSqlExpr extends SqlExpr, MethodCall {
)
}
override
Expr getSql() {
result = getArgumentForName("sql")
}
override Expr getSql() { result = getArgumentForName("sql") }
}

View File

@@ -1,4 +1,5 @@
/** Provides definitions related to the namespace `System`. */
import csharp
private import system.Reflection
@@ -11,144 +12,94 @@ class SystemNamespace extends Namespace {
}
/** A class in the `System` namespace. */
class SystemClass extends Class {
SystemClass() {
this.getNamespace() instanceof SystemNamespace
}
}
class SystemClass extends Class { SystemClass() { this.getNamespace() instanceof SystemNamespace } }
/** An unbound generic class in the `System` namespace. */
class SystemUnboundGenericClass extends UnboundGenericClass {
SystemUnboundGenericClass() {
this.getNamespace() instanceof SystemNamespace
}
SystemUnboundGenericClass() { this.getNamespace() instanceof SystemNamespace }
}
/** An interface in the `System` namespace. */
class SystemInterface extends Interface {
SystemInterface() {
this.getNamespace() instanceof SystemNamespace
}
SystemInterface() { this.getNamespace() instanceof SystemNamespace }
}
/** An unbound generic interface in the `System` namespace. */
class SystemUnboundGenericInterface extends UnboundGenericInterface {
SystemUnboundGenericInterface() {
this.getNamespace() instanceof SystemNamespace
}
SystemUnboundGenericInterface() { this.getNamespace() instanceof SystemNamespace }
}
/** A delegate type in the `System` namespace. */
class SystemDelegateType extends DelegateType {
SystemDelegateType() {
this.getNamespace() instanceof SystemNamespace
}
SystemDelegateType() { this.getNamespace() instanceof SystemNamespace }
}
/** An unbound generic delegate type in the `System` namespace. */
class SystemUnboundGenericDelegateType extends UnboundGenericDelegateType {
SystemUnboundGenericDelegateType() {
this.getNamespace() instanceof SystemNamespace
}
SystemUnboundGenericDelegateType() { this.getNamespace() instanceof SystemNamespace }
}
/** The `System.Action` delegate type. */
class SystemActionDelegateType extends SystemDelegateType {
SystemActionDelegateType() {
this.getName() = "Action"
}
SystemActionDelegateType() { this.getName() = "Action" }
}
/** The `System.Action<T1, ..., Tn>` delegate type. */
class SystemActionTDelegateType extends SystemUnboundGenericDelegateType {
SystemActionTDelegateType() {
this.getName().regexpMatch("Action<,*>")
}
SystemActionTDelegateType() { this.getName().regexpMatch("Action<,*>") }
}
/** `System.Array` class. */
class SystemArrayClass extends SystemClass {
SystemArrayClass() {
this.hasName("Array")
}
}
class SystemArrayClass extends SystemClass { SystemArrayClass() { this.hasName("Array") } }
/** The `System.Boolean` structure. */
class SystemBooleanStruct extends BoolType {
/** Gets the `Parse(string)` method. */
Method getParseMethod() {
result.getDeclaringType() = this
and
result.hasName("Parse")
and
result.getNumberOfParameters() = 1
and
result.getParameter(0).getType() instanceof StringType
and
result.getDeclaringType() = this and
result.hasName("Parse") and
result.getNumberOfParameters() = 1 and
result.getParameter(0).getType() instanceof StringType and
result.getReturnType() instanceof BoolType
}
/** Gets the `TryParse(string, out bool)` method. */
Method getTryParseMethod() {
result.getDeclaringType() = this
and
result.hasName("TryParse")
and
result.getNumberOfParameters() = 2
and
result.getParameter(0).getType() instanceof StringType
and
result.getParameter(1).getType() instanceof BoolType
and
result.getDeclaringType() = this and
result.hasName("TryParse") and
result.getNumberOfParameters() = 2 and
result.getParameter(0).getType() instanceof StringType and
result.getParameter(1).getType() instanceof BoolType and
result.getReturnType() instanceof BoolType
}
}
/** The `System.Convert` class. */
class SystemConvertClass extends SystemClass {
SystemConvertClass() {
this.hasName("Convert")
}
}
class SystemConvertClass extends SystemClass { SystemConvertClass() { this.hasName("Convert") } }
/** `System.Delegate` class. */
class SystemDelegateClass extends SystemClass {
SystemDelegateClass() {
this.hasName("Delegate")
}
}
class SystemDelegateClass extends SystemClass { SystemDelegateClass() { this.hasName("Delegate") } }
/** The `System.DivideByZeroException` class. */
class SystemDivideByZeroExceptionClass extends SystemClass {
SystemDivideByZeroExceptionClass() {
this.hasName("DivideByZeroException")
}
SystemDivideByZeroExceptionClass() { this.hasName("DivideByZeroException") }
}
/** The `System.Enum` class. */
class SystemEnumClass extends SystemClass {
SystemEnumClass() {
this.hasName("Enum")
}
}
class SystemEnumClass extends SystemClass { SystemEnumClass() { this.hasName("Enum") } }
/** The `System.Exception` class. */
class SystemExceptionClass extends SystemClass {
SystemExceptionClass() {
this.hasName("Exception")
}
SystemExceptionClass() { this.hasName("Exception") }
}
/** The `System.Func<T1, ..., Tn, TResult>` delegate type. */
class SystemFuncDelegateType extends SystemUnboundGenericDelegateType {
SystemFuncDelegateType() {
this.getName().regexpMatch("Func<,*>")
}
SystemFuncDelegateType() { this.getName().regexpMatch("Func<,*>") }
/** Gets one of the `Ti` input type parameters. */
TypeParameter getAnInputTypeParameter() {
exists(int i |
i in [0 .. this.getNumberOfTypeParameters() - 2] |
exists(int i | i in [0 .. this.getNumberOfTypeParameters() - 2] |
result = this.getTypeParameter(i)
)
}
@@ -161,236 +112,170 @@ class SystemFuncDelegateType extends SystemUnboundGenericDelegateType {
/** The `System.IComparable` interface. */
class SystemIComparableInterface extends SystemInterface {
SystemIComparableInterface() {
this.hasName("IComparable")
}
SystemIComparableInterface() { this.hasName("IComparable") }
/** Gets the `CompareTo(object)` method. */
Method getCompareToMethod() {
result.getDeclaringType() = this
and
result.hasName("CompareTo")
and
result.getNumberOfParameters() = 1
and
result.getParameter(0).getType() instanceof ObjectType
and
result.getDeclaringType() = this and
result.hasName("CompareTo") and
result.getNumberOfParameters() = 1 and
result.getParameter(0).getType() instanceof ObjectType and
result.getReturnType() instanceof IntType
}
}
/** The `System.IComparable<T>` interface. */
class SystemIComparableTInterface extends SystemUnboundGenericInterface {
SystemIComparableTInterface() {
this.hasName("IComparable<>")
}
SystemIComparableTInterface() { this.hasName("IComparable<>") }
/** Gets the `CompareTo(T)` method. */
Method getCompareToMethod() {
result.getDeclaringType() = this
and
result.hasName("CompareTo")
and
result.getNumberOfParameters() = 1
and
result.getParameter(0).getType() = getTypeParameter(0)
and
result.getDeclaringType() = this and
result.hasName("CompareTo") and
result.getNumberOfParameters() = 1 and
result.getParameter(0).getType() = getTypeParameter(0) and
result.getReturnType() instanceof IntType
}
}
/** The `System.IEquatable<T>` interface. */
class SystemIEquatableTInterface extends SystemUnboundGenericInterface {
SystemIEquatableTInterface() {
this.hasName("IEquatable<>")
}
SystemIEquatableTInterface() { this.hasName("IEquatable<>") }
/** Gets the `Equals(T)` method. */
Method getEqualsMethod() {
result.getDeclaringType() = this
and
result.hasName("Equals")
and
result.getNumberOfParameters() = 1
and
result.getParameter(0).getType() = getTypeParameter(0)
and
result.getDeclaringType() = this and
result.hasName("Equals") and
result.getNumberOfParameters() = 1 and
result.getParameter(0).getType() = getTypeParameter(0) and
result.getReturnType() instanceof BoolType
}
}
/** The `System.IFormatProvider` interface. */
class SystemIFormatProviderInterface extends SystemInterface {
SystemIFormatProviderInterface() {
this.hasName("IFormatProvider")
}
SystemIFormatProviderInterface() { this.hasName("IFormatProvider") }
}
/** The `System.Int32` structure. */
class SystemInt32Struct extends IntType {
/** Gets the `Parse(string, ...)` method. */
Method getParseMethod() {
result.getDeclaringType() = this
and
result.hasName("Parse")
and
result.getParameter(0).getType() instanceof StringType
and
result.getDeclaringType() = this and
result.hasName("Parse") and
result.getParameter(0).getType() instanceof StringType and
result.getReturnType() instanceof IntType
}
/** Gets the `TryParse(string, ..., out int)` method. */
Method getTryParseMethod() {
result.getDeclaringType() = this
and
result.hasName("TryParse")
and
result.getParameter(0).getType() instanceof StringType
and
result.getParameter(result.getNumberOfParameters() - 1).getType() instanceof IntType
and
result.getDeclaringType() = this and
result.hasName("TryParse") and
result.getParameter(0).getType() instanceof StringType and
result.getParameter(result.getNumberOfParameters() - 1).getType() instanceof IntType and
result.getReturnType() instanceof BoolType
}
}
/** The `System.InvalidCastException` class. */
class SystemInvalidCastExceptionClass extends SystemClass {
SystemInvalidCastExceptionClass() {
this.hasName("InvalidCastException")
}
SystemInvalidCastExceptionClass() { this.hasName("InvalidCastException") }
}
/** The `System.Lazy<T>` class. */
class SystemLazyClass extends SystemUnboundGenericClass {
SystemLazyClass() {
this.hasName("Lazy<>")
and
this.hasName("Lazy<>") and
this.getNumberOfTypeParameters() = 1
}
/** Gets the `Value` property. */
Property getValueProperty() {
result.getDeclaringType() = this
and
result.hasName("Value")
and
result.getDeclaringType() = this and
result.hasName("Value") and
result.getType() = getTypeParameter(0)
}
}
/** The `System.NullReferenceException` class. */
class SystemNullReferenceExceptionClass extends SystemClass {
SystemNullReferenceExceptionClass() {
this.hasName("NullReferenceException")
}
SystemNullReferenceExceptionClass() { this.hasName("NullReferenceException") }
}
/** The `System.Object` class. */
class SystemObjectClass extends SystemClass {
SystemObjectClass() {
this instanceof ObjectType
}
SystemObjectClass() { this instanceof ObjectType }
/** Gets the `Equals(object)` method. */
Method getEqualsMethod() {
result.getDeclaringType() = this
and
result.hasName("Equals")
and
result.getNumberOfParameters() = 1
and
result.getParameter(0).getType() instanceof ObjectType
and
result.getDeclaringType() = this and
result.hasName("Equals") and
result.getNumberOfParameters() = 1 and
result.getParameter(0).getType() instanceof ObjectType and
result.getReturnType() instanceof BoolType
}
/** Gets the `Equals(object, object)` method. */
Method getStaticEqualsMethod() {
result.isStatic()
and
result.getDeclaringType() = this
and
result.hasName("Equals")
and
result.getNumberOfParameters() = 2
and
result.getParameter(0).getType() instanceof ObjectType
and
result.getParameter(1).getType() instanceof ObjectType
and
result.isStatic() and
result.getDeclaringType() = this and
result.hasName("Equals") and
result.getNumberOfParameters() = 2 and
result.getParameter(0).getType() instanceof ObjectType and
result.getParameter(1).getType() instanceof ObjectType and
result.getReturnType() instanceof BoolType
}
/** Gets the `ReferenceEquals(object, object)` method. */
Method getReferenceEqualsMethod() {
result.isStatic()
and
result.getDeclaringType() = this
and
result.hasName("ReferenceEquals")
and
result.getNumberOfParameters() = 2
and
result.getParameter(0).getType() instanceof ObjectType
and
result.getParameter(1).getType() instanceof ObjectType
and
result.isStatic() and
result.getDeclaringType() = this and
result.hasName("ReferenceEquals") and
result.getNumberOfParameters() = 2 and
result.getParameter(0).getType() instanceof ObjectType and
result.getParameter(1).getType() instanceof ObjectType and
result.getReturnType() instanceof BoolType
}
/** Gets the `GetHashCode()` method. */
Method getGetHashCodeMethod() {
result.getDeclaringType() = this
and
result.hasName("GetHashCode")
and
result.hasNoParameters()
and
result.getDeclaringType() = this and
result.hasName("GetHashCode") and
result.hasNoParameters() and
result.getReturnType() instanceof IntType
}
/** Gets the `GetType()` method. */
Method getGetTypeMethod() {
result.getDeclaringType() = this
and
result.hasName("GetType")
and
result.hasNoParameters()
and
result.getDeclaringType() = this and
result.hasName("GetType") and
result.hasNoParameters() and
result.getReturnType() instanceof SystemTypeClass
}
/** Gets the `ToString()` method. */
Method getToStringMethod() {
result.getDeclaringType() = this
and
result.hasName("ToString")
and
result.getNumberOfParameters() = 0
and
result.getDeclaringType() = this and
result.hasName("ToString") and
result.getNumberOfParameters() = 0 and
result.getReturnType() instanceof StringType
}
}
/** The `System.OutOfMemoryException` class. */
class SystemOutOfMemoryExceptionClass extends SystemClass {
SystemOutOfMemoryExceptionClass() {
this.hasName("OutOfMemoryException")
}
SystemOutOfMemoryExceptionClass() { this.hasName("OutOfMemoryException") }
}
/** The `System.OverflowException` class. */
class SystemOverflowExceptionClass extends SystemClass {
SystemOverflowExceptionClass() {
this.hasName("OverflowException")
}
SystemOverflowExceptionClass() { this.hasName("OverflowException") }
}
/** The `System.Predicate<T>` delegate type. */
class SystemPredicateDelegateType extends SystemUnboundGenericDelegateType {
SystemPredicateDelegateType() {
this.hasName("Predicate<>")
and
this.hasName("Predicate<>") and
this.getNumberOfTypeParameters() = 1
}
}
@@ -411,157 +296,113 @@ class SystemStringClass extends StringType {
/** Gets the `Replace(string/char, string/char)` method. */
Method getReplaceMethod() {
result.getDeclaringType() = this
and
result.hasName("Replace")
and
result.getNumberOfParameters() = 2
and
result.getDeclaringType() = this and
result.hasName("Replace") and
result.getNumberOfParameters() = 2 and
result.getReturnType() instanceof StringType
}
/** Gets a `Format(...)` method. */
Method getFormatMethod() {
result.getDeclaringType() = this
and
result.hasName("Format")
and
result.getNumberOfParameters() in [2 .. 5]
and
result.getDeclaringType() = this and
result.hasName("Format") and
result.getNumberOfParameters() in [2 .. 5] and
result.getReturnType() instanceof StringType
}
/** Gets a `Split(...)` method. */
Method getSplitMethod() {
result.getDeclaringType() = this
and
result.hasName("Split")
and
result.getNumberOfParameters() in [1 .. 3]
and
result.getDeclaringType() = this and
result.hasName("Split") and
result.getNumberOfParameters() in [1 .. 3] and
result.getReturnType().(ArrayType).getElementType() instanceof StringType
}
/** Gets a `Substring(...)` method. */
Method getSubstringMethod() {
result.getDeclaringType() = this
and
result.hasName("Substring")
and
result.getNumberOfParameters() in [1 .. 2]
and
result.getDeclaringType() = this and
result.hasName("Substring") and
result.getNumberOfParameters() in [1 .. 2] and
result.getReturnType() instanceof StringType
}
/** Gets a `Concat(...)` method. */
Method getConcatMethod() {
result.getDeclaringType() = this
and
result.hasName("Concat")
and
result.getDeclaringType() = this and
result.hasName("Concat") and
result.getReturnType() instanceof StringType
}
/** Gets the `Copy()` method. */
Method getCopyMethod() {
result.getDeclaringType() = this
and
result.hasName("Copy")
and
result.getNumberOfParameters() = 1
and
result.getParameter(0).getType() instanceof StringType
and
result.getDeclaringType() = this and
result.hasName("Copy") and
result.getNumberOfParameters() = 1 and
result.getParameter(0).getType() instanceof StringType and
result.getReturnType() instanceof StringType
}
/** Gets a `Join(string, ...)` method. */
Method getJoinMethod() {
result.getDeclaringType() = this
and
result.hasName("Join")
and
result.getNumberOfParameters() > 1
and
result.getParameter(0).getType() instanceof StringType
and
result.getDeclaringType() = this and
result.hasName("Join") and
result.getNumberOfParameters() > 1 and
result.getParameter(0).getType() instanceof StringType and
result.getReturnType() instanceof StringType
}
/** Gets the `Clone()` method. */
Method getCloneMethod() {
result.getDeclaringType() = this
and
result.hasName("Clone")
and
result.getNumberOfParameters() = 0
and
result.getDeclaringType() = this and
result.hasName("Clone") and
result.getNumberOfParameters() = 0 and
result.getReturnType() instanceof ObjectType
}
/** Gets the `Insert(int, string)` method. */
Method getInsertMethod() {
result.getDeclaringType() = this
and
result.hasName("Insert")
and
result.getNumberOfParameters() = 2
and
result.getParameter(0).getType() instanceof IntType
and
result.getParameter(1).getType() instanceof StringType
and
result.getDeclaringType() = this and
result.hasName("Insert") and
result.getNumberOfParameters() = 2 and
result.getParameter(0).getType() instanceof IntType and
result.getParameter(1).getType() instanceof StringType and
result.getReturnType() instanceof StringType
}
/** Gets the `Normalize(...)` method. */
Method getNormalizeMethod() {
result.getDeclaringType() = this
and
result.hasName("Normalize")
and
result.getNumberOfParameters() in [0 .. 1]
and
result.getDeclaringType() = this and
result.hasName("Normalize") and
result.getNumberOfParameters() in [0 .. 1] and
result.getReturnType() instanceof StringType
}
/** Gets a `Remove(...)` method. */
Method getRemoveMethod() {
result.getDeclaringType() = this
and
result.hasName("Remove")
and
result.getNumberOfParameters() in [1 .. 2]
and
result.getDeclaringType() = this and
result.hasName("Remove") and
result.getNumberOfParameters() in [1 .. 2] and
result.getReturnType() instanceof StringType
}
/** Gets the `IsNullOrEmpty(string)` method. */
Method getIsNullOrEmptyMethod() {
result.getDeclaringType() = this
and
result.hasName("IsNullOrEmpty")
and
result.isStatic()
and
result.getNumberOfParameters() = 1
and
result.getDeclaringType() = this and
result.hasName("IsNullOrEmpty") and
result.isStatic() and
result.getNumberOfParameters() = 1 and
result.getReturnType() instanceof BoolType
}
}
/** A `ToString()` method. */
class ToStringMethod extends Method {
ToStringMethod() {
this = any(SystemObjectClass c).getToStringMethod().getAnOverrider*()
}
ToStringMethod() { this = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() }
}
/** The `System.Type` class */
class SystemTypeClass extends SystemClass {
SystemTypeClass() {
this.hasName("Type")
}
SystemTypeClass() { this.hasName("Type") }
/** Gets the `FullName` property. */
Property getFullNameProperty() {
@@ -572,95 +413,71 @@ class SystemTypeClass extends SystemClass {
/** Gets the `InvokeMember(string, ...)` method. */
Method getInvokeMemberMethod() {
result.getDeclaringType() = this
and
result.hasName("InvokeMember")
and
result.getParameter(0).getType() instanceof StringType
and
result.getParameter(3).getType() instanceof ObjectType
and
result.getParameter(4).getType().(ArrayType).getElementType() instanceof ObjectType
and
result.getDeclaringType() = this and
result.hasName("InvokeMember") and
result.getParameter(0).getType() instanceof StringType and
result.getParameter(3).getType() instanceof ObjectType and
result.getParameter(4).getType().(ArrayType).getElementType() instanceof ObjectType and
result.getReturnType() instanceof ObjectType
}
/** Gets the `GetMethod(string, ...)` method. */
Method getGetMethodMethod() {
result.getDeclaringType() = this
and
result.hasName("GetMethod")
and
result.getParameter(0).getType() instanceof StringType
and
result.getDeclaringType() = this and
result.hasName("GetMethod") and
result.getParameter(0).getType() instanceof StringType and
result.getReturnType() instanceof SystemReflectionMethodInfoClass
}
}
/** The `System.Uri` class. */
class SystemUriClass extends SystemClass {
SystemUriClass() {
this.hasName("Uri")
}
SystemUriClass() { this.hasName("Uri") }
/** Gets the `PathAndQuery` property. */
Property getPathAndQueryProperty() {
result.getDeclaringType() = this
and
result.hasName("PathAndQuery")
and
result.getDeclaringType() = this and
result.hasName("PathAndQuery") and
result.getType() instanceof StringType
}
/** Gets the `Query` property. */
Property getQueryProperty() {
result.getDeclaringType() = this
and
result.hasName("Query")
and
result.getDeclaringType() = this and
result.hasName("Query") and
result.getType() instanceof StringType
}
/** Gets the `OriginalString` property. */
Property getOriginalStringProperty() {
result.getDeclaringType() = this
and
result.hasName("OriginalString")
and
result.getDeclaringType() = this and
result.hasName("OriginalString") and
result.getType() instanceof StringType
}
}
/** The `System.ValueType` class. */
class SystemValueTypeClass extends SystemClass {
SystemValueTypeClass() {
this.hasName("ValueType")
}
SystemValueTypeClass() { this.hasName("ValueType") }
}
/** The `System.IntPtr` type. */
class SystemIntPtrType extends ValueType {
SystemIntPtrType() {
this = any(SystemNamespace n).getATypeDeclaration()
and
this = any(SystemNamespace n).getATypeDeclaration() and
this.hasName("IntPtr")
}
}
/** The `System.IDisposable` interface. */
class SystemIDisposableInterface extends SystemInterface {
SystemIDisposableInterface() {
this.hasName("IDisposable")
}
SystemIDisposableInterface() { this.hasName("IDisposable") }
/** Gets the `Dispose()` method. */
Method getDisposeMethod() {
result.getDeclaringType() = this
and
result.hasName("Dispose")
and
result.getNumberOfParameters() = 0
and
result.getDeclaringType() = this and
result.hasName("Dispose") and
result.getNumberOfParameters() = 0 and
result.getReturnType() instanceof VoidType
}
}
@@ -668,8 +485,7 @@ class SystemIDisposableInterface extends SystemInterface {
/** A method that overrides `int object.GetHashCode()`. */
class GetHashCodeMethod extends Method {
GetHashCodeMethod() {
exists(Method m |
m = any(SystemObjectClass c).getGetHashCodeMethod() |
exists(Method m | m = any(SystemObjectClass c).getGetHashCodeMethod() |
this = m.getAnOverrider*()
)
}
@@ -678,10 +494,7 @@ class GetHashCodeMethod extends Method {
/** A method that overrides `bool object.Equals(object)`. */
class EqualsMethod extends Method {
EqualsMethod() {
exists(Method m |
m = any(SystemObjectClass c).getEqualsMethod() |
this = m.getAnOverrider*()
)
exists(Method m | m = any(SystemObjectClass c).getEqualsMethod() | this = m.getAnOverrider*())
}
}
@@ -690,7 +503,8 @@ class IEquatableEqualsMethod extends Method {
IEquatableEqualsMethod() {
exists(Method m |
m = any(SystemIEquatableTInterface i).getAConstructedGeneric().getAMethod() and
m.getSourceDeclaration() = any(SystemIEquatableTInterface i).getEqualsMethod() |
m.getSourceDeclaration() = any(SystemIEquatableTInterface i).getEqualsMethod()
|
this = m or getAnUltimateImplementee() = m
)
}
@@ -703,9 +517,7 @@ class IEquatableEqualsMethod extends Method {
* or an implementation of `IEquatable<T>.Equals(T)` which is called
* from the `object.Equals(object)` method inherited by `t`.
*/
predicate implementsEquals(ValueOrRefType t) {
getInvokedEqualsMethod(t).getDeclaringType() = t
}
predicate implementsEquals(ValueOrRefType t) { getInvokedEqualsMethod(t).getDeclaringType() = t }
/**
* Gets the equals method that will be invoked on a value `x`
@@ -725,9 +537,7 @@ Method getInvokedEqualsMethod(ValueOrRefType t) {
)
}
private EqualsMethod getInheritedEqualsMethod(ValueOrRefType t) {
t.hasMethod(result)
}
private EqualsMethod getInheritedEqualsMethod(ValueOrRefType t) { t.hasMethod(result) }
/**
* Equals method `eq` is inherited by `t`, `t` overrides `IEquatable<T>.Equals(T)`
@@ -754,7 +564,8 @@ private IEquatableEqualsMethod getInvokedIEquatableEqualsMethod(ValueOrRefType t
eq = getInheritedEqualsMethod(t.getBaseClass()) and
exists(IEquatableEqualsMethod ieem |
result = ieem.getAnOverrider*() and
eq.getDeclaringType() = ieem.getDeclaringType() |
eq.getDeclaringType() = ieem.getDeclaringType()
|
not ieem.fromSource()
or
callsEqualsMethod(eq, ieem)
@@ -772,8 +583,7 @@ private predicate callsEqualsMethod(EqualsMethod eq, IEquatableEqualsMethod ieem
/** A method that implements `void IDisposable.Dispose()`. */
class DisposeMethod extends Method {
DisposeMethod() {
exists(Method m |
m = any(SystemIDisposableInterface i).getDisposeMethod() |
exists(Method m | m = any(SystemIDisposableInterface i).getDisposeMethod() |
this = m or this.getAnUltimateImplementee() = m
)
}
@@ -796,9 +606,7 @@ library class DisposeBoolMethod extends Method {
* or an implementation of a method `Dispose(bool)` which is called
* from the `IDisposable.Dispose()` method inherited by `t`.
*/
predicate implementsDispose(ValueOrRefType t) {
getInvokedDisposeMethod(t).getDeclaringType() = t
}
predicate implementsDispose(ValueOrRefType t) { getInvokedDisposeMethod(t).getDeclaringType() = t }
/**
* Gets the dispose method that will be invoked on a value `x`
@@ -818,9 +626,7 @@ Method getInvokedDisposeMethod(ValueOrRefType t) {
)
}
private DisposeMethod getInheritedDisposeMethod(ValueOrRefType t) {
t.hasMethod(result)
}
private DisposeMethod getInheritedDisposeMethod(ValueOrRefType t) { t.hasMethod(result) }
/**
* Dispose method `disp` is inherited by `t`, `t` overrides a `void Dispose(bool)`
@@ -847,7 +653,8 @@ private DisposeBoolMethod getInvokedDiposeBoolMethod(ValueOrRefType t, DisposeMe
disp = getInheritedDisposeMethod(t.getBaseClass()) and
exists(DisposeBoolMethod dbm |
result = dbm.getAnOverrider*() and
disp.getDeclaringType() = dbm.getDeclaringType() |
disp.getDeclaringType() = dbm.getDeclaringType()
|
not disp.fromSource()
or
exists(MethodCall callToDerivedDispose |
@@ -859,21 +666,13 @@ private DisposeBoolMethod getInvokedDiposeBoolMethod(ValueOrRefType t, DisposeMe
/** A struct in the `System` namespace. */
class SystemStruct extends Struct {
SystemStruct() {
this.getNamespace() instanceof SystemNamespace
}
SystemStruct() { this.getNamespace() instanceof SystemNamespace }
}
/** `System.Guid` struct. */
class SystemGuid extends SystemStruct {
SystemGuid() {
this.hasName("Guid")
}
}
class SystemGuid extends SystemStruct { SystemGuid() { this.hasName("Guid") } }
/** The `System.NotImplementedException` class. */
class SystemNotImplementedExceptionClass extends SystemClass {
SystemNotImplementedExceptionClass() {
this.hasName("NotImplementedException")
}
SystemNotImplementedExceptionClass() { this.hasName("NotImplementedException") }
}

Some files were not shown because too many files have changed in this diff Show More