5491db0d37249c1fc2cb633146fe759cf104118d
[idea/community.git] / platform / lang-impl / src / com / intellij / psi / stubs / StubTreeLoaderImpl.java
1 /*
2  * Copyright 2000-2011 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.psi.stubs;
17
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.application.ModalityState;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.openapi.editor.Document;
22 import com.intellij.openapi.fileEditor.FileDocumentManager;
23 import com.intellij.openapi.project.DumbService;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.vfs.VirtualFile;
26 import com.intellij.psi.search.GlobalSearchScopes;
27 import com.intellij.util.indexing.FileBasedIndex;
28 import com.intellij.util.indexing.FileContent;
29 import com.intellij.util.indexing.FileContentImpl;
30 import com.intellij.util.indexing.IndexingStamp;
31 import org.jetbrains.annotations.Nullable;
32
33 import java.io.IOException;
34 import java.util.List;
35
36 /**
37  * @author yole
38  */
39 public class StubTreeLoaderImpl extends StubTreeLoader {
40   private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.StubTreeLoaderImpl");
41
42   @Nullable
43   public StubTree readOrBuild(Project project, final VirtualFile vFile) {
44     final StubTree fromIndices = readFromVFile(project, vFile);
45     if (fromIndices != null) {
46       return fromIndices;
47     }
48
49     if (!canHaveStub(vFile)) {
50       return null;
51     }
52
53     try {
54       final FileContent fc = new FileContentImpl(vFile, vFile.contentsToByteArray());
55       fc.putUserData(FileBasedIndex.PROJECT, project);
56       final StubElement element = StubUpdatingIndex.buildStubTree(fc);
57       if (element instanceof PsiFileStub) {
58         return new StubTree((PsiFileStub)element);
59       }
60     }
61     catch (IOException e) {
62       throw new RuntimeException(e);
63     }
64
65     return null;
66   }
67
68   @Nullable
69   public StubTree readFromVFile(Project project, final VirtualFile vFile) {
70     if (DumbService.getInstance(project).isDumb()) {
71       return null;
72     }
73
74     final int id = Math.abs(FileBasedIndex.getFileId(vFile));
75     if (id > 0) {
76       final List<SerializedStubTree> datas = FileBasedIndex.getInstance().getValues(StubUpdatingIndex.INDEX_ID, id, GlobalSearchScopes
77           .fileScope(project, vFile));
78       final int size = datas.size();
79
80       if (size == 1) {
81         StubElement stub = datas.get(0).getStub();
82         return new StubTree((PsiFileStub)stub);
83       }
84       else if (size != 0) {
85         LOG.error("Twin stubs: " + vFile.getPresentableUrl() + " has " + size + " stub versions. Should only have one. id=" + id);
86
87         ApplicationManager.getApplication().invokeLater(new Runnable() {
88           public void run() {
89             final Document doc = FileDocumentManager.getInstance().getCachedDocument(vFile);
90             if (doc != null) {
91               FileDocumentManager.getInstance().saveDocument(doc);
92             }
93           }
94         }, ModalityState.NON_MODAL);
95
96         FileBasedIndex.getInstance().requestReindex(vFile);
97       }
98     }
99
100     return null;
101   }
102
103   @Override
104   public void rebuildStubTree(VirtualFile virtualFile) {
105     FileBasedIndex.getInstance().requestReindex(virtualFile);
106   }
107
108   @Override
109   public long getStubTreeTimestamp(VirtualFile vFile) {
110     return IndexingStamp.getIndexStamp(vFile, StubUpdatingIndex.INDEX_ID);
111   }
112
113   @Override
114   public boolean canHaveStub(VirtualFile file) {
115     return StubUpdatingIndex.canHaveStub(file);
116   }
117 }