update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / cache / TypeInfo.java
blobe13563c336c6b9b22f5967023ccc0377334e9b99
1 /*
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;
38 /**
39 * @author max
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);
59 static {
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) {
77 this.text = text;
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);
89 @NotNull
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();
96 final String text;
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();
106 else {
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();
116 else {
117 list = new ArrayList<PsiAnnotationStub>(annotations.length);
118 for (PsiAnnotation annotation : annotations) {
119 PsiAnnotationStub stub = JavaStubElementTypes.ANNOTATION.createStub(annotation, null);
120 list.add(stub);
123 return new TypeInfo(StringRef.fromString(text), (byte)arrayCount, isEllipsis, list);
126 @NotNull
127 public static TypeInfo fromString(String typeText, boolean isEllipsis) {
128 assert !typeText.endsWith("...") : typeText;
130 byte arrayCount = 0;
131 while (typeText.endsWith("[]")) {
132 arrayCount++;
133 typeText = typeText.substring(0, typeText.length() - 2);
136 StringRef text = StringRef.fromString(typeText);
138 return new TypeInfo(text, arrayCount, isEllipsis, Collections.<PsiAnnotationStub>emptyList());
141 @NotNull
142 public static TypeInfo fromString(@NotNull String typeText) {
143 boolean isEllipsis = false;
144 if (typeText.endsWith("...")) {
145 isEllipsis = true;
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());
154 @NotNull
155 public static TypeInfo readTYPE(StubInputStream record, StubElement parentStub) throws IOException {
156 final int flags = 0xFF & record.readByte();
157 if (flags == NULL_FLAGS) {
158 return NULL;
161 // flags bits
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;
168 StringRef text;
169 if (frequentIndex == 0) {
170 text = record.readName();
172 else {
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);
185 else {
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);
195 return;
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);
205 // flags bits
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) |
213 frequentIndex;
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());
230 @Nullable
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()+" ");
241 buf.append(text);
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) {
245 buf.append("...");
248 return buf.toString();
251 public void addAnnotation(PsiAnnotationStub annotation) {
252 myAnnotationStubs.add(annotation);