Skip to content

Commit c642e72

Browse files
authored
Merge pull request #1555 from calumgrant/cs/typemention-fixes
C#: Fix various extraction errors
2 parents f202511 + 4dd4167 commit c642e72

File tree

29 files changed

+3926
-64
lines changed

29 files changed

+3926
-64
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Improvements to C# analysis
2+
3+
The following changes in version 1.23 affect C# analysis in all applications.
4+
5+
## Changes to existing queries
6+
7+
| **Query** | **Expected impact** | **Change** |
8+
|------------------------------|------------------------|-----------------------------------|
9+
10+
## Removal of old queries
11+
12+
## Changes to code extraction
13+
14+
* `nameof` expressions are now extracted correctly when the name is a namespace.
15+
16+
## Changes to QL libraries
17+
18+
* The new class `NamespaceAccess` models accesses to namespaces, for example in `nameof` expressions.
19+
20+
## Changes to autobuilder
21+

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ static ExprKind AccessKind(Context cx, ISymbol symbol)
3333
case SymbolKind.Parameter:
3434
return ExprKind.PARAMETER_ACCESS;
3535

36+
case SymbolKind.Namespace:
37+
return ExprKind.NAMESPACE_ACCESS;
38+
3639
default:
3740
cx.ModelError(symbol, $"Unhandled access kind '{symbol.Kind}'");
3841
return ExprKind.UNKNOWN;

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ public static Expression Create(ExpressionNodeInfo info)
5959
case SymbolKind.Parameter:
6060
return Access.Create(info, target, false, Parameter.GetAlreadyCreated(info.Context, (IParameterSymbol)target));
6161

62+
case SymbolKind.Namespace:
63+
return Access.Create(info, target, false, Namespace.Create(info.Context, (INamespaceSymbol)target));
64+
6265
default:
6366
throw new InternalError(info.Node, $"Unhandled identifier kind '{target.Kind}'");
6467
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@ protected override void Populate()
2626

2727
var location = cx.Create(Stmt.Identifier.GetLocation());
2828

29-
if (typeSymbol.Name != "_")
30-
Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, location, Stmt.Type.IsVar, this, 0);
31-
else
32-
TypeMention.Create(cx, Stmt.Type, this, type);
29+
Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, location, Stmt.Type.IsVar, this, 0);
3330

3431
Statement.Create(cx, Stmt.Statement, this, 2);
3532
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,39 @@ class TypeMention : FreshEntity
2222
Loc = loc;
2323
}
2424

25+
static TypeSyntax GetElementType(TypeSyntax type)
26+
{
27+
switch (type)
28+
{
29+
case ArrayTypeSyntax ats:
30+
return GetElementType(ats.ElementType);
31+
case NullableTypeSyntax nts:
32+
return GetElementType(nts.ElementType);
33+
default:
34+
return type;
35+
}
36+
}
37+
38+
static Type GetElementType(Type type)
39+
{
40+
switch (type)
41+
{
42+
case ArrayType at:
43+
return GetElementType(at.ElementType.Type);
44+
case NamedType nt when nt.symbol.IsBoundNullable():
45+
return nt.TypeArguments.Single();
46+
default:
47+
return type;
48+
}
49+
}
50+
2551
void Populate()
2652
{
2753
switch (Syntax.Kind())
2854
{
2955
case SyntaxKind.ArrayType:
30-
var ats = (ArrayTypeSyntax)Syntax;
31-
var at = (ArrayType)Type;
3256
Emit(Loc ?? Syntax.GetLocation(), Parent, Type);
33-
Create(cx, ats.ElementType, this, at.ElementType);
57+
Create(cx, GetElementType(Syntax), this, GetElementType(Type));
3458
return;
3559
case SyntaxKind.NullableType:
3660
var nts = (NullableTypeSyntax)Syntax;

csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public enum ExprKind
114114
POSITIONAL_PATTERN = 117,
115115
SWITCH_CASE = 118,
116116
ASSIGN_COALESCE = 119,
117-
SUPPRESS_NULLABLE_WARNING = 120
117+
SUPPRESS_NULLABLE_WARNING = 120,
118+
NAMESPACE_ACCESS = 121
118119
}
119120
}

csharp/ql/src/semmle/code/csharp/Namespace.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class TypeContainer extends DotNet::NamedElement, Element, @type_container { }
1818
* }
1919
* ```
2020
*/
21-
class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
21+
class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespace {
2222
/** Gets the simple name of this namespace, for example `IO` in `System.IO`. */
2323
override string getName() { namespaces(this, result) }
2424

@@ -117,6 +117,10 @@ class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
117117
NamespaceDeclaration getADeclaration() { result.getNamespace() = this }
118118

119119
override Location getALocation() { result = this.getADeclaration().getALocation() }
120+
121+
override string toString() { result = DotNet::Namespace.super.toString() }
122+
123+
override predicate hasQualifiedName(string a, string b) { DotNet::Namespace.super.hasQualifiedName(a, b) }
120124
}
121125

122126
/**

csharp/ql/src/semmle/code/csharp/exprs/Access.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,3 +826,12 @@ class ArrayRead extends ArrayAccess, AssignableRead { }
826826
* ```
827827
*/
828828
class ArrayWrite extends ArrayAccess, AssignableWrite { }
829+
830+
/**
831+
* An access to a namespace, for example `System` in `nameof(System)`.
832+
*/
833+
class NamespaceAccess extends Access, @namespace_access_expr {
834+
override Namespace getTarget() { expr_access(this, result) }
835+
836+
override string toString() { result = "access to namespace " + this.getTarget().getName() }
837+
}

csharp/ql/src/semmle/code/dotnet/Namespace.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
* Provides the `Namespace` class to represent .Net namespaces.
33
*/
44

5-
private import Element
5+
private import Declaration
66

77
/** A namespace. */
8-
class Namespace extends NamedElement, @namespace {
8+
class Namespace extends Declaration, @namespace {
99
/**
1010
* Gets the parent namespace, if any. For example the parent namespace of `System.IO`
1111
* is `System`. The parent namespace of `System` is the global namespace.

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ tokens(
214214
| @using_directive | @type_parameter_constraints | @external_element
215215
| @xmllocatable | @asp_element | @namespace;
216216

217-
@declaration = @callable | @generic | @assignable;
217+
@declaration = @callable | @generic | @assignable | @namespace;
218218

219219
@named_element = @namespace | @declaration;
220220

@@ -982,6 +982,7 @@ case @expr.kind of
982982
| 118 = @switch_case_expr
983983
| 119 = @assign_coalesce_expr
984984
| 120 = @suppress_nullable_warning_expr
985+
| 121 = @namespace_access_expr
985986
;
986987

987988
@switch = @switch_stmt | @switch_expr;
@@ -1004,7 +1005,7 @@ case @expr.kind of
10041005

10051006
@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
10061007
| @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
1007-
@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr;
1008+
@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
10081009
@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
10091010

10101011
@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
@@ -1084,7 +1085,7 @@ expr_access(
10841085
unique int accesser_id: @access_expr ref,
10851086
int target_id: @accessible ref);
10861087

1087-
@accessible = @method | @assignable | @local_function;
1088+
@accessible = @method | @assignable | @local_function | @namespace;
10881089

10891090
expr_location(
10901091
unique int id: @expr ref,

0 commit comments

Comments
 (0)