C#: Extract indexed initializers correctly.

This commit is contained in:
Calum Grant
2020-05-11 09:31:48 +01:00
parent b2f1008a00
commit 84bce9f742
5 changed files with 150 additions and 9 deletions

View File

@@ -18,7 +18,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.FIELD_ACCESS;
case SymbolKind.Property:
return ExprKind.PROPERTY_ACCESS;
return symbol is IPropertySymbol prop && prop.IsIndexer ?
ExprKind.INDEXER_ACCESS : ExprKind.PROPERTY_ACCESS;
case SymbolKind.Event:
return ExprKind.EVENT_ACCESS;

View File

@@ -74,14 +74,22 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
CreateFromNode(new ExpressionNodeInfo(cx, assignment.Right, assignmentEntity, 0));
var target = cx.GetSymbolInfo(assignment.Left);
if (target.Symbol == null)
{
cx.ModelError(assignment, "Unknown object initializer");
new Unknown(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1));
}
else
{
// If the target is null, then assume that this is an array initializer (of the form `[...] = ...`)
Expression access = target.Symbol is null ?
new Expression(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) :
Access.Create(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1), target.Symbol, false, cx.CreateEntity(target.Symbol));
if (assignment.Left is ImplicitElementAccessSyntax iea)
{
// An array/indexer initializer of the form `[...] = ...`
int indexChild = 0;
foreach (var arg in iea.ArgumentList.Arguments)
{
Expression.Create(cx, arg.Expression, access, indexChild++);
}
}
}
else

View File

