Skip to content

Commit 93ce34a

Browse files
committed
C#: Add a new object->entity cache.
1 parent 88734f1 commit 93ce34a

File tree

3 files changed

+87
-54
lines changed

3 files changed

+87
-54
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public NamedTypeRef(Context cx, INamedTypeSymbol symbol) : base(cx, symbol)
174174
referencedType = Type.Create(cx, symbol);
175175
}
176176

177-
public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) => NamedTypeRefFactory.Instance.CreateEntity(cx, type);
177+
public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) => NamedTypeRefFactory.Instance.CreateEntity2(cx, type);
178178

179179
class NamedTypeRefFactory : ICachedEntityFactory<INamedTypeSymbol, NamedTypeRef>
180180
{

csharp/extractor/Semmle.Extraction/Context.cs

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,37 +43,81 @@ public SemanticModel Model(SyntaxNode node)
4343
int NewId() => TrapWriter.IdCounter++;
4444

4545
/// <summary>
46-
/// Gets the cached label for the given entity, or creates a new
47-
/// (cached) label if it hasn't already been created. The label
48-
/// is set on the supplied <paramref name="entity"/> object.
46+
/// Creates a new entity using the factory.
4947
/// </summary>
50-
/// <returns><code>true</code> iff the label already existed.</returns>
51-
public bool GetOrAddCachedLabel(ICachedEntity entity)
48+
/// <param name="factory">The entity factory.</param>
49+
/// <param name="init">The initializer for the entity.</param>
50+
/// <returns>The new/existing entity.</returns>
51+
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
5252
{
53-
// Look up the label in the entityLabelCache
54-
if (entityLabelCache.TryGetValue(entity, out Label label))
53+
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
54+
}
55+
56+
/// <summary>
57+
/// Creates a new entity using the factory.
58+
/// Uses a different cache to <see cref="CreateEntity{Type, Entity}(ICachedEntityFactory{Type, Entity}, Type)"/>,
59+
/// and can store null values.
60+
/// </summary>
61+
/// <param name="factory">The entity factory.</param>
62+
/// <param name="init">The initializer for the entity.</param>
63+
/// <returns>The new/existing entity.</returns>
64+
public Entity CreateEntity2<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type type) where Entity : ICachedEntity
65+
{
66+
using (StackGuard)
5567
{
56-
entity.Label = label;
57-
return true;
68+
var entity = factory.Create(this, type);
69+
70+
if(entityLabelCache.TryGetValue(entity, out var label))
71+
{
72+
entity.Label = label;
73+
return entity;
74+
}
75+
else
76+
{
77+
var id = entity.Id;
78+
label = new Label(NewId());
79+
entity.Label = label;
80+
entityLabelCache[entity] = label;
81+
DefineLabel(label, id);
82+
if (entity.NeedsPopulation)
83+
Populate(null, entity);
84+
return entity;
85+
}
5886
}
87+
}
88+
89+
private Entity CreateNonNullEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
90+
{
91+
if (objectEntityCache.TryGetValue(init, out var cached))
92+
return (Entity)cached;
5993

60-
entity.Label = label = new Label(NewId());
61-
entityLabelCache[entity] = label;
94+
using (StackGuard)
95+
{
96+
var label = new Label(NewId());
97+
var entity = factory.Create(this, init);
98+
entity.Label = label;
6299

63-
var id = entity.Id;
64-
DefineLabel(label, id);
100+
objectEntityCache[init] = entity;
101+
102+
var id = entity.Id;
103+
DefineLabel(label, id);
65104

66105
#if DEBUG_LABELS
67-
if (idLabelCache.TryGetValue(id, out var originalEntity))
68-
{
69-
Extractor.Message(new Message { message = "Label collision for " + id.ToString(), severity = Severity.Warning });
70-
}
71-
else
72-
{
73-
idLabelCache[id] = entity;
74-
}
106+
if (idLabelCache.TryGetValue(id, out var originalEntity))
107+
{
108+
Extractor.Message(new Message { message = "Label collision for " + id.ToString(), severity = Severity.Warning });
109+
}
110+
else
111+
{
112+
idLabelCache[id] = entity;
113+
}
75114
#endif
76-
return false;
115+
116+
if (entity.NeedsPopulation)
117+
Populate(init as ISymbol, entity);
118+
119+
return entity;
120+
}
77121
}
78122

