@@ -35,6 +35,7 @@ public class AngularJsHtmlElementsProvider : IHtmlDeclaredElementsProvider
3535 {
3636 private readonly AngularJsCache cache ;
3737 private readonly ISolution solution ;
38+ private readonly HtmlStandardDeclaredElementsProvider standardProvider ;
3839 private readonly object lockObject = new object ( ) ;
3940 private readonly IHtmlAttributeValueType cdataAttributeValueType ;
4041 private readonly Dictionary < string , IHtmlTagDeclaredElement > tags = new Dictionary < string , IHtmlTagDeclaredElement > ( ) ;
@@ -43,11 +44,14 @@ public class AngularJsHtmlElementsProvider : IHtmlDeclaredElementsProvider
4344 private ISymbolTable commonAttributesSymbolTable ;
4445 private ISymbolTable allAttributesSymbolTable ;
4546 private ISymbolTable allTagsSymbolTable ;
47+ private JetHashSet < string > allTags ;
48+ private JetHashSet < string > allAttributes ;
4649
47- public AngularJsHtmlElementsProvider ( Lifetime lifetime , AngularJsCache cache , ISolution solution )
50+ public AngularJsHtmlElementsProvider ( Lifetime lifetime , AngularJsCache cache , ISolution solution , HtmlStandardDeclaredElementsProvider standardProvider )
4851 {
4952 this . cache = cache ;
5053 this . solution = solution ;
54+ this . standardProvider = standardProvider ;
5155
5256 // TODO: Finer grained caching?
5357 // This will clear the cache of elements whenever the AngularJs cache changes, which will be
@@ -131,10 +135,8 @@ public IHtmlTagDeclaredElement GetTag(string name)
131135 {
132136 lock ( lockObject )
133137 {
134- var providers = solution . GetComponents < IHtmlDeclaredElementsProvider > ( ) ;
135-
136138 var tagDeclaredElements = from d in cache . Directives
137- where d . IsElement && string . Equals ( d . Name , name , StringComparison . InvariantCultureIgnoreCase ) && ! IsOverridingTag ( d . Name , providers )
139+ where d . IsElement && string . Equals ( d . Name , name , StringComparison . InvariantCultureIgnoreCase ) && ! IsOverridingTag ( d . Name )
138140 select GetOrCreateTagLocked ( d . Name ) ;
139141 return tagDeclaredElements . FirstOrDefault ( ) ;
140142 }
@@ -151,10 +153,9 @@ public ISymbolTable GetAllTagsSymbolTable()
151153 if ( allTagsSymbolTable == null )
152154 {
153155 var psiServices = solution . GetComponent < IPsiServices > ( ) ;
154- var providers = solution . GetComponents < IHtmlDeclaredElementsProvider > ( ) ;
155156
156157 var tagDeclaredElements = from d in cache . Directives
157- where d . IsElement && ! IsOverridingTag ( d . Name , providers )
158+ where d . IsElement && ! IsOverridingTag ( d . Name )
158159 from n in GetPrefixedNames ( d . Name )
159160 select GetOrCreateTagLocked ( n ) ;
160161 allTagsSymbolTable = new DeclaredElementsSymbolTable < IHtmlTagDeclaredElement > ( psiServices , tagDeclaredElements ) ;
@@ -207,8 +208,8 @@ from p in d.Parameters
207208 from n in GetPrefixedNames ( p . Name )
208209 select GetOrCreateAttributeLocked ( n , d . Name ) ;
209210
210- var attributes = attributeDeclaredElements . Concat ( parameterAttributeDeclaredElements ) ;
211- allAttributesSymbolTable = new DeclaredElementsSymbolTable < IHtmlAttributeDeclaredElement > ( psiServices , attributes ) ;
211+ var attrs = attributeDeclaredElements . Concat ( parameterAttributeDeclaredElements ) ;
212+ allAttributesSymbolTable = new DeclaredElementsSymbolTable < IHtmlAttributeDeclaredElement > ( psiServices , attrs ) ;
212213 }
213214 return allAttributesSymbolTable ;
214215 }
@@ -248,15 +249,44 @@ public bool IsApplicable(IPsiSourceFile file)
248249 return true ;
249250 }
250251
251- private bool IsOverridingTag ( string name , IEnumerable < IHtmlDeclaredElementsProvider > providers )
252+ private bool IsOverridingTag ( string name )
252253 {
253- // This feels a little rude...
254- return providers . Where ( p => p != this ) . Any ( p => p . GetTag ( name ) != null ) ;
254+ // This is horrible. We can't override existing tags and attributes, but we calling the
255+ // other providers dynamically causes serious perf issues. We'll just make do with
256+ // caching the standard HTML attributes and hope for the best. We also can't do this
257+ // in the constructor, or we get a nasty circular instantiation issue. I'll file a YT
258+ // ticket to handle this better in a future version.
259+ if ( allTags == null )
260+ {
261+ lock ( lockObject )
262+ {
263+ if ( allTags == null )
264+ {
265+ allTags = standardProvider . GetAllTagsSymbolTable ( ) . Names ( ) . ToHashSet ( IdentityFunc < string > . Instance , StringComparer . InvariantCultureIgnoreCase ) ;
266+ }
267+ }
268+ }
269+ return allTags . Contains ( name ) ;
255270 }
256271
257272 private bool IsKnownCommonAttribute ( string name , IEnumerable < IHtmlDeclaredElementsProvider > providers )
258273 {
259- return providers . Where ( p => p != this ) . Any ( p => p . GetAttributes ( name ) . Any ( ) ) ;
274+ // This is horrible. We can't override existing tags and attributes, but we calling the
275+ // other providers dynamically causes serious perf issues. We'll just make do with
276+ // caching the standard HTML attributes and hope for the best. We also can't do this
277+ // in the constructor, or we get a nasty circular instantiation issue. I'll file a YT
278+ // ticket to handle this better in a future version.
279+ if ( allAttributes == null )
280+ {
281+ lock ( lockObject )
282+ {
283+ if ( allAttributes == null )
284+ {
285+ allAttributes = standardProvider . GetAllAttributesSymbolTable ( ) . Names ( ) . ToHashSet ( IdentityFunc < string > . Instance , StringComparer . InvariantCultureIgnoreCase ) ;
286+ }
287+ }
288+ }
289+ return allAttributes . Contains ( name ) ;
260290 }
261291
262292 private static string StripPrefix ( string name )
0 commit comments