C#: Handle named attribute arguments

This commit is contained in:
Tom Hvitved
2019-03-27 10:39:50 +01:00
parent 12843d2b0e
commit 7634973bb4
6 changed files with 89 additions and 14 deletions

View File

@@ -0,0 +1,17 @@
# Improvements to C# analysis
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------|
## Changes to code extraction
* Named attribute arguments are now extracted.
## Changes to QL libraries
* The class `Attribute` has two new predicates: `getConstructorArgument()` and `getNamedArgument()`. The first predicate returns arguments to the underlying constructor call and the latter returns named arguments for initializing fields and properties.
## Changes to autobuilder

View File

@@ -51,9 +51,12 @@ namespace Semmle.Extraction.CSharp.Entities
int child = 0;
foreach (var arg in syntax.ArgumentList.Arguments)
{
Expression.Create(cx, arg.Expression, this, child++);
var expr = Expression.Create(cx, arg.Expression, this, child++);
if (arg.NameEquals != null)
{
cx.Emit(Tuples.expr_argument_name(expr, arg.NameEquals.Name.Identifier.Text));
}
}
// !! Handle named arguments
});
}
}
@@ -66,14 +69,6 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public static void ExtractAttributes(Context cx, IEnumerable<AttributeListSyntax> attributes, IEntity entity)
{
foreach (var attributeSyntax in attributes.SelectMany(l => l.Attributes))
{
new Attribute(cx, attributeSyntax, entity);
}
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
}
}

View File

@@ -28,7 +28,10 @@ class Attributable extends @attributable {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.(Element).getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
this
.(Element)
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -51,9 +54,37 @@ class Attribute extends TopLevelExprParent, @attribute {
/** Gets the element that this attribute is attached to. */
Attributable getTarget() { attributes(this, _, result) }
/** Gets the `i`th argument of this attribute. */
/**
* Gets the `i`th argument of this attribute. This includes both constructor
* arguments and named arguments.
*/
Expr getArgument(int i) { result = this.getChildExpr(i) }
/**
* Gets the `i`th constructor argument of this attribute. For example, only
* `true` is a constructor argument in
*
* ```
* MyAttribute[true, Foo = 0]
* ```
*/
Expr getConstructorArgument(int i) {
result = this.getArgument(i) and not exists(result.getExplicitArgumentName())
}
/**
* Gets the named argument `name` of this attribute. For example, only
* `0` is a named argument in
*
* ```
* MyAttribute[true, Foo = 0]
* ```
*/
Expr getNamedArgument(string name) {
result = this.getArgument(_) and
result.getExplicitArgumentName() = name
}
override Location getALocation() { attribute_location(this, result) }
override string toString() {

View File

@@ -7,3 +7,5 @@
| arguments.cs:39:27:39:27 | 0 | o |
| arguments.cs:40:18:40:35 | array creation of type Int32[] | args |
| arguments.cs:40:41:40:41 | 0 | o |
| arguments.cs:68:28:68:29 | "" | y |
| arguments.cs:68:36:68:36 | 0 | x |

View File

@@ -1,3 +1,4 @@
arguments
| attributes.cs:10:12:10:24 | [AssemblyTitle(...)] | 0 | attributes.cs:10:26:10:45 | "C# attributes test" |
| attributes.cs:11:12:11:30 | [AssemblyDescription(...)] | 0 | attributes.cs:11:32:11:56 | "A test of C# attributes" |
| attributes.cs:12:12:12:32 | [AssemblyConfiguration(...)] | 0 | attributes.cs:12:34:12:35 | "" |
@@ -16,3 +17,23 @@
| attributes.cs:54:6:54:16 | [My(...)] | 0 | attributes.cs:54:18:54:21 | true |
| attributes.cs:54:6:54:16 | [My(...)] | 1 | attributes.cs:54:28:54:29 | "" |
| attributes.cs:54:6:54:16 | [My(...)] | 2 | attributes.cs:54:36:54:36 | 0 |
constructorArguments
| attributes.cs:10:12:10:24 | [AssemblyTitle(...)] | 0 | attributes.cs:10:26:10:45 | "C# attributes test" |
| attributes.cs:11:12:11:30 | [AssemblyDescription(...)] | 0 | attributes.cs:11:32:11:56 | "A test of C# attributes" |
| attributes.cs:12:12:12:32 | [AssemblyConfiguration(...)] | 0 | attributes.cs:12:34:12:35 | "" |
| attributes.cs:13:12:13:26 | [AssemblyCompany(...)] | 0 | attributes.cs:13:28:13:39 | "Semmle Plc" |
| attributes.cs:14:12:14:26 | [AssemblyProduct(...)] | 0 | attributes.cs:14:28:14:34 | "Odasa" |
| attributes.cs:15:12:15:28 | [AssemblyCopyright(...)] | 0 | attributes.cs:15:30:15:54 | "Copyright \ufffd Semmle 2018" |
| attributes.cs:16:12:16:28 | [AssemblyTrademark(...)] | 0 | attributes.cs:16:30:16:31 | "" |
| attributes.cs:17:12:17:26 | [AssemblyCulture(...)] | 0 | attributes.cs:17:28:17:29 | "" |
| attributes.cs:22:12:22:21 | [ComVisible(...)] | 0 | attributes.cs:22:23:22:27 | false |
| attributes.cs:25:12:25:15 | [Guid(...)] | 0 | attributes.cs:25:17:25:54 | "2f70fdd6-14aa-4850-b053-d547adb1f476" |
| attributes.cs:37:12:37:26 | [AssemblyVersion(...)] | 0 | attributes.cs:37:28:37:36 | "1.0.0.0" |
| attributes.cs:38:12:38:30 | [AssemblyFileVersion(...)] | 0 | attributes.cs:38:32:38:40 | "1.0.0.0" |
| attributes.cs:40:2:40:22 | [AttributeUsage(...)] | 0 | attributes.cs:40:24:40:50 | access to constant All |
| attributes.cs:43:6:43:16 | [Conditional(...)] | 0 | attributes.cs:43:18:43:25 | "DEBUG2" |
| attributes.cs:51:6:51:16 | [My(...)] | 0 | attributes.cs:51:18:51:22 | false |
| attributes.cs:54:6:54:16 | [My(...)] | 0 | attributes.cs:54:18:54:21 | true |
namedArguments
| attributes.cs:54:6:54:16 | [My(...)] | x | attributes.cs:54:36:54:36 | 0 |
| attributes.cs:54:6:54:16 | [My(...)] | y | attributes.cs:54:28:54:29 | "" |

View File

@@ -1,4 +1,13 @@
import csharp
from Attribute attribute, int index
select attribute, index, attribute.getArgument(index)
query predicate arguments(Attribute attribute, int index, Expr e) {
e = attribute.getArgument(index)
}
query predicate constructorArguments(Attribute attribute, int index, Expr e) {
e = attribute.getConstructorArgument(index)
}
query predicate namedArguments(Attribute attribute, string name, Expr e) {
e = attribute.getNamedArgument(name)
}