79123
/// <summary>
@@ -111,6 +155,7 @@ public void AddFreshLabel(IEntity entity)
111155
}
112156

113157
readonly Dictionary<IId, ICachedEntity> idLabelCache = new Dictionary<IId, ICachedEntity>();
158+
readonly Dictionary<object, ICachedEntity> objectEntityCache = new Dictionary<object, ICachedEntity>();
114159
readonly Dictionary<ICachedEntity, Label> entityLabelCache = new Dictionary<ICachedEntity, Label>();
115160
readonly HashSet<Label> extractedGenerics = new HashSet<Label>();
116161

csharp/extractor/Semmle.Extraction/Entity.cs

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -98,48 +98,36 @@ public interface ICachedEntityFactory<Initializer, Entity> where Entity : ICache
9898
public static class ICachedEntityFactoryExtensions
9999
{
100100
public static Entity CreateEntity<Entity, T1, T2>(this ICachedEntityFactory<(T1, T2), Entity> factory, Context cx, T1 t1, T2 t2)
101-
where Entity : ICachedEntity
102-
{
103-
return factory.CreateEntity(cx, (t1, t2));
104-
}
101+
where Entity : ICachedEntity => factory.CreateEntity2(cx, (t1, t2));
105102

106103
public static Entity CreateEntity<Entity, T1, T2, T3>(this ICachedEntityFactory<(T1, T2, T3), Entity> factory, Context cx, T1 t1, T2 t2, T3 t3)
107-
where Entity : ICachedEntity
108-
{
109-
return factory.CreateEntity(cx, (t1, t2, t3));
110-
}
104+
where Entity : ICachedEntity => factory.CreateEntity2(cx, (t1, t2, t3));
111105

112106
public static Entity CreateEntity<Entity, T1, T2, T3, T4>(this ICachedEntityFactory<(T1, T2, T3, T4), Entity> factory, Context cx, T1 t1, T2 t2, T3 t3, T4 t4)
113-
where Entity : ICachedEntity
114-
{
115-
return factory.CreateEntity(cx, (t1, t2, t3, t4));
116-
}
107+
where Entity : ICachedEntity => factory.CreateEntity2(cx, (t1, t2, t3, t4));
117108

118109
/// <summary>
119-
/// Creates a new entity or returns the existing one from the cache.
110+
/// Creates and populates a new entity, or returns the existing one from the cache.
120111
/// </summary>
121112
/// <typeparam name="Type">The symbol type used to construct the entity.</typeparam>
122113
/// <typeparam name="Entity">The type of the entity to create.</typeparam>
123114
/// <param name="cx">The extractor context.</param>
124115
/// <param name="factory">The factory used to construct the entity.</param>
125-
/// <param name="t">The initializer for the entity.</param>
126-
/// <returns></returns>
116+
/// <param name="init">The initializer for the entity, which may not be null.</param>
117+
/// <returns>The entity.</returns>
127118
public static Entity CreateEntity<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
128-
where Entity : ICachedEntity
129-
{
130-
using (cx.StackGuard)
131-
{
132-
var entity = factory.Create(cx, init);
133-
if (cx.GetOrAddCachedLabel(entity))
134-
return entity;
135-
136-
if (!entity.NeedsPopulation)
137-
return entity;
138-
139-
cx.Populate(init as ISymbol, entity);
140-
141-
return entity;
142-
}
143-
}
119+
where Entity : ICachedEntity => cx.CreateEntity(factory, init);
120+
121+
/// <summary>
122+
/// Creates and populates a new entity, but uses a different cache.
123+
/// </summary>
124+
/// <typeparam name="Type">The symbol type used to construct the entity.</typeparam>
125+
/// <typeparam name="Entity">The type of the entity to create.</typeparam>
126+
/// <param name="cx">The extractor context.</param>
127+
/// <param name="factory">The factory used to construct the entity.</param>
128+
/// <param name="init">The initializer for the entity, which may be null.</param>
129+
/// <returns>The entity.</returns>
130+
public static Entity CreateEntity2<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
131+
where Entity : ICachedEntity => cx.CreateEntity2(factory, init);
144132
}
145133
}

0 commit comments

Comments
 (0)