@@ -0,0 +1,78 @@
assignedMembers
| csharp6.cs:12:16:12:20 | Value | csharp6.cs:15:9:15:10 | 20 |
| csharp6.cs:57:40:57:54 | DictionaryField | csharp6.cs:73:31:73:72 | { ..., ... } |
| csharp6.cs:58:40:58:57 | DictionaryProperty | csharp6.cs:74:34:74:76 | { ..., ... } |
| csharp6.cs:59:25:59:34 | ArrayField | csharp6.cs:75:26:75:54 | { ..., ... } |
| csharp6.cs:60:25:60:37 | ArrayProperty | csharp6.cs:77:29:77:56 | { ..., ... } |
| csharp6.cs:61:26:61:36 | ArrayField2 | csharp6.cs:76:27:76:56 | { ..., ... } |
| csharp6.cs:62:26:62:39 | ArrayProperty2 | csharp6.cs:78:30:78:59 | { ..., ... } |
indexerCalls
| csharp6.cs:32:68:32:70 | access to indexer | 0 | csharp6.cs:32:69:32:69 | 2 |
| csharp6.cs:32:68:32:73 | access to indexer | 0 | csharp6.cs:32:72:32:72 | 1 |
| csharp6.cs:68:52:68:54 | access to indexer | 0 | csharp6.cs:68:53:68:53 | 0 |
| csharp6.cs:68:52:68:54 | access to indexer | 1 | csharp6.cs:68:58:68:63 | "Zero" |
| csharp6.cs:68:66:68:68 | access to indexer | 0 | csharp6.cs:68:67:68:67 | 1 |
| csharp6.cs:68:66:68:68 | access to indexer | 1 | csharp6.cs:68:72:68:76 | "One" |
| csharp6.cs:68:79:68:81 | access to indexer | 0 | csharp6.cs:68:80:68:80 | 2 |
| csharp6.cs:68:79:68:81 | access to indexer | 1 | csharp6.cs:68:85:68:89 | "Two" |
| csharp6.cs:73:33:73:35 | access to indexer | 0 | csharp6.cs:73:34:73:34 | 0 |
| csharp6.cs:73:33:73:35 | access to indexer | 1 | csharp6.cs:73:39:73:44 | "Zero" |
| csharp6.cs:73:47:73:49 | access to indexer | 0 | csharp6.cs:73:48:73:48 | 1 |
| csharp6.cs:73:47:73:49 | access to indexer | 1 | csharp6.cs:73:53:73:57 | "One" |
| csharp6.cs:73:60:73:62 | access to indexer | 0 | csharp6.cs:73:61:73:61 | 2 |
| csharp6.cs:73:60:73:62 | access to indexer | 1 | csharp6.cs:73:66:73:70 | "Two" |
| csharp6.cs:74:36:74:38 | access to indexer | 0 | csharp6.cs:74:37:74:37 | 3 |
| csharp6.cs:74:36:74:38 | access to indexer | 1 | csharp6.cs:74:42:74:48 | "Three" |
| csharp6.cs:74:51:74:53 | access to indexer | 0 | csharp6.cs:74:52:74:52 | 2 |
| csharp6.cs:74:51:74:53 | access to indexer | 1 | csharp6.cs:74:57:74:61 | "Two" |
| csharp6.cs:74:64:74:66 | access to indexer | 0 | csharp6.cs:74:65:74:65 | 1 |
| csharp6.cs:74:64:74:66 | access to indexer | 1 | csharp6.cs:74:70:74:74 | "One" |
elementAssignments
| csharp6.cs:68:52:68:54 | access to indexer | csharp6.cs:68:52:68:63 | ... = ... | 0 | csharp6.cs:68:53:68:53 | 0 |
| csharp6.cs:68:66:68:68 | access to indexer | csharp6.cs:68:66:68:76 | ... = ... | 0 | csharp6.cs:68:67:68:67 | 1 |
| csharp6.cs:68:79:68:81 | access to indexer | csharp6.cs:68:79:68:89 | ... = ... | 0 | csharp6.cs:68:80:68:80 | 2 |
| csharp6.cs:73:33:73:35 | access to indexer | csharp6.cs:73:33:73:44 | ... = ... | 0 | csharp6.cs:73:34:73:34 | 0 |
| csharp6.cs:73:47:73:49 | access to indexer | csharp6.cs:73:47:73:57 | ... = ... | 0 | csharp6.cs:73:48:73:48 | 1 |
| csharp6.cs:73:60:73:62 | access to indexer | csharp6.cs:73:60:73:70 | ... = ... | 0 | csharp6.cs:73:61:73:61 | 2 |
| csharp6.cs:74:36:74:38 | access to indexer | csharp6.cs:74:36:74:48 | ... = ... | 0 | csharp6.cs:74:37:74:37 | 3 |
| csharp6.cs:74:51:74:53 | access to indexer | csharp6.cs:74:51:74:61 | ... = ... | 0 | csharp6.cs:74:52:74:52 | 2 |
| csharp6.cs:74:64:74:66 | access to indexer | csharp6.cs:74:64:74:74 | ... = ... | 0 | csharp6.cs:74:65:74:65 | 1 |
| csharp6.cs:75:28:75:30 | access to array element | csharp6.cs:75:28:75:39 | ... = ... | 0 | csharp6.cs:75:29:75:29 | 0 |
| csharp6.cs:75:42:75:44 | access to array element | csharp6.cs:75:42:75:52 | ... = ... | 0 | csharp6.cs:75:43:75:43 | 1 |
| csharp6.cs:76:29:76:34 | access to array element | csharp6.cs:76:29:76:40 | ... = ... | 0 | csharp6.cs:76:30:76:30 | 0 |
| csharp6.cs:76:29:76:34 | access to array element | csharp6.cs:76:29:76:40 | ... = ... | 1 | csharp6.cs:76:33:76:33 | 1 |
| csharp6.cs:76:43:76:48 | access to array element | csharp6.cs:76:43:76:54 | ... = ... | 0 | csharp6.cs:76:44:76:44 | 1 |
| csharp6.cs:76:43:76:48 | access to array element | csharp6.cs:76:43:76:54 | ... = ... | 1 | csharp6.cs:76:47:76:47 | 0 |
| csharp6.cs:77:31:77:33 | access to array element | csharp6.cs:77:31:77:41 | ... = ... | 0 | csharp6.cs:77:32:77:32 | 1 |
| csharp6.cs:77:44:77:46 | access to array element | csharp6.cs:77:44:77:54 | ... = ... | 0 | csharp6.cs:77:45:77:45 | 2 |
| csharp6.cs:78:32:78:37 | access to array element | csharp6.cs:78:32:78:43 | ... = ... | 0 | csharp6.cs:78:33:78:33 | 0 |
| csharp6.cs:78:32:78:37 | access to array element | csharp6.cs:78:32:78:43 | ... = ... | 1 | csharp6.cs:78:36:78:36 | 1 |
| csharp6.cs:78:46:78:51 | access to array element | csharp6.cs:78:46:78:57 | ... = ... | 0 | csharp6.cs:78:47:78:47 | 1 |
| csharp6.cs:78:46:78:51 | access to array element | csharp6.cs:78:46:78:57 | ... = ... | 1 | csharp6.cs:78:50:78:50 | 0 |
arrayQualifiers
| csharp6.cs:32:68:32:70 | access to indexer | csharp6.cs:32:38:32:66 | object creation of type Dictionary<Int32,String> |
| csharp6.cs:32:68:32:73 | access to indexer | csharp6.cs:32:68:32:70 | access to indexer |
initializers
| csharp6.cs:68:50:68:91 | { ..., ... } | 0 | csharp6.cs:68:52:68:63 | ... = ... |
| csharp6.cs:68:50:68:91 | { ..., ... } | 1 | csharp6.cs:68:66:68:76 | ... = ... |
| csharp6.cs:68:50:68:91 | { ..., ... } | 2 | csharp6.cs:68:79:68:89 | ... = ... |
| csharp6.cs:72:9:79:9 | { ..., ... } | 0 | csharp6.cs:73:13:73:72 | ... = ... |
| csharp6.cs:72:9:79:9 | { ..., ... } | 1 | csharp6.cs:74:13:74:76 | ... = ... |
| csharp6.cs:72:9:79:9 | { ..., ... } | 2 | csharp6.cs:75:13:75:54 | ... = ... |
| csharp6.cs:72:9:79:9 | { ..., ... } | 3 | csharp6.cs:76:13:76:56 | ... = ... |
| csharp6.cs:72:9:79:9 | { ..., ... } | 4 | csharp6.cs:77:13:77:56 | ... = ... |
| csharp6.cs:72:9:79:9 | { ..., ... } | 5 | csharp6.cs:78:13:78:59 | ... = ... |
| csharp6.cs:73:31:73:72 | { ..., ... } | 0 | csharp6.cs:73:33:73:44 | ... = ... |
| csharp6.cs:73:31:73:72 | { ..., ... } | 1 | csharp6.cs:73:47:73:57 | ... = ... |
| csharp6.cs:73:31:73:72 | { ..., ... } | 2 | csharp6.cs:73:60:73:70 | ... = ... |
| csharp6.cs:74:34:74:76 | { ..., ... } | 0 | csharp6.cs:74:36:74:48 | ... = ... |
| csharp6.cs:74:34:74:76 | { ..., ... } | 1 | csharp6.cs:74:51:74:61 | ... = ... |
| csharp6.cs:74:34:74:76 | { ..., ... } | 2 | csharp6.cs:74:64:74:74 | ... = ... |
| csharp6.cs:75:26:75:54 | { ..., ... } | 0 | csharp6.cs:75:28:75:39 | ... = ... |
| csharp6.cs:75:26:75:54 | { ..., ... } | 1 | csharp6.cs:75:42:75:52 | ... = ... |
| csharp6.cs:76:27:76:56 | { ..., ... } | 0 | csharp6.cs:76:29:76:40 | ... = ... |
| csharp6.cs:76:27:76:56 | { ..., ... } | 1 | csharp6.cs:76:43:76:54 | ... = ... |
| csharp6.cs:77:29:77:56 | { ..., ... } | 0 | csharp6.cs:77:31:77:41 | ... = ... |
| csharp6.cs:77:29:77:56 | { ..., ... } | 1 | csharp6.cs:77:44:77:54 | ... = ... |
| csharp6.cs:78:30:78:59 | { ..., ... } | 0 | csharp6.cs:78:32:78:43 | ... = ... |
| csharp6.cs:78:30:78:59 | { ..., ... } | 1 | csharp6.cs:78:46:78:57 | ... = ... |

