/platform/lang-impl/src/com/intellij/extapi/psi/StubPathBuilder.java

https://bitbucket.org/nbargnesi/idea · Java · 147 lines · 102 code · 27 blank · 18 comment · 34 complexity · 03301823295bc79c3590b14b97befdd9 MD5 · raw file

  1. /*
  2. * Copyright 2000-2009 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. /*
  17. * @author max
  18. */
  19. package com.intellij.extapi.psi;
  20. import com.intellij.lang.ASTNode;
  21. import com.intellij.openapi.util.Pair;
  22. import com.intellij.psi.PsiElement;
  23. import com.intellij.psi.PsiFile;
  24. import com.intellij.psi.StubBasedPsiElement;
  25. import com.intellij.psi.impl.source.PsiFileImpl;
  26. import com.intellij.psi.stubs.*;
  27. import org.jetbrains.annotations.Nullable;
  28. import java.util.List;
  29. public class StubPathBuilder {
  30. private StubPathBuilder() {
  31. }
  32. public static StubPath build(StubBasedPsiElement psi) {
  33. if (psi instanceof PsiFile) {
  34. return null;
  35. }
  36. final StubElement liveStub = psi.getStub();
  37. if (liveStub != null) {
  38. return build(liveStub);
  39. }
  40. return buildForPsi(psi, ((PsiFileImpl)psi.getContainingFile()).calcStubTree()).getFirst();
  41. }
  42. public static StubPath build(StubElement stub) {
  43. if (stub instanceof PsiFileStub || stub == null) {
  44. return null;
  45. }
  46. final IStubElementType type = stub.getStubType();
  47. return new StubPath(build(stub.getParentStub()), type.getId(stub), type);
  48. }
  49. private static Pair<StubPath, StubElement> buildForPsi(PsiElement psi, StubTree tree) {
  50. if (psi instanceof PsiFile) {
  51. return new Pair<StubPath, StubElement>(null, tree.getRoot());
  52. }
  53. if (psi instanceof StubBasedPsiElement) {
  54. final IStubElementType type = ((StubBasedPsiElement)psi).getElementType();
  55. if (type.shouldCreateStub(psi.getNode())) {
  56. final Pair<StubPath, StubElement> parentPair = buildForPsi(psi.getParent(), tree);
  57. final StubElement parentStub = parentPair.getSecond();
  58. final List<StubElement> childrenStubs = parentStub.getChildrenStubs();
  59. for (StubElement childStub : childrenStubs) {
  60. if (childStub.getPsi() == psi) {
  61. final IStubElementType type1 = childStub.getStubType();
  62. return new Pair<StubPath, StubElement>(new StubPath(parentPair.getFirst(), type1.getId(childStub), type1), childStub);
  63. }
  64. }
  65. return new Pair<StubPath, StubElement>(null, null);
  66. }
  67. }
  68. return buildForPsi(psi.getParent(), tree);
  69. }
  70. @Nullable
  71. public static PsiElement resolve(PsiFile file, StubPath path) {
  72. PsiFileImpl fileImpl = (PsiFileImpl)file;
  73. StubTree tree = fileImpl.getStubTree();
  74. boolean foreign = (tree == null);
  75. if (foreign) {
  76. tree = fileImpl.calcStubTree();
  77. }
  78. StubElement stub = resolveStub(tree, path);
  79. if (foreign) {
  80. final PsiElement cachedPsi = ((StubBase)stub).getCachedPsi();
  81. if (cachedPsi != null) return cachedPsi;
  82. final ASTNode ast = fileImpl.findTreeForStub(tree, stub);
  83. return ast != null ? ast.getPsi() : null;
  84. }
  85. else {
  86. return stub != null ? stub.getPsi() : null;
  87. }
  88. }
  89. @Nullable
  90. public static StubElement resolveStub(StubTree tree, StubPath path) {
  91. if (path == null) {
  92. return tree.getRoot();
  93. }
  94. StubElement parentStub = resolveStub(tree, path.getParentPath());
  95. if (parentStub == null) {
  96. return null;
  97. }
  98. final String id = path.getId();
  99. final IStubElementType type = (IStubElementType)path.getType();
  100. final List<StubElement> children = parentStub.getChildrenStubs();
  101. if (id.startsWith("#")) {
  102. int count = Integer.parseInt(id.substring(1));
  103. for (StubElement child : children) {
  104. if (child.getStubType() == type) {
  105. count--;
  106. if (count == 0) {
  107. return child;
  108. }
  109. }
  110. }
  111. return null;
  112. }
  113. for (StubElement child : children) {
  114. if (child.getStubType() == type && id.equals(type.getId(child))) {
  115. return child;
  116. }
  117. }
  118. return null;
  119. }
  120. }