1- using System ;
21using System . IO ;
32using System . Linq ;
43using Microsoft . CodeAnalysis ;
87
98namespace Semmle . Extraction . CSharp . Entities
109{
11- internal class Attribute : FreshEntity , IExpressionParentEntity
10+ internal class Attribute : CachedEntity < ( AttributeData , IEntity ) > , IExpressionParentEntity
1211 {
1312 bool IExpressionParentEntity . IsTopLevelParent => true ;
1413
1514 private readonly AttributeData attributeData ;
1615 private readonly AttributeSyntax attributeSyntax ;
1716 private readonly IEntity entity ;
1817
19- public Attribute ( Context cx , AttributeData attributeData , IEntity entity )
20- : base ( cx )
18+ private Attribute ( Context cx , AttributeData attributeData , IEntity entity )
19+ : base ( cx , ( attributeData , entity ) )
2120 {
2221 this . attributeData = attributeData ;
2322 this . attributeSyntax = attributeData . ApplicationSyntaxReference ? . GetSyntax ( ) as AttributeSyntax ;
2423 this . entity = entity ;
24+ }
25+
26+ public override void WriteId ( TextWriter trapFile )
27+ {
28+ if ( ReportingLocation ? . IsInSource == true )
29+ {
30+ trapFile . WriteSubId ( Context . Create ( ReportingLocation ) ) ;
31+ trapFile . Write ( ";attribute" ) ;
32+ }
33+ else
34+ {
35+ trapFile . Write ( '*' ) ;
36+ }
37+ }
2538
26- TryPopulate ( ) ;
39+ public override void WriteQuotedId ( TextWriter trapFile )
40+ {
41+ if ( ReportingLocation ? . IsInSource == true )
42+ {
43+ base . WriteQuotedId ( trapFile ) ;
44+ }
45+ else
46+ {
47+ trapFile . Write ( '*' ) ;
48+ }
2749 }
2850
29- protected override void Populate ( TextWriter trapFile )
51+ public override void Populate ( TextWriter trapFile )
3052 {
31- var type = Type . Create ( cx , attributeData . AttributeClass ) ;
53+ var type = Type . Create ( Context , attributeData . AttributeClass ) ;
3254 trapFile . attributes ( this , type . TypeRef , entity ) ;
3355
3456 if ( attributeSyntax is object )
3557 {
36- trapFile . attribute_location ( this , cx . Create ( attributeSyntax . Name . GetLocation ( ) ) ) ;
58+ trapFile . attribute_location ( this , Context . Create ( attributeSyntax . Name . GetLocation ( ) ) ) ;
3759
38- if ( cx . Extractor . OutputPath != null )
60+ if ( Context . Extractor . OutputPath != null )
3961 {
40- trapFile . attribute_location ( this , Assembly . CreateOutputAssembly ( cx ) ) ;
62+ trapFile . attribute_location ( this , Assembly . CreateOutputAssembly ( Context ) ) ;
4163 }
4264
43- TypeMention . Create ( cx , attributeSyntax . Name , this , type ) ;
65+ TypeMention . Create ( Context , attributeSyntax . Name , this , type ) ;
4466 }
4567
4668 ExtractArguments ( trapFile ) ;
@@ -80,7 +102,7 @@ private Expression CreateExpressionFromArgument(TypedConstant constant, Expressi
80102 {
81103 if ( syntax is object )
82104 {
83- return Expression . Create ( cx , syntax , parent , childIndex ) ;
105+ return Expression . Create ( Context , syntax , parent , childIndex ) ;
84106 }
85107
86108 return CreateGeneratedExpressionFromArgument ( constant , parent , childIndex ) ;
@@ -91,25 +113,25 @@ private Expression CreateGeneratedExpressionFromArgument(TypedConstant constant,
91113 {
92114 if ( constant . IsNull )
93115 {
94- return Literal . CreateGeneratedNullLiteral ( cx , parent , childIndex ) ;
116+ return Literal . CreateGeneratedNullLiteral ( Context , parent , childIndex ) ;
95117 }
96118
97119 switch ( constant . Kind )
98120 {
99121 case TypedConstantKind . Primitive :
100- return Literal . CreateGenerated ( cx , parent , childIndex , constant . Type , constant . Value ) ;
122+ return Literal . CreateGenerated ( Context , parent , childIndex , constant . Type , constant . Value ) ;
101123 case TypedConstantKind . Enum :
102124 // Enum value is generated in the following format: (Enum)value
103125
104- var cast = Cast . CreateGenerated ( cx , parent , childIndex , constant . Type , constant . Value ) ;
105- Literal . CreateGenerated ( cx , cast , Cast . ExpressionIndex , ( ( INamedTypeSymbol ) constant . Type ) . EnumUnderlyingType , constant . Value ) ;
106- TypeAccess . CreateGenerated ( cx , cast , Cast . TypeAccessIndex , constant . Type ) ;
126+ var cast = Cast . CreateGenerated ( Context , parent , childIndex , constant . Type , constant . Value ) ;
127+ Literal . CreateGenerated ( Context , cast , Cast . ExpressionIndex , ( ( INamedTypeSymbol ) constant . Type ) . EnumUnderlyingType , constant . Value ) ;
128+ TypeAccess . CreateGenerated ( Context , cast , Cast . TypeAccessIndex , constant . Type ) ;
107129
108130 return cast ;
109131 case TypedConstantKind . Type :
110132 var type = ( ( ITypeSymbol ) constant . Value ) . OriginalDefinition ;
111- var t = TypeOf . CreateGenerated ( cx , parent , childIndex , type ) ;
112- TypeAccess . CreateGenerated ( cx , t , TypeOf . TypeAccessIndex , type ) ;
133+ var t = TypeOf . CreateGenerated ( Context , parent , childIndex , type ) ;
134+ TypeAccess . CreateGenerated ( Context , t , TypeOf . TypeAccessIndex , type ) ;
113135 return t ;
114136 case TypedConstantKind . Array :
115137 {
@@ -119,11 +141,11 @@ private Expression CreateGeneratedExpressionFromArgument(TypedConstant constant,
119141 //
120142 // itemI is generated recursively.
121143
122- var arrayCreation = NormalArrayCreation . CreateGenerated ( cx , parent , childIndex , constant . Type , constant . Values . Length ) ;
144+ var arrayCreation = NormalArrayCreation . CreateGenerated ( Context , parent , childIndex , constant . Type , constant . Values . Length ) ;
123145
124146 if ( constant . Values . Length > 0 )
125147 {
126- var arrayInit = ArrayInitializer . CreateGenerated ( cx , arrayCreation ) ;
148+ var arrayInit = ArrayInitializer . CreateGenerated ( Context , arrayCreation ) ;
127149
128150 constant . Values
129151 . Select ( ( constantItem , itemIndex ) => CreateGeneratedExpressionFromArgument ( constantItem , arrayInit , itemIndex ) )
@@ -134,19 +156,37 @@ private Expression CreateGeneratedExpressionFromArgument(TypedConstant constant,
134156 return arrayCreation ;
135157 }
136158 default :
137- cx . ExtractionError ( "Couldn't extract constant in attribute" , entity . ToString ( ) , cx . Create ( entity . ReportingLocation ) ) ;
159+ Context . ExtractionError ( "Couldn't extract constant in attribute" , entity . ToString ( ) , Context . Create ( entity . ReportingLocation ) ) ;
138160 return null ;
139161 }
140162 }
141163
164+ public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour . OptionalLabel ;
165+
166+ public override Microsoft . CodeAnalysis . Location ReportingLocation => attributeSyntax ? . Name . GetLocation ( ) ;
167+
168+ public override bool NeedsPopulation => true ;
169+
142170 public static void ExtractAttributes ( Context cx , ISymbol symbol , IEntity entity )
143171 {
144172 foreach ( var attribute in symbol . GetAttributes ( ) )
145173 {
146- new Attribute ( cx , attribute , entity ) ;
174+ Create ( cx , attribute , entity ) ;
147175 }
148176 }
149177
150- public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour . OptionalLabel ;
178+ public static Attribute Create ( Context cx , AttributeData attributeData , IEntity entity )
179+ {
180+ var init = ( attributeData , entity ) ;
181+ return AttributeFactory . Instance . CreateEntity ( cx , init , init ) ;
182+ }
183+
184+ private class AttributeFactory : ICachedEntityFactory < ( AttributeData attributeData , IEntity receiver ) , Attribute >
185+ {
186+ public static readonly AttributeFactory Instance = new AttributeFactory ( ) ;
187+
188+ public Attribute Create ( Context cx , ( AttributeData attributeData , IEntity receiver ) init ) =>
189+ new Attribute ( cx , init . attributeData , init . receiver ) ;
190+ }
151191 }
152192}
0 commit comments