2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com
.intellij
.psi
.impl
.meta
;
19 import com
.intellij
.openapi
.Disposable
;
20 import com
.intellij
.openapi
.extensions
.Extensions
;
21 import com
.intellij
.openapi
.progress
.ProgressManager
;
22 import com
.intellij
.openapi
.util
.Disposer
;
23 import com
.intellij
.openapi
.util
.Key
;
24 import com
.intellij
.openapi
.util
.UserDataCache
;
25 import com
.intellij
.patterns
.ElementPattern
;
26 import com
.intellij
.psi
.PsiElement
;
27 import com
.intellij
.psi
.filters
.ElementFilter
;
28 import com
.intellij
.psi
.filters
.position
.PatternFilter
;
29 import com
.intellij
.psi
.meta
.MetaDataContributor
;
30 import com
.intellij
.psi
.meta
.MetaDataRegistrar
;
31 import com
.intellij
.psi
.meta
.PsiMetaData
;
32 import com
.intellij
.psi
.util
.CachedValue
;
33 import com
.intellij
.psi
.util
.CachedValueProvider
;
34 import com
.intellij
.psi
.util
.CachedValuesManager
;
35 import com
.intellij
.util
.containers
.ContainerUtil
;
36 import org
.jetbrains
.annotations
.NotNull
;
37 import org
.jetbrains
.annotations
.Nullable
;
39 import java
.util
.List
;
42 * Created by IntelliJ IDEA.
46 * To change this template use Options | File Templates.
48 public class MetaRegistry
extends MetaDataRegistrar
{
49 private static final List
<MyBinding
> ourBindings
= ContainerUtil
.createEmptyCOWList();
50 private static volatile boolean ourContributorsLoaded
= false;
52 private static final Key
<CachedValue
<PsiMetaData
>> META_DATA_KEY
= Key
.create("META DATA KEY");
54 public static void bindDataToElement(final PsiElement element
, final PsiMetaData data
) {
55 CachedValue
<PsiMetaData
> value
= CachedValuesManager
.getManager(element
.getProject()).createCachedValue(new CachedValueProvider
<PsiMetaData
>() {
56 public Result
<PsiMetaData
> compute() {
58 return new Result
<PsiMetaData
>(data
, data
.getDependences());
61 element
.putUserData(META_DATA_KEY
, value
);
64 public static PsiMetaData
getMeta(final PsiElement element
) {
65 final PsiMetaData base
= getMetaBase(element
);
66 return base
!= null ? base
: null;
69 private static final UserDataCache
<CachedValue
<PsiMetaData
>, PsiElement
, Object
> ourCachedMetaCache
=
70 new UserDataCache
<CachedValue
<PsiMetaData
>, PsiElement
, Object
>() {
71 protected CachedValue
<PsiMetaData
> compute(final PsiElement element
, Object p
) {
72 return CachedValuesManager
.getManager(element
.getProject()).createCachedValue(new CachedValueProvider
<PsiMetaData
>() {
73 public Result
<PsiMetaData
> compute() {
75 ensureContributorsLoaded();
76 for (final MyBinding binding
: ourBindings
) {
77 if (binding
.myFilter
.isClassAcceptable(element
.getClass()) && binding
.myFilter
.isAcceptable(element
, element
.getParent())) {
78 final PsiMetaData data
= binding
.myDataClass
.newInstance();
80 return new Result
<PsiMetaData
>(data
, data
.getDependences());
84 catch (IllegalAccessException iae
) {
85 throw new RuntimeException(iae
);
87 catch (InstantiationException ie
) {
88 throw new RuntimeException(ie
);
91 return new Result
<PsiMetaData
>(null, element
);
97 private static void ensureContributorsLoaded() {
98 if (!ourContributorsLoaded
) {
99 synchronized (ourBindings
) {
100 if (!ourContributorsLoaded
) {
101 for(MetaDataContributor contributor
: Extensions
.getExtensions(MetaDataContributor
.EP_NAME
)) {
102 contributor
.contributeMetaData(MetaDataRegistrar
.getInstance());
104 ourContributorsLoaded
= true;
111 public static PsiMetaData
getMetaBase(final PsiElement element
) {
112 ProgressManager
.checkCanceled();
113 return ourCachedMetaCache
.get(META_DATA_KEY
, element
, null).getValue();
116 public static <T
extends PsiMetaData
> void addMetadataBinding(ElementFilter filter
, Class
<T
> aMetadataClass
, Disposable parentDisposable
) {
117 final MyBinding binding
= new MyBinding(filter
, aMetadataClass
);
119 Disposer
.register(parentDisposable
, new Disposable() {
120 public void dispose() {
121 ourBindings
.remove(binding
);
126 public static <T
extends PsiMetaData
> void addMetadataBinding(ElementFilter filter
, Class
<T
> aMetadataClass
) {
127 addBinding(new MyBinding(filter
, aMetadataClass
));
130 private static void addBinding(final MyBinding binding
) {
131 ourBindings
.add(0, binding
);
134 public <T
extends PsiMetaData
> void registerMetaData(ElementFilter filter
, Class
<T
> metadataDescriptorClass
) {
135 addMetadataBinding(filter
, metadataDescriptorClass
);
139 public <T
extends PsiMetaData
> void registerMetaData(ElementPattern
<?
> pattern
, Class
<T
> metadataDescriptorClass
) {
140 addMetadataBinding(new PatternFilter(pattern
), metadataDescriptorClass
);
143 private static class MyBinding
{
144 private final ElementFilter myFilter
;
145 private final Class
<?
extends PsiMetaData
> myDataClass
;
147 public MyBinding(@NotNull ElementFilter filter
, @NotNull Class
<?
extends PsiMetaData
> dataClass
) {
149 myDataClass
= dataClass
;