mirror of
https://github.com/github/codeql.git
synced 2026-01-06 11:10:23 +01:00
Merge pull request #4617 from tamasvajk/feature/csharp9-implicit-obj-creation
C#: Extract 'ImplicitObjectCreationExpressionSyntax'
This commit is contained in:
@@ -84,6 +84,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
case SyntaxKind.ObjectCreationExpression:
|
||||
return ExplicitObjectCreation.Create(info);
|
||||
|
||||
case SyntaxKind.ImplicitObjectCreationExpression:
|
||||
return ImplicitObjectCreation.Create(info);
|
||||
|
||||
case SyntaxKind.ArrayCreationExpression:
|
||||
return NormalArrayCreation.Create(info);
|
||||
|
||||
@@ -179,7 +182,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
return ImplicitArrayCreation.Create(info);
|
||||
|
||||
case SyntaxKind.AnonymousObjectCreationExpression:
|
||||
return ImplicitObjectCreation.Create(info);
|
||||
return AnonymousObjectCreation.Create(info);
|
||||
|
||||
case SyntaxKind.ComplexElementInitializerExpression:
|
||||
return CollectionInitializer.Create(info);
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
internal abstract class ObjectCreation<TExpressionSyntax> : Expression<TExpressionSyntax>
|
||||
where TExpressionSyntax : ExpressionSyntax
|
||||
{
|
||||
protected ObjectCreation(ExpressionNodeInfo info)
|
||||
: base(info) { }
|
||||
}
|
||||
|
||||
// new Foo(...) { ... }.
|
||||
internal class ExplicitObjectCreation : ObjectCreation<ObjectCreationExpressionSyntax>
|
||||
{
|
||||
private static bool IsDynamicObjectCreation(Context cx, ObjectCreationExpressionSyntax node)
|
||||
{
|
||||
return node.ArgumentList != null && node.ArgumentList.Arguments.Any(arg => IsDynamic(cx, arg.Expression));
|
||||
}
|
||||
|
||||
private static ExprKind GetKind(Context cx, ObjectCreationExpressionSyntax node)
|
||||
{
|
||||
var si = cx.GetModel(node).GetSymbolInfo(node.Type);
|
||||
return Entities.Type.IsDelegate(si.Symbol as INamedTypeSymbol) ? ExprKind.EXPLICIT_DELEGATE_CREATION : ExprKind.OBJECT_CREATION;
|
||||
}
|
||||
|
||||
private ExplicitObjectCreation(ExpressionNodeInfo info)
|
||||
: base(info.SetKind(GetKind(info.Context, (ObjectCreationExpressionSyntax)info.Node))) { }
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new ExplicitObjectCreation(info).TryPopulate();
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
if (Syntax.ArgumentList != null)
|
||||
{
|
||||
PopulateArguments(trapFile, Syntax.ArgumentList, 0);
|
||||
}
|
||||
|
||||
var target = cx.GetModel(Syntax).GetSymbolInfo(Syntax);
|
||||
var method = (IMethodSymbol)target.Symbol;
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
trapFile.expr_call(this, Method.Create(cx, method));
|
||||
}
|
||||
|
||||
if (IsDynamicObjectCreation(cx, Syntax))
|
||||
{
|
||||
var name = GetDynamicName(Syntax.Type);
|
||||
if (name.HasValue)
|
||||
trapFile.dynamic_member_name(this, name.Value.Text);
|
||||
else
|
||||
cx.ModelError(Syntax, "Unable to get name for dynamic object creation.");
|
||||
}
|
||||
|
||||
if (Syntax.Initializer != null)
|
||||
{
|
||||
switch (Syntax.Initializer.Kind())
|
||||
{
|
||||
case SyntaxKind.CollectionInitializerExpression:
|
||||
CollectionInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1) { Type = Type });
|
||||
break;
|
||||
case SyntaxKind.ObjectInitializerExpression:
|
||||
ObjectInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1) { Type = Type });
|
||||
break;
|
||||
default:
|
||||
cx.ModelError("Unhandled initializer in object creation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TypeMention.Create(cx, Syntax.Type, this, Type);
|
||||
}
|
||||
|
||||
private static SyntaxToken? GetDynamicName(CSharpSyntaxNode name)
|
||||
{
|
||||
switch (name.Kind())
|
||||
{
|
||||
case SyntaxKind.IdentifierName:
|
||||
return ((IdentifierNameSyntax)name).Identifier;
|
||||
case SyntaxKind.GenericName:
|
||||
return ((GenericNameSyntax)name).Identifier;
|
||||
case SyntaxKind.QualifiedName:
|
||||
// We ignore any qualifiers, for now
|
||||
return GetDynamicName(((QualifiedNameSyntax)name).Right);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ImplicitObjectCreation : ObjectCreation<AnonymousObjectCreationExpressionSyntax>
|
||||
{
|
||||
public ImplicitObjectCreation(ExpressionNodeInfo info)
|
||||
: base(info.SetKind(ExprKind.OBJECT_CREATION)) { }
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) =>
|
||||
new ImplicitObjectCreation(info).TryPopulate();
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
var target = cx.GetSymbolInfo(Syntax);
|
||||
var method = (IMethodSymbol)target.Symbol;
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
trapFile.expr_call(this, Method.Create(cx, method));
|
||||
}
|
||||
var child = 0;
|
||||
|
||||
var objectInitializer = Syntax.Initializers.Any() ?
|
||||
new Expression(new ExpressionInfo(cx, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null)) :
|
||||
null;
|
||||
|
||||
foreach (var init in Syntax.Initializers)
|
||||
{
|
||||
// Create an "assignment"
|
||||
var property = cx.GetModel(init).GetDeclaredSymbol(init);
|
||||
var propEntity = Property.Create(cx, property);
|
||||
var type = Entities.Type.Create(cx, property.GetAnnotatedType());
|
||||
var loc = cx.Create(init.GetLocation());
|
||||
|
||||
var assignment = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, false, null));
|
||||
Create(cx, init.Expression, assignment, 0);
|
||||
Property.Create(cx, property);
|
||||
|
||||
var access = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.PROPERTY_ACCESS, assignment, 1, false, null));
|
||||
trapFile.expr_access(access, propEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
internal class AnonymousObjectCreation : Expression<AnonymousObjectCreationExpressionSyntax>
|
||||
{
|
||||
public AnonymousObjectCreation(ExpressionNodeInfo info)
|
||||
: base(info.SetKind(ExprKind.OBJECT_CREATION)) { }
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) =>
|
||||
new AnonymousObjectCreation(info).TryPopulate();
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
var target = cx.GetSymbolInfo(Syntax);
|
||||
var method = (IMethodSymbol)target.Symbol;
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
trapFile.expr_call(this, Method.Create(cx, method));
|
||||
}
|
||||
var child = 0;
|
||||
|
||||
var objectInitializer = Syntax.Initializers.Any() ?
|
||||
new Expression(new ExpressionInfo(cx, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null)) :
|
||||
null;
|
||||
|
||||
foreach (var init in Syntax.Initializers)
|
||||
{
|
||||
// Create an "assignment"
|
||||
var property = cx.GetModel(init).GetDeclaredSymbol(init);
|
||||
var propEntity = Property.Create(cx, property);
|
||||
var type = Entities.Type.Create(cx, property.GetAnnotatedType());
|
||||
var loc = cx.Create(init.GetLocation());
|
||||
|
||||
var assignment = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, false, null));
|
||||
Create(cx, init.Expression, assignment, 0);
|
||||
Property.Create(cx, property);
|
||||
|
||||
var access = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.PROPERTY_ACCESS, assignment, 1, false, null));
|
||||
trapFile.expr_access(access, propEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Kinds;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
internal abstract class BaseObjectCreation<TExpressionSyntax> : Expression<TExpressionSyntax>
|
||||
where TExpressionSyntax : BaseObjectCreationExpressionSyntax
|
||||
{
|
||||
protected BaseObjectCreation(ExpressionNodeInfo info)
|
||||
: base(info.SetKind(GetKind(info.Context, (BaseObjectCreationExpressionSyntax)info.Node)))
|
||||
{
|
||||
}
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
if (Syntax.ArgumentList != null)
|
||||
{
|
||||
PopulateArguments(trapFile, Syntax.ArgumentList, 0);
|
||||
}
|
||||
|
||||
var target = cx.GetModel(Syntax).GetSymbolInfo(Syntax);
|
||||
if (target.Symbol is IMethodSymbol method)
|
||||
{
|
||||
trapFile.expr_call(this, Method.Create(cx, method));
|
||||
}
|
||||
|
||||
if (IsDynamicObjectCreation(cx, Syntax))
|
||||
{
|
||||
if (cx.GetModel(Syntax).GetTypeInfo(Syntax).Type is INamedTypeSymbol type &&
|
||||
!string.IsNullOrEmpty(type.Name))
|
||||
{
|
||||
trapFile.dynamic_member_name(this, type.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
cx.ModelError(Syntax, "Unable to get name for dynamic object creation.");
|
||||
}
|
||||
}
|
||||
|
||||
if (Syntax.Initializer != null)
|
||||
{
|
||||
switch (Syntax.Initializer.Kind())
|
||||
{
|
||||
case SyntaxKind.CollectionInitializerExpression:
|
||||
CollectionInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1) { Type = Type });
|
||||
break;
|
||||
case SyntaxKind.ObjectInitializerExpression:
|
||||
ObjectInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1) { Type = Type });
|
||||
break;
|
||||
default:
|
||||
cx.ModelError("Unhandled initializer in object creation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ExprKind GetKind(Context cx, BaseObjectCreationExpressionSyntax node)
|
||||
{
|
||||
var type = cx.GetModel(node).GetTypeInfo(node).Type;
|
||||
return Entities.Type.IsDelegate(type as INamedTypeSymbol)
|
||||
? ExprKind.EXPLICIT_DELEGATE_CREATION
|
||||
: ExprKind.OBJECT_CREATION;
|
||||
}
|
||||
|
||||
private static bool IsDynamicObjectCreation(Context cx, BaseObjectCreationExpressionSyntax node)
|
||||
{
|
||||
return node.ArgumentList != null &&
|
||||
node.ArgumentList.Arguments.Any(arg => IsDynamic(cx, arg.Expression));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
// new Foo(...) { ... }.
|
||||
internal class ExplicitObjectCreation : BaseObjectCreation<ObjectCreationExpressionSyntax>
|
||||
{
|
||||
private ExplicitObjectCreation(ExpressionNodeInfo info) : base(info) { }
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new ExplicitObjectCreation(info).TryPopulate();
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
base.PopulateExpression(trapFile);
|
||||
|
||||
TypeMention.Create(cx, Syntax.Type, this, Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
internal class ImplicitObjectCreation : BaseObjectCreation<ImplicitObjectCreationExpressionSyntax>
|
||||
{
|
||||
private ImplicitObjectCreation(ExpressionNodeInfo info) : base(info) { }
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new ImplicitObjectCreation(info).TryPopulate();
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
base.PopulateExpression(trapFile);
|
||||
|
||||
trapFile.implicitly_typed_object_creation(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,6 +301,11 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.WriteTuple("implicitly_typed_array_creation", array);
|
||||
}
|
||||
|
||||
internal static void implicitly_typed_object_creation(this TextWriter trapFile, Expression expression)
|
||||
{
|
||||
trapFile.WriteTuple("implicitly_typed_object_creation", expression);
|
||||
}
|
||||
|
||||
internal static void indexer_location(this TextWriter trapFile, Indexer indexer, Location location)
|
||||
{
|
||||
trapFile.WriteTuple("indexer_location", indexer, location);
|
||||
|
||||
@@ -205,6 +205,9 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr {
|
||||
*/
|
||||
ObjectOrCollectionInitializer getInitializer() { result = this.getChild(-1) }
|
||||
|
||||
/** Holds if the type of the created object is inferred. */
|
||||
predicate isImplicitlyTyped() { implicitly_typed_object_creation(this) }
|
||||
|
||||
override string toString() { result = "object creation of type " + this.getType().getName() }
|
||||
|
||||
override Expr getRawArgument(int i) {
|
||||
@@ -271,6 +274,9 @@ class DelegateCreation extends Expr, @delegate_creation_expr {
|
||||
*/
|
||||
class ExplicitDelegateCreation extends DelegateCreation, @explicit_delegate_creation_expr {
|
||||
override string getAPrimaryQlClass() { result = "ExplicitDelegateCreation" }
|
||||
|
||||
/** Holds if the type of the created delegate is inferred. */
|
||||
predicate isImplicitlyTyped() { implicitly_typed_object_creation(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1078,6 +1078,8 @@ case @expr.kind of
|
||||
|
||||
@throw_element = @throw_expr | @throw_stmt;
|
||||
|
||||
@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
|
||||
|
||||
implicitly_typed_array_creation(
|
||||
unique int id: @array_creation_expr ref);
|
||||
|
||||
@@ -1087,6 +1089,9 @@ explicitly_sized_array_creation(
|
||||
stackalloc_array_creation(
|
||||
unique int id: @array_creation_expr ref);
|
||||
|
||||
implicitly_typed_object_creation(
|
||||
unique int id: @implicitly_typeable_object_creation_expr ref);
|
||||
|
||||
mutator_invocation_mode(
|
||||
unique int id: @operator_invocation_expr ref,
|
||||
int mode: int ref /* prefix = 1, postfix = 2*/);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class AnonObj
|
||||
{
|
||||
private List<AnonObj> l = new();
|
||||
|
||||
public int Prop1 { get; set; }
|
||||
|
||||
public AnonObj M1(AnonObj t)
|
||||
{
|
||||
this.M1(new() { Prop1 = 1 });
|
||||
return new();
|
||||
}
|
||||
|
||||
delegate void D(int x);
|
||||
|
||||
void M2(int x) { }
|
||||
|
||||
D GetM() { return new(M2); }
|
||||
|
||||
void MethodAdd()
|
||||
{
|
||||
List<int> list = new();// { 1, 2, 3 }; todo: the initializer causes an extraction error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
implicitlyTypedObjectCreation
|
||||
| AnonymousObjectCreation.cs:7:31:7:35 | object creation of type List<AnonObj> |
|
||||
| AnonymousObjectCreation.cs:13:17:13:35 | object creation of type AnonObj |
|
||||
| AnonymousObjectCreation.cs:14:16:14:20 | object creation of type AnonObj |
|
||||
| AnonymousObjectCreation.cs:25:26:25:30 | object creation of type List<Int32> |
|
||||
implicitlyTypedDelegateCreation
|
||||
| AnonymousObjectCreation.cs:21:23:21:29 | delegate creation of type D |
|
||||
@@ -0,0 +1,9 @@
|
||||
import csharp
|
||||
|
||||
query predicate implicitlyTypedObjectCreation(ObjectCreation creation) {
|
||||
creation.isImplicitlyTyped()
|
||||
}
|
||||
|
||||
query predicate implicitlyTypedDelegateCreation(ExplicitDelegateCreation creation) {
|
||||
creation.isImplicitlyTyped()
|
||||
}
|
||||
@@ -1,3 +1,59 @@
|
||||
AnonymousObjectCreation.cs:
|
||||
# 5| [Class] AnonObj
|
||||
# 7| 5: [Field] l
|
||||
# 7| -1: [TypeMention] List<AnonObj>
|
||||
# 7| 1: [TypeMention] AnonObj
|
||||
# 7| 1: [AssignExpr] ... = ...
|
||||
# 7| 0: [FieldAccess] access to field l
|
||||
# 7| 1: [ObjectCreation] object creation of type List<AnonObj>
|
||||
# 9| 6: [Property] Prop1
|
||||
# 9| -1: [TypeMention] int
|
||||
# 9| 3: [Getter] get_Prop1
|
||||
# 9| 4: [Setter] set_Prop1
|
||||
#-----| 2: (Parameters)
|
||||
# 9| 0: [Parameter] value
|
||||
# 11| 7: [Method] M1
|
||||
# 11| -1: [TypeMention] AnonObj
|
||||
#-----| 2: (Parameters)
|
||||
# 11| 0: [Parameter] t
|
||||
# 11| -1: [TypeMention] AnonObj
|
||||
# 12| 4: [BlockStmt] {...}
|
||||
# 13| 0: [ExprStmt] ...;
|
||||
# 13| 0: [MethodCall] call to method M1
|
||||
# 13| -1: [ThisAccess] this access
|
||||
# 13| 0: [ObjectCreation] object creation of type AnonObj
|
||||
# 13| -1: [ObjectInitializer] { ..., ... }
|
||||
# 13| 0: [MemberInitializer] ... = ...
|
||||
# 13| 0: [PropertyCall] access to property Prop1
|
||||
# 13| 1: [IntLiteral] 1
|
||||
# 14| 1: [ReturnStmt] return ...;
|
||||
# 14| 0: [ObjectCreation] object creation of type AnonObj
|
||||
# 17| 8: [DelegateType] D
|
||||
#-----| 2: (Parameters)
|
||||
# 17| 0: [Parameter] x
|
||||
# 17| -1: [TypeMention] int
|
||||
# 19| 9: [Method] M2
|
||||
# 19| -1: [TypeMention] Void
|
||||
#-----| 2: (Parameters)
|
||||
# 19| 0: [Parameter] x
|
||||
# 19| -1: [TypeMention] int
|
||||
# 19| 4: [BlockStmt] {...}
|
||||
# 21| 10: [Method] GetM
|
||||
# 21| -1: [TypeMention] D
|
||||
# 21| 4: [BlockStmt] {...}
|
||||
# 21| 0: [ReturnStmt] return ...;
|
||||
# 21| 0: [ExplicitDelegateCreation] delegate creation of type D
|
||||
# 21| 0: [ImplicitDelegateCreation] delegate creation of type D
|
||||
# 21| 0: [MethodAccess] access to method M2
|
||||
# 23| 11: [Method] MethodAdd
|
||||
# 23| -1: [TypeMention] Void
|
||||
# 24| 4: [BlockStmt] {...}
|
||||
# 25| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 25| 0: [LocalVariableDeclAndInitExpr] List<Int32> list = ...
|
||||
# 25| -1: [TypeMention] List<Int32>
|
||||
# 25| 1: [TypeMention] int
|
||||
# 25| 0: [LocalVariableAccess] access to local variable list
|
||||
# 25| 1: [ObjectCreation] object creation of type List<Int32>
|
||||
Discard.cs:
|
||||
# 3| [Class] Discard
|
||||
# 5| 5: [Method] M1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
| AnonymousObjectCreation.cs:9:29:9:31 | set_Prop1 | set |
|
||||
| InitOnlyProperty.cs:12:42:12:45 | set_Prop0 | init |
|
||||
| InitOnlyProperty.cs:13:37:13:40 | set_Prop1 | init |
|
||||
| InitOnlyProperty.cs:14:37:14:39 | set_Prop2 | set |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Added 'implicitly_typed_object_creation' and 'implicitly_typeable_object_creation_expr'.
|
||||
compatibility: backwards
|
||||
Reference in New Issue
Block a user