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.
16 package com
.intellij
.psi
.impl
.cache
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.psi
.*;
20 import com
.intellij
.psi
.impl
.compiled
.ClsTypeElementImpl
;
21 import com
.intellij
.psi
.impl
.java
.stubs
.JavaStubElementTypes
;
22 import com
.intellij
.psi
.impl
.java
.stubs
.PsiAnnotationStub
;
23 import com
.intellij
.psi
.stubs
.StubElement
;
24 import com
.intellij
.psi
.stubs
.StubInputStream
;
25 import com
.intellij
.psi
.stubs
.StubOutputStream
;
26 import com
.intellij
.util
.io
.StringRef
;
27 import com
.intellij
.util
.SmartList
;
28 import gnu
.trove
.TIntObjectHashMap
;
29 import gnu
.trove
.TObjectIntHashMap
;
30 import org
.jetbrains
.annotations
.NotNull
;
31 import org
.jetbrains
.annotations
.Nullable
;
33 import java
.io
.IOException
;
34 import java
.util
.ArrayList
;
35 import java
.util
.Collections
;
36 import java
.util
.List
;
41 public class TypeInfo
{
42 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.impl.cache.TypeInfo");
44 public final StringRef text
;
45 public final byte arrayCount
;
46 public final boolean isEllipsis
;
47 public static final TIntObjectHashMap
<String
> ourIndexFrequentType
= new TIntObjectHashMap
<String
>();
48 private static final TObjectIntHashMap
<String
> ourFrequentTypeIndex
= new TObjectIntHashMap
<String
>();
50 private final List
<PsiAnnotationStub
> myAnnotationStubs
;
52 private static void registerFrequentType(String typeText
) {
53 int index
= ourFrequentTypeIndex
.size() + 1;
54 assert index
< 15; // 0xf is reserved
55 ourFrequentTypeIndex
.put(typeText
, index
);
56 ourIndexFrequentType
.put(index
, typeText
);
60 registerFrequentType("boolean");
61 registerFrequentType("byte");
62 registerFrequentType("char");
63 registerFrequentType("double");
64 registerFrequentType("float");
65 registerFrequentType("int");
66 registerFrequentType("long");
67 registerFrequentType("null");
68 registerFrequentType("short");
69 registerFrequentType("void");
70 registerFrequentType("Object");
71 registerFrequentType("java.lang.Object");
72 registerFrequentType("String");
73 registerFrequentType("java.lang.String");
76 public TypeInfo(StringRef text
, byte arrayCount
, boolean ellipsis
, @NotNull List
<PsiAnnotationStub
> annotationStubs
) {
78 this.arrayCount
= arrayCount
;
79 isEllipsis
= ellipsis
;
80 myAnnotationStubs
= annotationStubs
;
82 public TypeInfo(@NotNull TypeInfo typeInfo
) {
83 this.text
= typeInfo
.text
;
84 this.arrayCount
= typeInfo
.arrayCount
;
85 isEllipsis
= typeInfo
.isEllipsis
;
86 myAnnotationStubs
= new SmartList
<PsiAnnotationStub
>(typeInfo
.myAnnotationStubs
);
90 public static TypeInfo
create(PsiType type
, PsiTypeElement typeElement
) {
91 if (type
== null) return NULL
;
93 final boolean isEllipsis
= type
instanceof PsiEllipsisType
;
94 int arrayCount
= type
.getArrayDimensions();
97 if (typeElement
!= null) {
98 while (typeElement
.getFirstChild() instanceof PsiTypeElement
) {
99 typeElement
= (PsiTypeElement
)typeElement
.getFirstChild();
102 text
= typeElement
instanceof PsiCompiledElement
103 ?
((ClsTypeElementImpl
)typeElement
).getCanonicalText()
104 : typeElement
.getText();
107 type
= type
.getDeepComponentType();
108 text
= type
.getInternalCanonicalText();
111 PsiAnnotation
[] annotations
= type
.getAnnotations();
112 List
<PsiAnnotationStub
> list
;
113 if (annotations
.length
== 0) {
114 list
= Collections
.emptyList();
117 list
= new ArrayList
<PsiAnnotationStub
>(annotations
.length
);
118 for (PsiAnnotation annotation
: annotations
) {
119 PsiAnnotationStub stub
= JavaStubElementTypes
.ANNOTATION
.createStub(annotation
, null);
123 return new TypeInfo(StringRef
.fromString(text
), (byte)arrayCount
, isEllipsis
, list
);
127 public static TypeInfo
fromString(String typeText
, boolean isEllipsis
) {
128 assert !typeText
.endsWith("...") : typeText
;
131 while (typeText
.endsWith("[]")) {
133 typeText
= typeText
.substring(0, typeText
.length() - 2);
136 StringRef text
= StringRef
.fromString(typeText
);
138 return new TypeInfo(text
, arrayCount
, isEllipsis
, Collections
.<PsiAnnotationStub
>emptyList());
142 public static TypeInfo
fromString(@NotNull String typeText
) {
143 boolean isEllipsis
= false;
144 if (typeText
.endsWith("...")) {
146 typeText
= typeText
.substring(0, typeText
.length() - 3);
149 return fromString(typeText
, isEllipsis
);
152 private static final TypeInfo NULL
= new TypeInfo(null, (byte)0, false, Collections
.<PsiAnnotationStub
>emptyList());
155 public static TypeInfo
readTYPE(StubInputStream record
, StubElement parentStub
) throws IOException
{
156 final int flags
= 0xFF & record
.readByte();
157 if (flags
== NULL_FLAGS
) {
162 // ZeroPad:1 IsEllipsis:1 ArrayCountPresent:1 AnnotationsArePresent:1 FrequentIndex:4
164 final int frequentIndex
= 0xF & flags
;
166 byte arrayCount
= (flags
& 0x20) != 0 ? record
.readByte() : 0;
167 boolean isEllipsis
= (flags
& 0x40) != 0;
169 if (frequentIndex
== 0) {
170 text
= record
.readName();
173 text
= StringRef
.fromString(ourIndexFrequentType
.get(frequentIndex
));
175 boolean annotationsArePresent
= (flags
& 0x10) != 0;
176 List
<PsiAnnotationStub
> annotationStubs
;
177 if (annotationsArePresent
) {
178 int size
= 0xFF & record
.readByte();
179 annotationStubs
= new ArrayList
<PsiAnnotationStub
>(size
);
180 for (int i
=0; i
<size
; i
++) {
181 PsiAnnotationStub annotationStub
= JavaStubElementTypes
.ANNOTATION
.deserialize(record
, parentStub
);
182 annotationStubs
.add(annotationStub
);
186 annotationStubs
= Collections
.emptyList();
188 return new TypeInfo(text
, arrayCount
, isEllipsis
, annotationStubs
);
191 private static final int NULL_FLAGS
= 0x0F;
192 public static void writeTYPE(final StubOutputStream dataStream
, @NotNull TypeInfo typeInfo
) throws IOException
{
193 if (typeInfo
== NULL
) {
194 dataStream
.writeByte(NULL_FLAGS
);
198 boolean isEllipsis
= typeInfo
.isEllipsis
;
199 String text
= typeInfo
.text
.getString();
200 byte arrayCount
= typeInfo
.arrayCount
;
202 int frequentIndex
= ourFrequentTypeIndex
.get(text
);
203 LOG
.assertTrue(frequentIndex
< 15, frequentIndex
);
206 // ZeroPad:1 IsEllipsis:1 ArrayCountPresent:1 AnnotationsArePresent:1 FrequentIndex:4
208 List
<PsiAnnotationStub
> annotations
= typeInfo
.myAnnotationStubs
;
209 boolean annotationsArePresent
= !annotations
.isEmpty();
210 int flags
= ((isEllipsis ?
1 : 0) << 6) |
211 ((arrayCount
== 0 ?
0 : 1) << 5) |
212 ((annotationsArePresent ?
1 : 0)<<4) |
214 dataStream
.writeByte(flags
);
215 if (arrayCount
!= 0) {
216 dataStream
.writeByte(arrayCount
);
218 if (frequentIndex
== 0) {
219 dataStream
.writeName(text
);
221 if (annotationsArePresent
) {
222 LOG
.assertTrue(annotations
.size() < 256, annotations
.size());
223 dataStream
.writeByte(annotations
.size());
224 for (PsiAnnotationStub annotation
: annotations
) {
225 dataStream
.writeUTFFast(annotation
.getText());
231 public static String
createTypeText(@NotNull TypeInfo typeInfo
) {
232 if (typeInfo
== NULL
) return null;
233 if (typeInfo
.text
== null) return null;
234 if (typeInfo
.arrayCount
== 0 && typeInfo
.myAnnotationStubs
.isEmpty()) return typeInfo
.text
.getString();
236 String text
= typeInfo
.text
.getString();
237 StringBuilder buf
= new StringBuilder(text
.length());
238 for (PsiAnnotationStub stub
: typeInfo
.myAnnotationStubs
) {
239 buf
.append(stub
.getText()+" ");
242 final int arrayCount
= typeInfo
.isEllipsis ? typeInfo
.arrayCount
- 1 : typeInfo
.arrayCount
;
243 for (int i
= 0; i
< arrayCount
; i
++) buf
.append("[]");
244 if (typeInfo
.isEllipsis
) {
248 return buf
.toString();
251 public void addAnnotation(PsiAnnotationStub annotation
) {
252 myAnnotationStubs
.add(annotation
);