mirror of
https://github.com/github/codeql.git
synced 2026-04-25 00:35:20 +02:00
Merge pull request #2462 from hvitved/csharp/localvars-refactor
C#: Handle tuple patterns in `is` expressions
This commit is contained in:
@@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
if (cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
|
||||
{
|
||||
var type = Type.Create(cx, symbol.GetAnnotatedType());
|
||||
return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, parent, child);
|
||||
return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), false, parent, child);
|
||||
}
|
||||
if (designation is DiscardDesignationSyntax)
|
||||
{
|
||||
@@ -48,7 +48,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
var type = Type.Create(cx, symbol.GetAnnotatedType());
|
||||
|
||||
return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), cx.Create(varDesignation.GetLocation()), false, parent, child);
|
||||
return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), true, parent, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -117,7 +117,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
var type = Entities.Type.Create(cx, symbol.GetAnnotatedType());
|
||||
|
||||
VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), cx.Create(designation.GetLocation()), false, this, 0);
|
||||
VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), false, this, 0);
|
||||
}
|
||||
|
||||
if (syntax.PositionalPatternClause is PositionalPatternClauseSyntax posPc)
|
||||
@@ -138,38 +138,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
}
|
||||
|
||||
private void PopulatePattern(PatternSyntax pattern, TypeSyntax optionalType, SyntaxToken varKeyword, VariableDesignationSyntax designation)
|
||||
{
|
||||
var isVar = optionalType is null;
|
||||
if (!(designation is null) && cx.GetModel(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
|
||||
{
|
||||
var type = Entities.Type.Create(cx, symbol.GetAnnotatedType());
|
||||
VariableDeclaration.Create(cx, symbol, type, optionalType, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 1);
|
||||
}
|
||||
else if (!isVar)
|
||||
Expressions.TypeAccess.Create(cx, optionalType, this, 1);
|
||||
}
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
Create(cx, Syntax.Expression, this, 0);
|
||||
switch (Syntax.Pattern)
|
||||
{
|
||||
case ConstantPatternSyntax constantPattern:
|
||||
Create(cx, constantPattern.Expression, this, 1);
|
||||
return;
|
||||
case VarPatternSyntax varPattern:
|
||||
PopulatePattern(varPattern, null, varPattern.VarKeyword, varPattern.Designation);
|
||||
return;
|
||||
case DeclarationPatternSyntax declPattern:
|
||||
PopulatePattern(declPattern, declPattern.Type, default(SyntaxToken), declPattern.Designation);
|
||||
return;
|
||||
case RecursivePatternSyntax recPattern:
|
||||
new RecursivePattern(cx, recPattern, this, 1);
|
||||
return;
|
||||
default:
|
||||
throw new InternalError(Syntax, "Is pattern not handled");
|
||||
}
|
||||
cx.CreatePattern(Syntax.Pattern, this, 1);
|
||||
}
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new IsPattern(info).TryPopulate();
|
||||
|
||||
@@ -54,10 +54,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
case SymbolKind.Local:
|
||||
case SymbolKind.RangeVariable:
|
||||
return Access.Create(info, target, false, LocalVariable.GetAlreadyCreated(info.Context, target));
|
||||
return Access.Create(info, target, false, LocalVariable.Create(info.Context, target));
|
||||
|
||||
case SymbolKind.Parameter:
|
||||
return Access.Create(info, target, false, Parameter.GetAlreadyCreated(info.Context, (IParameterSymbol)target));
|
||||
return Access.Create(info, target, false, Parameter.Create(info.Context, (IParameterSymbol)target));
|
||||
|
||||
case SymbolKind.Namespace:
|
||||
return Access.Create(info, target, false, Namespace.Create(info.Context, (INamespaceSymbol)target));
|
||||
|
||||
@@ -65,7 +65,6 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
protected Expression DeclareRangeVariable(Context cx, IExpressionParentEntity parent, int child, bool getElement, ISymbol variableSymbol, SyntaxToken name)
|
||||
{
|
||||
var type = Type.Create(cx, cx.GetType(Expr));
|
||||
Extraction.Entities.Location nameLoc;
|
||||
|
||||
AnnotatedType declType;
|
||||
TypeSyntax declTypeSyntax = null;
|
||||
@@ -90,7 +89,6 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
declType,
|
||||
declTypeSyntax,
|
||||
cx.Create(node.GetLocation()),
|
||||
nameLoc = cx.Create(name.GetLocation()),
|
||||
true,
|
||||
parent,
|
||||
child
|
||||
@@ -98,8 +96,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
Expression.Create(cx, Expr, decl, 0);
|
||||
|
||||
var nameLoc = cx.Create(name.GetLocation());
|
||||
var access = new Expression(new ExpressionInfo(cx, type, nameLoc, ExprKind.LOCAL_VARIABLE_ACCESS, decl, 1, false, null));
|
||||
cx.TrapWriter.Writer.expr_access(access, LocalVariable.GetAlreadyCreated(cx, variableSymbol));
|
||||
cx.TrapWriter.Writer.expr_access(access, LocalVariable.Create(cx, variableSymbol));
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
@@ -11,12 +11,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
VariableDeclaration(IExpressionInfo info) : base(info) { }
|
||||
|
||||
public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedType type, TypeSyntax optionalSyntax, Extraction.Entities.Location exprLocation, Extraction.Entities.Location declLocation, bool isVar, IExpressionParentEntity parent, int child)
|
||||
public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedType type, TypeSyntax optionalSyntax, Extraction.Entities.Location exprLocation, bool isVar, IExpressionParentEntity parent, int child)
|
||||
{
|
||||
var ret = new VariableDeclaration(new ExpressionInfo(cx, type, exprLocation, ExprKind.LOCAL_VAR_DECL, parent, child, false, null));
|
||||
cx.Try(null, null, () =>
|
||||
{
|
||||
LocalVariable.Create(cx, symbol, ret, isVar, declLocation);
|
||||
var l = LocalVariable.Create(cx, symbol);
|
||||
l.PopulateManual(ret, isVar);
|
||||
if (optionalSyntax != null)
|
||||
TypeMention.Create(cx, optionalSyntax, parent, type);
|
||||
});
|
||||
@@ -25,20 +26,20 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
static VariableDeclaration CreateSingle(Context cx, DeclarationExpressionSyntax node, SingleVariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
|
||||
{
|
||||
bool isVar = node.Type.IsVar;
|
||||
|
||||
var variableSymbol = cx.GetModel(designation).GetDeclaredSymbol(designation) as ILocalSymbol;
|
||||
if (variableSymbol == null)
|
||||
{
|
||||
cx.ModelError(node, "Failed to determine local variable");
|
||||
return Create(cx, node, NullType.Create(cx), isVar, parent, child);
|
||||
return Create(cx, node, NullType.Create(cx), parent, child);
|
||||
}
|
||||
|
||||
var type = Entities.Type.Create(cx, variableSymbol.GetAnnotatedType());
|
||||
var location = cx.Create(designation.GetLocation());
|
||||
|
||||
var ret = Create(cx, designation, type, isVar, parent, child);
|
||||
cx.Try(null, null, () => LocalVariable.Create(cx, variableSymbol, ret, isVar, location));
|
||||
var ret = Create(cx, designation, type, parent, child);
|
||||
cx.Try(null, null, () =>
|
||||
{
|
||||
var l = LocalVariable.Create(cx, variableSymbol);
|
||||
l.PopulateManual(ret, node.Type.IsVar);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -78,10 +79,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
case SingleVariableDesignationSyntax single:
|
||||
if (cx.GetModel(variable).GetDeclaredSymbol(single) is ILocalSymbol local)
|
||||
{
|
||||
var decl = Create(cx, variable, Entities.Type.Create(cx, local.GetAnnotatedType()), true, tuple, child0++);
|
||||
var id = single.Identifier;
|
||||
var location = cx.Create(id.GetLocation());
|
||||
LocalVariable.Create(cx, local, decl, true, location);
|
||||
var decl = Create(cx, variable, Entities.Type.Create(cx, local.GetAnnotatedType()), tuple, child0++);
|
||||
var l = LocalVariable.Create(cx, local);
|
||||
l.PopulateManual(decl, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -111,30 +111,29 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
case DiscardDesignationSyntax discard:
|
||||
var ti = cx.GetType(discard);
|
||||
var type = Entities.Type.Create(cx, ti);
|
||||
return Create(cx, node, type, node.Type.IsVar, parent, child);
|
||||
return Create(cx, node, type, parent, child);
|
||||
default:
|
||||
cx.ModelError(node, "Failed to determine designation type");
|
||||
return Create(cx, node, Entities.NullType.Create(cx), node.Type.IsVar, parent, child);
|
||||
return Create(cx, node, NullType.Create(cx), parent, child);
|
||||
}
|
||||
}
|
||||
|
||||
public static Expression Create(Context cx, DeclarationExpressionSyntax node, IExpressionParentEntity parent, int child) =>
|
||||
Create(cx, node, node.Designation, parent, child);
|
||||
|
||||
public static VariableDeclaration Create(Context cx, CSharpSyntaxNode c, AnnotatedType type, bool isVar, IExpressionParentEntity parent, int child) =>
|
||||
public static VariableDeclaration Create(Context cx, CSharpSyntaxNode c, AnnotatedType type, IExpressionParentEntity parent, int child) =>
|
||||
new VariableDeclaration(new ExpressionInfo(cx, type, cx.Create(c.FixedLocation()), ExprKind.LOCAL_VAR_DECL, parent, child, false, null));
|
||||
|
||||
public static VariableDeclaration Create(Context cx, CatchDeclarationSyntax d, bool isVar, IExpressionParentEntity parent, int child)
|
||||
{
|
||||
var symbol = cx.GetModel(d).GetDeclaredSymbol(d);
|
||||
var type = Entities.Type.Create(cx, symbol.GetAnnotatedType());
|
||||
var ret = Create(cx, d, type, isVar, parent, child);
|
||||
var ret = Create(cx, d, type, parent, child);
|
||||
cx.Try(d, null, () =>
|
||||
{
|
||||
var id = d.Identifier;
|
||||
var declSymbol = cx.GetModel(d).GetDeclaredSymbol(d);
|
||||
var location = cx.Create(id.GetLocation());
|
||||
LocalVariable.Create(cx, declSymbol, ret, isVar, location);
|
||||
var l = LocalVariable.Create(cx, declSymbol);
|
||||
l.PopulateManual(ret, isVar);
|
||||
TypeMention.Create(cx, d.Type, ret, type);
|
||||
});
|
||||
return ret;
|
||||
@@ -142,20 +141,19 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
public static VariableDeclaration CreateDeclarator(Context cx, VariableDeclaratorSyntax d, AnnotatedType type, bool isVar, IExpressionParentEntity parent, int child)
|
||||
{
|
||||
var ret = Create(cx, d, type, isVar, parent, child);
|
||||
var ret = Create(cx, d, type, parent, child);
|
||||
cx.Try(d, null, () =>
|
||||
{
|
||||
var id = d.Identifier;
|
||||
var declSymbol = cx.GetModel(d).GetDeclaredSymbol(d);
|
||||
var location = cx.Create(id.GetLocation());
|
||||
var localVar = LocalVariable.Create(cx, declSymbol, ret, isVar, location);
|
||||
var localVar = LocalVariable.Create(cx, declSymbol);
|
||||
localVar.PopulateManual(ret, isVar);
|
||||
|
||||
if (d.Initializer != null)
|
||||
{
|
||||
Create(cx, d.Initializer.Value, ret, 0);
|
||||
|
||||
// Create an access
|
||||
var access = new Expression(new ExpressionInfo(cx, type, location, ExprKind.LOCAL_VARIABLE_ACCESS, ret, 1, false, null));
|
||||
var access = new Expression(new ExpressionInfo(cx, type, localVar.Location, ExprKind.LOCAL_VARIABLE_ACCESS, ret, 1, false, null));
|
||||
cx.TrapWriter.Writer.expr_access(access, localVar);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
class LocalVariable : CachedSymbol<ISymbol>
|
||||
{
|
||||
LocalVariable(Context cx, ISymbol init, Expression parent, bool isVar, Extraction.Entities.Location declLocation)
|
||||
: base(cx, init)
|
||||
{
|
||||
Parent = parent;
|
||||
IsVar = isVar;
|
||||
DeclLocation = declLocation;
|
||||
}
|
||||
|
||||
readonly Expression Parent;
|
||||
readonly bool IsVar;
|
||||
readonly Extraction.Entities.Location DeclLocation;
|
||||
LocalVariable(Context cx, ISymbol init) : base(cx, init) { }
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(Parent);
|
||||
trapFile.WriteSubId(Location);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(symbol.Name);
|
||||
trapFile.Write(";localvar");
|
||||
}
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
public override void Populate(TextWriter trapFile) { }
|
||||
|
||||
public void PopulateManual(Expression parent, bool isVar)
|
||||
{
|
||||
var trapFile = Context.TrapWriter.Writer;
|
||||
var (kind, type) =
|
||||
symbol is ILocalSymbol l ?
|
||||
(l.IsRef ? 3 : l.IsConst ? 2 : 1, Type.Create(Context, l.GetAnnotatedType())) :
|
||||
(1, parent.Type);
|
||||
trapFile.localvars(this, kind, symbol.Name, isVar ? 1 : 0, type.Type.TypeRef, parent);
|
||||
|
||||
if (symbol is ILocalSymbol local)
|
||||
{
|
||||
PopulateNullability(trapFile, local.GetAnnotatedType());
|
||||
@@ -36,55 +33,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
|
||||
}
|
||||
|
||||
trapFile.localvars(
|
||||
this,
|
||||
IsRef ? 3 : IsConst ? 2 : 1,
|
||||
symbol.Name,
|
||||
IsVar ? 1 : 0,
|
||||
Type.Type.TypeRef,
|
||||
Parent);
|
||||
|
||||
trapFile.localvar_location(this, DeclLocation);
|
||||
trapFile.localvar_location(this, Location);
|
||||
|
||||
DefineConstantValue(trapFile);
|
||||
}
|
||||
|
||||
public static LocalVariable Create(Context cx, ISymbol local, Expression parent, bool isVar, Extraction.Entities.Location declLocation)
|
||||
public static LocalVariable Create(Context cx, ISymbol local)
|
||||
{
|
||||
return LocalVariableFactory.Instance.CreateEntity(cx, local, parent, isVar, declLocation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local variable entity for <paramref name="local"/> which must
|
||||
/// already have been created.
|
||||
/// </summary>
|
||||
public static LocalVariable GetAlreadyCreated(Context cx, ISymbol local) => LocalVariableFactory.Instance.CreateEntity(cx, local, null, false, null);
|
||||
|
||||
bool IsConst
|
||||
{
|
||||
get
|
||||
{
|
||||
var local = symbol as ILocalSymbol;
|
||||
return local != null && local.IsConst;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsRef
|
||||
{
|
||||
get
|
||||
{
|
||||
var local = symbol as ILocalSymbol;
|
||||
return local != null && local.IsRef;
|
||||
}
|
||||
}
|
||||
|
||||
AnnotatedType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
var local = symbol as ILocalSymbol;
|
||||
return local == null ? Parent.Type : Entities.Type.Create(Context, local.GetAnnotatedType());
|
||||
}
|
||||
return LocalVariableFactory.Instance.CreateEntity(cx, local);
|
||||
}
|
||||
|
||||
void DefineConstantValue(TextWriter trapFile)
|
||||
@@ -96,12 +52,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
class LocalVariableFactory : ICachedEntityFactory<(ISymbol, Expression, bool, Extraction.Entities.Location), LocalVariable>
|
||||
class LocalVariableFactory : ICachedEntityFactory<ISymbol, LocalVariable>
|
||||
{
|
||||
public static readonly LocalVariableFactory Instance = new LocalVariableFactory();
|
||||
|
||||
public LocalVariable Create(Context cx, (ISymbol, Expression, bool, Extraction.Entities.Location) init) =>
|
||||
new LocalVariable(cx, init.Item1, init.Item2, init.Item3, init.Item4);
|
||||
public LocalVariable Create(Context cx, ISymbol init) => new LocalVariable(cx, init);
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Extraction.CSharp.Populators;
|
||||
using System.Linq;
|
||||
@@ -69,11 +68,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) =>
|
||||
ParameterFactory.Instance.CreateEntity(cx, param, parent, original);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter entity for <paramref name="param"/> which must
|
||||
/// already have been created.
|
||||
/// </summary>
|
||||
public static Parameter GetAlreadyCreated(Context cx, IParameterSymbol param) =>
|
||||
public static Parameter Create(Context cx, IParameterSymbol param) =>
|
||||
ParameterFactory.Instance.CreateEntity(cx, param, null, null);
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
|
||||
if (cx.GetModel(pattern).GetDeclaredSymbol(designation) is ILocalSymbol symbol)
|
||||
{
|
||||
var type = Type.Create(cx, symbol.GetAnnotatedType());
|
||||
Expressions.VariableDeclaration.Create(cx, symbol, type, optionalType, cx.Create(pattern.GetLocation()), cx.Create(designation.GetLocation()), isVar, this, 0);
|
||||
Expressions.VariableDeclaration.Create(cx, symbol, type, optionalType, cx.Create(pattern.GetLocation()), isVar, this, 0);
|
||||
}
|
||||
break;
|
||||
case DiscardDesignationSyntax discard:
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
|
||||
|
||||
var location = cx.Create(Stmt.Identifier.GetLocation());
|
||||
|
||||
Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, location, Stmt.Type.IsVar, this, 0);
|
||||
Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, Stmt.Type.IsVar, this, 0);
|
||||
|
||||
Statement.Create(cx, Stmt.Statement, this, 2);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
|
||||
public override IEntity VisitNamespace(INamespaceSymbol ns) => Namespace.Create(cx, ns);
|
||||
|
||||
public override IEntity VisitParameter(IParameterSymbol param) => Parameter.GetAlreadyCreated(cx, param);
|
||||
public override IEntity VisitParameter(IParameterSymbol param) => Parameter.Create(cx, param);
|
||||
|
||||
public override IEntity VisitProperty(IPropertySymbol symbol) => Property.Create(cx, symbol);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
// semmle-extractor-options: /langversion:8.0
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
@@ -180,4 +180,13 @@ class UsingDiscard
|
||||
}
|
||||
}
|
||||
|
||||
class TupleMatching
|
||||
{
|
||||
(int, object) G(object o1, object o2)
|
||||
{
|
||||
(object, object)? pair = (o1, o2);
|
||||
return (0, pair is var (x, y) ? x : null);
|
||||
}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: /r:System.Dynamic.Runtime.dll
|
||||
|
||||
@@ -82,3 +82,12 @@
|
||||
| Program.cs:169:5:169:10 | String |
|
||||
| Program.cs:174:5:174:8 | Void |
|
||||
| Program.cs:176:17:176:19 | IDisposable |
|
||||
| Program.cs:185:5:185:17 | (Int32,Object) |
|
||||
| Program.cs:185:6:185:8 | Int32 |
|
||||
| Program.cs:185:11:185:16 | Object |
|
||||
| Program.cs:185:21:185:26 | Object |
|
||||
| Program.cs:185:32:185:37 | Object |
|
||||
| Program.cs:187:9:187:24 | (Object,Object) |
|
||||
| Program.cs:187:9:187:25 | Nullable<(Object,Object)> |
|
||||
| Program.cs:187:10:187:15 | Object |
|
||||
| Program.cs:187:18:187:23 | Object |
|
||||
|
||||
Reference in New Issue
Block a user