View File

@@ -0,0 +1,24 @@
import csharp
query predicate assignedMembers(AssignableMember member, Expr value) {
member.fromSource() and
value = member.getAnAssignedValue()
}
query predicate indexerCalls(IndexerCall indexer, int arg, Expr value) {
value = indexer.getArgument(arg)
}
query predicate elementAssignments(
ElementWrite write, Assignment assignment, int index, Expr indexer
) {
write = assignment.getLValue() and indexer = write.getIndex(index)
}
query predicate arrayQualifiers(ElementAccess access, Expr qualifier) {
qualifier = access.getQualifier()
}
query predicate initializers(ObjectInitializer init, int item, Expr expr) {
expr = init.getMemberInitializer(item)
}

View File

@@ -50,4 +50,34 @@ class TestCSharp6
int this[int i] => i;
}
// semmle-extractor-options: /r:System.Linq.dll
class IndexInitializers
{
class Compound
{
public Dictionary<int, string> DictionaryField;
public Dictionary<int, string> DictionaryProperty { get; set; }
public string[] ArrayField;
public string[] ArrayProperty { get; set; }
public string[,] ArrayField2;
public string[,] ArrayProperty2 { get; set; }
}
void Test()
{
// Collection initializer
var dict = new Dictionary<int, string>() { [0] = "Zero", [1] = "One", [2] = "Two" };
// Indexed initializer
var compound = new Compound()
{
DictionaryField = { [0] = "Zero", [1] = "One", [2] = "Two" },
DictionaryProperty = { [3] = "Three", [2] = "Two", [1] = "One" },
ArrayField = { [0] = "Zero", [1] = "One" },
ArrayField2 = { [0, 1] = "i", [1, 0] = "1" },
ArrayProperty = { [1] = "One", [2] = "Two" },
ArrayProperty2 = { [0, 1] = "i", [1, 0] = "1" },
};
}
}
// semmle-extractor-options: /r:System.Linq.dll /langerversion:6.0