mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
C#: Address more review comments
This commit is contained in:
@@ -5,37 +5,16 @@ using System.Reflection;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a "Key" object to allow modifiers to exist as entities in the extractor
|
||||
/// hash map. (Raw strings would work as keys but might clash with other types).
|
||||
/// </summary>
|
||||
class ModifierKey : Object
|
||||
class Modifier : Extraction.CachedEntity<string>
|
||||
{
|
||||
public readonly string name;
|
||||
|
||||
public ModifierKey(string m)
|
||||
{
|
||||
name = m;
|
||||
}
|
||||
|
||||
public override bool Equals(Object obj)
|
||||
{
|
||||
return obj.GetType() == GetType() && name == ((ModifierKey)obj).name;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 13 * name.GetHashCode();
|
||||
}
|
||||
|
||||
class Modifier : Extraction.CachedEntity<ModifierKey>
|
||||
{
|
||||
Modifier(Context cx, ModifierKey init)
|
||||
Modifier(Context cx, string init)
|
||||
: base(cx, init) { }
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(symbol.name);
|
||||
trapFile.Write(symbol);
|
||||
trapFile.Write(";modifier");
|
||||
}
|
||||
|
||||
@@ -43,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
trapFile.modifiers(Label, symbol.name);
|
||||
trapFile.modifiers(Label, symbol);
|
||||
}
|
||||
|
||||
public static string AccessbilityModifier(Accessibility access)
|
||||
@@ -154,21 +133,20 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public static Modifier Create(Context cx, string modifier)
|
||||
{
|
||||
var modifierKey = new ModifierKey(modifier);
|
||||
return ModifierFactory.Instance.CreateEntity(cx, modifierKey, modifierKey);
|
||||
return ModifierFactory.Instance.CreateEntity(cx, (typeof(Modifier), modifier), modifier);
|
||||
}
|
||||
|
||||
public static Modifier Create(Context cx, Accessibility access)
|
||||
{
|
||||
var modifierKey = new ModifierKey(AccessbilityModifier(access));
|
||||
return ModifierFactory.Instance.CreateEntity(cx, modifierKey, modifierKey);
|
||||
var modifier = AccessbilityModifier(access);
|
||||
return ModifierFactory.Instance.CreateEntity(cx, (typeof(Modifier), modifier), modifier);
|
||||
}
|
||||
|
||||
class ModifierFactory : ICachedEntityFactory<ModifierKey, Modifier>
|
||||
class ModifierFactory : ICachedEntityFactory<string, Modifier>
|
||||
{
|
||||
public static readonly ModifierFactory Instance = new ModifierFactory();
|
||||
|
||||
public Modifier Create(Context cx, ModifierKey init) => new Modifier(cx, init);
|
||||
public Modifier Create(Context cx, string init) => new Modifier(cx, init);
|
||||
}
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
|
||||
}
|
||||
|
||||
@@ -202,8 +202,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
return obj != null && obj.GetType() == typeof(VarargsType);
|
||||
}
|
||||
|
||||
static readonly object cacheKey = new object();
|
||||
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, cacheKey, null);
|
||||
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, typeof(VarargsType), null);
|
||||
|
||||
class VarargsTypeFactory : ICachedEntityFactory<string, VarargsType>
|
||||
{
|
||||
@@ -238,8 +237,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
return obj != null && obj.GetType() == typeof(VarargsParam);
|
||||
}
|
||||
|
||||
static readonly object cacheKey = new object();
|
||||
public static VarargsParam Create(Context cx, Method method) => VarargsParamFactory.Instance.CreateEntity(cx, cacheKey, method);
|
||||
public static VarargsParam Create(Context cx, Method method) => VarargsParamFactory.Instance.CreateEntity(cx, typeof(VarargsParam), method);
|
||||
|
||||
class VarargsParamFactory : ICachedEntityFactory<Method, VarargsParam>
|
||||
{
|
||||
@@ -266,27 +264,8 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.param_location(this, Original.Location);
|
||||
}
|
||||
|
||||
sealed class ConstructedExtensionParameterCacheKey
|
||||
{
|
||||
public readonly IParameterSymbol Parameter;
|
||||
public readonly ITypeSymbol ConstructedType;
|
||||
public ConstructedExtensionParameterCacheKey(IParameterSymbol parameter, ITypeSymbol constructedType)
|
||||
{
|
||||
Parameter = parameter;
|
||||
ConstructedType = constructedType;
|
||||
}
|
||||
|
||||
public override int GetHashCode() =>
|
||||
(Parameter, ConstructedType).GetHashCode();
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
obj is ConstructedExtensionParameterCacheKey k &&
|
||||
SymbolEqualityComparer.Default.Equals(k.Parameter, Parameter) &&
|
||||
SymbolEqualityComparer.Default.Equals(k.ConstructedType, ConstructedType);
|
||||
}
|
||||
|
||||
public static ConstructedExtensionParameter Create(Context cx, Method method, Parameter parameter) =>
|
||||
ExtensionParamFactory.Instance.CreateEntity(cx, new ConstructedExtensionParameterCacheKey(parameter.symbol, method.symbol.ReceiverType), (method, parameter));
|
||||
ExtensionParamFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(parameter.symbol), new SymbolEqualityWrapper(method.symbol.ReceiverType)), (method, parameter));
|
||||
|
||||
class ExtensionParamFactory : ICachedEntityFactory<(Method, Parameter), ConstructedExtensionParameter>
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.CSharp.Entities.Expressions;
|
||||
@@ -11,9 +12,13 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
class Property : CachedSymbol<IPropertySymbol>, IExpressionParentEntity
|
||||
{
|
||||
protected Property(Context cx, IPropertySymbol init)
|
||||
: base(cx, init) { }
|
||||
: base(cx, init)
|
||||
{
|
||||
type = new Lazy<Type>(() => Type.Create(Context, symbol.Type));
|
||||
}
|
||||
|
||||
Type Type => Type.Create(Context, symbol.Type);
|
||||
readonly Lazy<Type> type;
|
||||
Type Type => type.Value;
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
|
||||
@@ -107,10 +107,25 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => GetLocations(symbol).FirstOrDefault();
|
||||
|
||||
bool IsAnonymousType() => symbol.IsAnonymousType || symbol.Name.Contains("__AnonymousType");
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
symbol.BuildTypeId(Context, trapFile, symbol);
|
||||
trapFile.Write(";type");
|
||||
if (IsAnonymousType())
|
||||
trapFile.Write('*');
|
||||
else
|
||||
{
|
||||
symbol.BuildTypeId(Context, trapFile, symbol);
|
||||
trapFile.Write(";type");
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
if (IsAnonymousType())
|
||||
trapFile.Write('*');
|
||||
else
|
||||
base.WriteQuotedId(trapFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,22 +182,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
referencedType = Type.Create(cx, symbol);
|
||||
}
|
||||
|
||||
sealed class NamedTypeRefCacheKey
|
||||
{
|
||||
public readonly INamedTypeSymbol Symbol;
|
||||
public NamedTypeRefCacheKey(INamedTypeSymbol symbol) => Symbol = symbol;
|
||||
|
||||
public override int GetHashCode() =>
|
||||
11 * Symbol.GetHashCode();
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
obj is NamedTypeRefCacheKey k && SymbolEqualityComparer.IncludeNullability.Equals(k.Symbol, Symbol);
|
||||
}
|
||||
|
||||
public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) =>
|
||||
// We need to use a different cache key than `type` to avoid mixing up
|
||||
// `NamedType`s and `NamedTypeRef`s
|
||||
NamedTypeRefFactory.Instance.CreateEntity(cx, new NamedTypeRefCacheKey(type), type);
|
||||
NamedTypeRefFactory.Instance.CreateEntity(cx, (typeof(NamedTypeRef), new SymbolEqualityWrapper(type)), type);
|
||||
|
||||
class NamedTypeRefFactory : ICachedEntityFactory<INamedTypeSymbol, NamedTypeRef>
|
||||
{
|
||||
|
||||
@@ -27,8 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
return obj != null && obj.GetType() == typeof(NullType);
|
||||
}
|
||||
|
||||
static readonly object cacheKey = new object();
|
||||
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, cacheKey, null), NullableAnnotation.None);
|
||||
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, typeof(NullType), null), NullableAnnotation.None);
|
||||
|
||||
class NullTypeFactory : ICachedEntityFactory<ITypeSymbol, NullType>
|
||||
{
|
||||
|
||||
@@ -292,22 +292,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
DelegateTypeParameter(Context cx, IParameterSymbol init, IEntity parent, Parameter original)
|
||||
: base(cx, init, parent, original) { }
|
||||
|
||||
sealed class DelegateTypeParameterCacheKey
|
||||
{
|
||||
public readonly IParameterSymbol Symbol;
|
||||
public DelegateTypeParameterCacheKey(IParameterSymbol symbol) => Symbol = symbol;
|
||||
|
||||
public override int GetHashCode() =>
|
||||
13 * Symbol.GetHashCode();
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
obj is DelegateTypeParameterCacheKey k && SymbolEqualityComparer.IncludeNullability.Equals(k.Symbol, Symbol);
|
||||
}
|
||||
|
||||
new public static DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) =>
|
||||
// We need to use a different cache key than `param` to avoid mixing up
|
||||
// `DelegateTypeParameter`s and `Parameter`s
|
||||
DelegateTypeParameterFactory.Instance.CreateEntity(cx, new DelegateTypeParameterCacheKey(param), (param, parent, original));
|
||||
DelegateTypeParameterFactory.Instance.CreateEntity(cx, (typeof(DelegateTypeParameter), new SymbolEqualityWrapper(param)), (param, parent, original));
|
||||
|
||||
class DelegateTypeParameterFactory : ICachedEntityFactory<(IParameterSymbol, IEntity, Parameter), DelegateTypeParameter>
|
||||
{
|
||||
|
||||
@@ -212,7 +212,7 @@ namespace Semmle.Extraction.CSharp
|
||||
// #123 = @"C`1 : IEnumerable<__self___T>"
|
||||
// ```
|
||||
if (SymbolEqualityComparer.Default.Equals(symbol, symbolBeingDefined))
|
||||
trapFile.Write($"__self__");
|
||||
trapFile.Write("__self__");
|
||||
else if (symbol is ITypeSymbol type && type.IdDependsOn(cx, symbolBeingDefined))
|
||||
type.BuildTypeId(cx, trapFile, symbolBeingDefined, addBaseClass);
|
||||
else
|
||||
@@ -294,12 +294,7 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
}
|
||||
|
||||
if (named.IsAnonymousType)
|
||||
{
|
||||
AddContaining();
|
||||
named.BuildAnonymousName(cx, trapFile, (s0, cx0, trapFile0) => BuildOrWriteId(s0, cx0, trapFile0, symbolBeingDefined, addBaseClass), true);
|
||||
}
|
||||
else if (named.TypeParameters.IsEmpty)
|
||||
if (named.TypeParameters.IsEmpty)
|
||||
{
|
||||
AddContaining();
|
||||
trapFile.Write(named.Name);
|
||||
@@ -310,20 +305,6 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.Write(named.Name);
|
||||
trapFile.Write("`");
|
||||
trapFile.Write(named.TypeParameters.Length);
|
||||
// Some types such as `<>f__AnonymousType0` are not considered anonymous types by Roslyn,
|
||||
// perhaps because they contain type parameters. We still need to treat them like anonymous
|
||||
// types, though, by adding the underlying properties, in order to disambiguate them
|
||||
if (named.Name.Contains("__AnonymousType"))
|
||||
{
|
||||
trapFile.Write('<');
|
||||
trapFile.BuildList(",", named.GetMembers().OfType<IPropertySymbol>(), (prop, tb0) =>
|
||||
{
|
||||
tb0.Write(prop.Name);
|
||||
tb0.Write(" ");
|
||||
prop.Type.BuildOrWriteId(cx, tb0, symbolBeingDefined, addBaseClass);
|
||||
});
|
||||
trapFile.Write('>');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -364,22 +345,14 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.Write('.');
|
||||
}
|
||||
|
||||
static void BuildAnonymousName(this INamedTypeSymbol type, Context cx, TextWriter trapFile, Action<ITypeSymbol, Context, TextWriter> subTermAction, bool includeParamName)
|
||||
static void BuildAnonymousName(this INamedTypeSymbol type, Context cx, TextWriter trapFile)
|
||||
{
|
||||
var buildParam = includeParamName
|
||||
? (prop, tb0) =>
|
||||
{
|
||||
tb0.Write(prop.Name);
|
||||
tb0.Write(' ');
|
||||
subTermAction(prop.Type, cx, tb0);
|
||||
}
|
||||
: (Action<IPropertySymbol, TextWriter>)((prop, tb0) => subTermAction(prop.Type, cx, tb0));
|
||||
int memberCount = type.GetMembers().OfType<IPropertySymbol>().Count();
|
||||
int hackTypeNumber = memberCount == 1 ? 1 : 0;
|
||||
trapFile.Write("<>__AnonType");
|
||||
trapFile.Write(hackTypeNumber);
|
||||
trapFile.Write('<');
|
||||
trapFile.BuildList(",", type.GetMembers().OfType<IPropertySymbol>(), buildParam);
|
||||
trapFile.BuildList(",", type.GetMembers().OfType<IPropertySymbol>(), (prop, tb0) => BuildDisplayName(prop.Type, cx, tb0));
|
||||
trapFile.Write('>');
|
||||
}
|
||||
|
||||
@@ -444,11 +417,9 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
|
||||
if (namedType.IsAnonymousType)
|
||||
{
|
||||
namedType.BuildAnonymousName(cx, trapFile, (sub, cx0, tb0) => sub.BuildDisplayName(cx0, tb0), false);
|
||||
}
|
||||
|
||||
trapFile.Write(namedType.Name);
|
||||
namedType.BuildAnonymousName(cx, trapFile);
|
||||
else
|
||||
trapFile.Write(namedType.Name);
|
||||
if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any())
|
||||
{
|
||||
trapFile.Write('<');
|
||||
|
||||
@@ -89,8 +89,7 @@ namespace Semmle.Extraction.Entities
|
||||
|
||||
public static string PathAsDatabaseString(string path) => path.Replace('\\', '/');
|
||||
|
||||
static readonly object cacheKey = new object();
|
||||
public static File Create(Context cx, string path) => FileFactory.Instance.CreateEntity(cx, (cacheKey, path), path);
|
||||
public static File Create(Context cx, string path) => FileFactory.Instance.CreateEntity(cx, (typeof(File), path), path);
|
||||
|
||||
public static File CreateGenerated(Context cx) => GeneratedFile.Create(cx);
|
||||
|
||||
@@ -112,7 +111,7 @@ namespace Semmle.Extraction.Entities
|
||||
}
|
||||
|
||||
public static GeneratedFile Create(Context cx) =>
|
||||
GeneratedFileFactory.Instance.CreateEntity(cx, cacheKey, null);
|
||||
GeneratedFileFactory.Instance.CreateEntity(cx, typeof(GeneratedFile), null);
|
||||
|
||||
class GeneratedFileFactory : ICachedEntityFactory<string?, GeneratedFile>
|
||||
{
|
||||
|
||||
@@ -28,8 +28,7 @@ namespace Semmle.Extraction.Entities
|
||||
|
||||
public override bool Equals(object? obj) => obj != null && obj.GetType() == typeof(GeneratedLocation);
|
||||
|
||||
static readonly object cacheKey = new object();
|
||||
public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, cacheKey, null);
|
||||
public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, typeof(GeneratedLocation), null);
|
||||
|
||||
class GeneratedLocationFactory : ICachedEntityFactory<string?, GeneratedLocation>
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
@@ -75,4 +76,20 @@ namespace Semmle.Extraction
|
||||
|
||||
public abstract TrapStackBehaviour TrapStackBehaviour { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class used to wrap an `ISymbol` object, which uses `SymbolEqualityComparer.Default`
|
||||
/// for comparison.
|
||||
/// </summary>
|
||||
public sealed class SymbolEqualityWrapper
|
||||
{
|
||||
public ISymbol Symbol { get; }
|
||||
|
||||
public SymbolEqualityWrapper(ISymbol symbol) { Symbol = symbol; }
|
||||
|
||||
public override bool Equals(object? other) =>
|
||||
other is SymbolEqualityWrapper sew && SymbolEqualityComparer.Default.Equals(Symbol, sew.Symbol);
|
||||
|
||||
public override int GetHashCode() => 11 * Symbol.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,17 +56,7 @@ private class ThrowingCall extends NonReturningCall {
|
||||
}
|
||||
|
||||
/** Holds if accessor `a` has an auto-implementation. */
|
||||
private predicate hasAccessorAutoImplementation(Accessor a) {
|
||||
exists(SourceLocation sl | sl = a.getALocation() |
|
||||
not exists(ControlFlowElement cfe, Location l | sl.getFile() = l.getFile() |
|
||||
stmt_parent_top_level(cfe, _, a) and
|
||||
stmt_location(cfe, l)
|
||||
or
|
||||
expr_parent_top_level_adjusted(cfe, 0, a) and
|
||||
expr_location(cfe, l)
|
||||
)
|
||||
)
|
||||
}
|
||||
private predicate hasAccessorAutoImplementation(Accessor a) { not a.hasBody() }
|
||||
|
||||
abstract private class NonReturningCallable extends Callable {
|
||||
NonReturningCallable() {
|
||||
|
||||
Reference in New Issue
Block a user