예제 #1
0
 protected static void clearRelativeOffsets(TreeElement element) {
   TreeElement cur = element;
   while (cur != null && cur.myStartOffsetInParent != -1) {
     cur.myStartOffsetInParent = -1;
     cur = cur.getTreeNext();
   }
 }
예제 #2
0
  @Override
  public int getStartOffset() {
    int result = 0;
    TreeElement current = this;
    while (current.myParent != null) {
      result += current.getStartOffsetInParent();
      current = current.myParent;
    }

    return result;
  }
예제 #3
0
  @Override
  public Object clone() {
    TreeElement clone = (TreeElement) super.clone();
    synchronized (PsiLock.LOCK) {
      clone.myNextSibling = null;
      clone.myPrevSibling = null;
      clone.myParent = null;
      clone.myStartOffsetInParent = -1;
    }

    return clone;
  }
예제 #4
0
 public void replaceChildInternal(@NotNull ASTNode child, @NotNull TreeElement newElement) {
   if (newElement.getElementType() == JavaElementType.IMPORT_LIST) {
     LOG.assertTrue(child.getElementType() == JavaElementType.IMPORT_LIST);
     if (newElement.getFirstChildNode() == null) { // empty import list
       ASTNode next = child.getTreeNext();
       if (next != null && next.getElementType() == TokenType.WHITE_SPACE) {
         removeChild(next);
       }
     }
   }
   super.replaceChildInternal(child, newElement);
 }
예제 #5
0
  public PsiManagerEx getManager() {
    TreeElement element;
    for (element = this; element.getTreeParent() != null; element = element.getTreeParent()) {}

    if (element instanceof FileElement) { // TODO!!
      return element.getManager();
    } else {
      if (getTreeParent() != null) {
        return getTreeParent().getManager();
      }
      return null;
    }
  }
예제 #6
0
  @Nullable
  public static ASTNode findDocComment(@NotNull CompositeElement element) {
    TreeElement node = element.getFirstChildNode();
    while (node != null
        && (isWhitespaceOrComment(node) && !(node.getPsi() instanceof PsiDocComment))) {
      node = node.getTreeNext();
    }

    if (node != null && node.getElementType() == JavaDocElementType.DOC_COMMENT) {
      return node;
    } else {
      return null;
    }
  }
예제 #7
0
  protected final void rawInsertAfterMeWithoutNotifications(TreeElement firstNew) {
    firstNew.rawRemoveUpToWithoutNotifications(null, false);
    final CompositeElement p = getTreeParent();
    final TreeElement treeNext = getTreeNext();
    firstNew.setTreePrev(this);
    setTreeNext(firstNew);
    while (true) {
      final TreeElement n = firstNew.getTreeNext();
      assert n != this : "Attempt to create cycle";
      firstNew.setTreeParent(p);
      if (n == null) break;
      firstNew = n;
    }

    if (treeNext == null) {
      if (p != null) {
        firstNew.setTreeParent(p);
        p.setLastChildNode(firstNew);
      }
    } else {
      firstNew.setTreeNext(treeNext);
      treeNext.setTreePrev(firstNew);
    }
    DebugUtil.checkTreeStructure(this);
  }
  @Override
  public ASTNode parseContents(ASTNode chameleon) {
    final CharTable table = SharedImplUtil.findCharTableByTree(chameleon);
    final FileElement treeElement =
        new DummyHolder(((TreeElement) chameleon).getManager(), null, table).getTreeElement();
    final PsiFile file = (PsiFile) TreeUtil.getFileElement((TreeElement) chameleon).getPsi();
    PsiFile originalFile = file.getOriginalFile();

    final TemplateLanguageFileViewProvider viewProvider =
        (TemplateLanguageFileViewProvider) originalFile.getViewProvider();

    final Language language = getTemplateFileLanguage(viewProvider);
    final CharSequence chars = chameleon.getChars();

    final PsiFile templateFile = createTemplateFile(file, language, chars, viewProvider);

    final TreeElement parsed = ((PsiFileImpl) templateFile).calcTreeElement();
    Lexer langLexer =
        LanguageParserDefinitions.INSTANCE.forLanguage(language).createLexer(file.getProject());
    final Lexer lexer =
        new MergingLexerAdapter(
            new TemplateBlackAndWhiteLexer(
                createBaseLexer(viewProvider),
                langLexer,
                myTemplateElementType,
                myOuterElementType),
            TokenSet.create(myTemplateElementType, myOuterElementType));
    lexer.start(chars);
    insertOuters(parsed, lexer, table);

    if (parsed != null) {
      final TreeElement element = parsed.getFirstChildNode();
      if (element != null) {
        ((CompositeElement) parsed).rawRemoveAllChildren();
        treeElement.rawAddChildren(element);
      }
    }

    treeElement.subtreeChanged();
    TreeElement childNode = treeElement.getFirstChildNode();

    DebugUtil.checkTreeStructure(parsed);
    DebugUtil.checkTreeStructure(treeElement);
    DebugUtil.checkTreeStructure(chameleon);
    DebugUtil.checkTreeStructure(file.getNode());
    DebugUtil.checkTreeStructure(originalFile.getNode());

    return childNode;
  }
  @Override
  public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) {
    boolean needToAddNewline = false;
    if (first == last && first.getElementType() == DOC_TAG) {
      if (anchor == null) {
        anchor = getLastChildNode(); // this is a '*/'
        final ASTNode prevBeforeWS =
            TreeUtil.skipElementsBack(anchor.getTreePrev(), ElementType.JAVA_WHITESPACE_BIT_SET);
        if (prevBeforeWS != null) {
          anchor = prevBeforeWS;
          before = Boolean.FALSE;
        } else {
          before = Boolean.TRUE;
        }
        needToAddNewline = true;
      }
      if (anchor.getElementType() != DOC_TAG) {
        final CharTable charTable = SharedImplUtil.findCharTableByTree(this);
        final TreeElement newLine =
            Factory.createSingleLeafElement(DOC_COMMENT_DATA, "\n", 0, 1, charTable, getManager());
        final TreeElement leadingAsterisk =
            Factory.createSingleLeafElement(
                DOC_COMMENT_LEADING_ASTERISKS, "*", 0, 1, charTable, getManager());
        final TreeElement commentData =
            Factory.createSingleLeafElement(DOC_COMMENT_DATA, " ", 0, 1, charTable, getManager());
        final TreeElement indentWS =
            Factory.createSingleLeafElement(DOC_COMMENT_DATA, " ", 0, 1, charTable, getManager());
        newLine.getTreeParent().addChild(indentWS);
        newLine.getTreeParent().addChild(leadingAsterisk);
        newLine.getTreeParent().addChild(commentData);
        super.addInternal(newLine, commentData, anchor, Boolean.FALSE);

        anchor = commentData;
        before = Boolean.FALSE;
      } else {
        needToAddNewline = true;
      }
    }
    if (before) anchor.getTreeParent().addChildren(first, last.getTreeNext(), anchor);
    else anchor.getTreeParent().addChildren(first, last.getTreeNext(), anchor.getTreeNext());

    if (needToAddNewline) {
      if (first.getTreePrev() != null && first.getTreePrev().getElementType() == DOC_TAG) {
        addNewLineToTag((CompositeElement) first.getTreePrev(), getProject());
      }
      if (first.getTreeNext() != null && first.getTreeNext().getElementType() == DOC_TAG) {
        addNewLineToTag((CompositeElement) first, getProject());
      } else {
        removeEndingAsterisksFromTag((CompositeElement) first);
      }
    }
    return first;
  }
  public static boolean containsWhiteSpacesOnly(@Nullable ASTNode node) {
    if (node == null) return false;

    final boolean[] spacesOnly = {true};
    ((TreeElement) node)
        .acceptTree(
            new RecursiveTreeElementWalkingVisitor() {
              @Override
              public void visitComposite(CompositeElement composite) {
                if (!spacesOnly(composite)) {
                  super.visitComposite(composite);
                }
              }

              @Override
              public void visitLeaf(LeafElement leaf) {
                if (!spacesOnly(leaf)) {
                  spacesOnly[0] = false;
                  stopWalking();
                }
              }
            });

    return spacesOnly[0];
  }
예제 #11
0
  @Override
  public PsiElement getMirror() {
    TreeElement mirrorTreeElement = myMirrorFileElement;
    if (mirrorTreeElement == null) {
      synchronized (myMirrorLock) {
        mirrorTreeElement = myMirrorFileElement;
        if (mirrorTreeElement == null) {
          VirtualFile file = getVirtualFile();
          PsiClass[] classes = getClasses();
          String fileName =
              (classes.length > 0 ? classes[0].getName() : file.getNameWithoutExtension())
                  + JavaFileType.DOT_DEFAULT_EXTENSION;

          final Document document = FileDocumentManager.getInstance().getDocument(file);
          assert document != null : file.getUrl();

          CharSequence mirrorText = document.getImmutableCharSequence();
          boolean internalDecompiler = StringUtil.startsWith(mirrorText, BANNER);
          PsiFileFactory factory = PsiFileFactory.getInstance(getManager().getProject());
          PsiFile mirror =
              factory.createFileFromText(fileName, JavaLanguage.INSTANCE, mirrorText, false, false);
          mirror.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, getLanguageLevel());

          mirrorTreeElement = SourceTreeToPsiMap.psiToTreeNotNull(mirror);
          try {
            final TreeElement finalMirrorTreeElement = mirrorTreeElement;
            ProgressManager.getInstance()
                .executeNonCancelableSection(
                    new Runnable() {
                      @Override
                      public void run() {
                        setMirror(finalMirrorTreeElement);
                        putUserData(CLS_DOCUMENT_LINK_KEY, document);
                      }
                    });
          } catch (InvalidMirrorException e) {
            //noinspection ThrowableResultOfMethodCallIgnored
            LOG.error(file.getUrl(), internalDecompiler ? e : wrapException(e, file));
          }

          ((PsiFileImpl) mirror).setOriginalFile(this);
          myMirrorFileElement = mirrorTreeElement;
        }
      }
    }
    return mirrorTreeElement.getPsi();
  }
  private static void addReferencesInRange(
      ArrayList<ASTNode> array, TreeElement parent, int startOffset, int endOffset) {
    if (parent.getElementType() == JavaElementType.JAVA_CODE_REFERENCE
        || parent.getElementType() == JavaElementType.REFERENCE_EXPRESSION) {
      array.add(parent);
      return;
    }

    if (parent.getPsi() instanceof PsiFile && JspPsiUtil.isInJspFile(parent.getPsi())) {
      final JspFile jspFile = JspPsiUtil.getJspFile(parent.getPsi());
      JspClass jspClass = (JspClass) jspFile.getJavaClass();
      addReferencesInRange(array, (TreeElement) jspClass.getNode(), startOffset, endOffset);
      return;
    }

    addReferencesInRangeForComposite(array, parent, startOffset, endOffset);
  }
예제 #13
0
  public final int getStartOffsetInParent() {
    if (myParent == null) return -1;
    int offsetInParent = myStartOffsetInParent;
    if (offsetInParent != -1) return offsetInParent;

    synchronized (START_OFFSET_LOCK) {
      TreeElement cur = this;
      offsetInParent = myStartOffsetInParent;
      if (offsetInParent != -1) return offsetInParent;

      ApplicationManager.getApplication().assertReadAccessAllowed();

      while (true) {
        TreeElement prev = cur.getTreePrev();
        if (prev == null) break;
        cur = prev;
        offsetInParent = cur.myStartOffsetInParent;
        if (offsetInParent != -1) break;
      }

      if (offsetInParent == -1) {
        cur.myStartOffsetInParent = offsetInParent = 0;
      }

      while (cur != this) {
        TreeElement next = cur.getTreeNext();
        offsetInParent += cur.getTextLength();
        next.myStartOffsetInParent = offsetInParent;
        cur = next;
      }
      return offsetInParent;
    }
  }
  private static boolean spacesOnly(@Nullable TreeElement node) {
    if (node == null) return false;

    if (isWhitespaceOrEmpty(node)) return true;
    PsiElement psi = node.getPsi();
    if (psi == null) {
      return false;
    }
    Language language = psi.getLanguage();
    return WhiteSpaceFormattingStrategyFactory.getStrategy(language).containsWhitespacesOnly(node);
  }
예제 #15
0
 public PomModelEvent runInner() throws IncorrectOperationException {
   final ASTNode anchor = expandTag();
   if (myChild.getElementType() == XmlElementType.XML_TAG) {
     // compute where to insert tag according to DTD or XSD
     final XmlElementDescriptor parentDescriptor = getDescriptor();
     final XmlTag[] subTags = getSubTags();
     final PsiElement declaration =
         parentDescriptor != null ? parentDescriptor.getDeclaration() : null;
     // filtring out generated dtds
     if (declaration != null
         && declaration.getContainingFile() != null
         && declaration.getContainingFile().isPhysical()
         && subTags.length > 0) {
       final XmlElementDescriptor[] childElementDescriptors =
           parentDescriptor.getElementsDescriptors(XmlTagImpl.this);
       int subTagNum = -1;
       for (final XmlElementDescriptor childElementDescriptor : childElementDescriptors) {
         final String childElementName = childElementDescriptor.getName();
         while (subTagNum < subTags.length - 1
             && subTags[subTagNum + 1].getName().equals(childElementName)) {
           subTagNum++;
         }
         if (childElementName.equals(
             XmlChildRole.START_TAG_NAME_FINDER.findChild(myChild).getText())) {
           // insert child just after anchor
           // insert into the position specified by index
           if (subTagNum >= 0) {
             final ASTNode subTag = (ASTNode) subTags[subTagNum];
             if (subTag.getTreeParent() != XmlTagImpl.this) {
               // in entity
               final XmlEntityRef entityRef =
                   PsiTreeUtil.getParentOfType(subTags[subTagNum], XmlEntityRef.class);
               throw new IncorrectOperationException(
                   "Can't insert subtag to the entity. Entity reference text: "
                       + (entityRef == null ? "" : entityRef.getText()));
             }
             myNewElement =
                 XmlTagImpl.super.addInternal(myChild, myChild, subTag, Boolean.FALSE);
           } else {
             final ASTNode child = XmlChildRole.START_TAG_END_FINDER.findChild(XmlTagImpl.this);
             myNewElement = XmlTagImpl.super.addInternal(myChild, myChild, child, Boolean.FALSE);
           }
           return null;
         }
       }
     } else {
       final ASTNode child = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(XmlTagImpl.this);
       myNewElement = XmlTagImpl.super.addInternal(myChild, myChild, child, Boolean.TRUE);
       return null;
     }
   }
   myNewElement = XmlTagImpl.super.addInternal(myChild, myChild, anchor, Boolean.TRUE);
   return null;
 }
예제 #16
0
  public void rawRemove() {
    final TreeElement next = getTreeNext();
    final CompositeElement parent = getTreeParent();
    final TreeElement prev = getTreePrev();

    if (prev != null) {
      prev.setTreeNext(next);
    } else if (parent != null) {
      parent.setFirstChildNode(next);
    }

    if (next != null) {
      next.setTreePrev(prev);
    } else if (parent != null) {
      parent.setLastChildNode(prev);
    }

    DebugUtil.checkTreeStructure(parent);
    DebugUtil.checkTreeStructure(prev);
    DebugUtil.checkTreeStructure(next);

    invalidate();
  }
  public ASTNode encodeXmlTextContents(String displayText, PsiElement text) {
    final PsiFile containingFile = text.getContainingFile();
    CharTable charTable = SharedImplUtil.findCharTableByTree(text.getNode());
    final FileElement dummyParent =
        DummyHolderFactory.createHolder(text.getManager(), null, charTable).getTreeElement();
    final XmlTag rootTag =
        ((XmlFile)
                PsiFileFactory.getInstance(containingFile.getProject())
                    .createFileFromText("a.xml", "<a>" + displayText + "</a>"))
            .getRootTag();

    assert rootTag != null;
    final XmlTagChild[] tagChildren = rootTag.getValue().getChildren();

    final XmlTagChild child = tagChildren.length > 0 ? tagChildren[0] : null;
    LOG.assertTrue(child != null, "Child is null for tag: " + rootTag.getText());

    final TreeElement element = (TreeElement) child.getNode();
    ((TreeElement) tagChildren[tagChildren.length - 1].getNode().getTreeNext()).rawRemoveUpToLast();
    dummyParent.rawAddChildren(element);
    TreeUtil.clearCaches(dummyParent);
    return element.getFirstChildNode();
  }
  private static void addReferencesInRangeForComposite(
      final ArrayList<ASTNode> array,
      final TreeElement parent,
      final int startOffset,
      final int endOffset) {
    int offset = 0;
    for (TreeElement child = parent.getFirstChildNode();
        child != null;
        child = child.getTreeNext()) {
      int length = child.getTextLength();

      if (startOffset <= offset + length && offset <= endOffset) {
        final IElementType type = child.getElementType();

        if (type == JavaElementType.JAVA_CODE_REFERENCE
            || type == JavaElementType.REFERENCE_EXPRESSION) {
          array.add(child);
        } else {
          addReferencesInRangeForComposite(array, child, startOffset - offset, endOffset - offset);
        }
      }
      offset += length;
    }
  }
  @Override
  public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) {
    if (first.getElementType() == NAME_VALUE_PAIR && last.getElementType() == NAME_VALUE_PAIR) {
      final CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this);
      ASTNode lparenth = findChildByRole(ChildRole.LPARENTH);
      if (lparenth == null) {
        LeafElement created =
            Factory.createSingleLeafElement(LPARENTH, "(", 0, 1, treeCharTab, getManager());
        super.addInternal(created, created, getFirstChildNode(), true);
      }
      ASTNode rparenth = findChildByRole(ChildRole.RPARENTH);
      if (rparenth == null) {
        LeafElement created =
            Factory.createSingleLeafElement(RPARENTH, ")", 0, 1, treeCharTab, getManager());
        super.addInternal(created, created, getLastChildNode(), false);
      }

      final ASTNode[] nodes = getChildren(NAME_VALUE_PAIR_BIT_SET);
      if (nodes.length == 1) {
        final ASTNode node = nodes[0];
        if (node instanceof PsiNameValuePair) {
          final PsiNameValuePair pair = (PsiNameValuePair) node;
          if (pair.getName() == null) {
            final String text = pair.getValue().getText();
            try {
              final PsiAnnotation annotation =
                  JavaPsiFacade.getInstance(getProject())
                      .getElementFactory()
                      .createAnnotationFromText("@AAA(value = " + text + ")", null);
              replaceChild(node, annotation.getParameterList().getAttributes()[0].getNode());
            } catch (IncorrectOperationException e) {
              LOG.error(e);
            }
          }
        }
      }

      if (anchor == null && before != null) {
        anchor = findChildByRole(before.booleanValue() ? ChildRole.RPARENTH : ChildRole.LPARENTH);
      }
    }

    return super.addInternal(first, last, anchor, before);
  }
예제 #20
0
  public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean beforeB) {
    TreeElement firstAppended = null;
    boolean before = beforeB == null || beforeB.booleanValue();
    try {
      TreeElement next;
      do {
        next = first.getTreeNext();

        if (firstAppended == null) {
          firstAppended = addInternal(first, anchor, before);
          anchor = firstAppended;
        } else {
          anchor = addInternal(first, anchor, false);
        }
      } while (first != last && (first = next) != null);
    } catch (IncorrectOperationException ignored) {
    } finally {
      clearCaches();
    }
    return firstAppended;
  }
  private void insertOuters(TreeElement root, Lexer lexer, final CharTable table) {
    TreePatcher patcher = TREE_PATCHER.forLanguage(root.getPsi().getLanguage());

    int treeOffset = 0;
    LeafElement leaf = TreeUtil.findFirstLeaf(root);
    while (lexer.getTokenType() != null) {
      IElementType tt = lexer.getTokenType();
      if (tt != myTemplateElementType) {
        while (leaf != null && treeOffset < lexer.getTokenStart()) {
          treeOffset += leaf.getTextLength();
          if (treeOffset > lexer.getTokenStart()) {
            leaf =
                patcher.split(
                    leaf, leaf.getTextLength() - (treeOffset - lexer.getTokenStart()), table);
            treeOffset = lexer.getTokenStart();
          }
          leaf = (LeafElement) TreeUtil.nextLeaf(leaf);
        }

        if (leaf == null) break;

        final OuterLanguageElementImpl newLeaf =
            createOuterLanguageElement(lexer, table, myOuterElementType);
        patcher.insert(leaf.getTreeParent(), leaf, newLeaf);
        leaf.getTreeParent().subtreeChanged();
        leaf = newLeaf;
      }
      lexer.advance();
    }

    if (lexer.getTokenType() != null) {
      assert lexer.getTokenType() != myTemplateElementType;
      final OuterLanguageElementImpl newLeaf =
          createOuterLanguageElement(lexer, table, myOuterElementType);
      ((CompositeElement) root).rawAddChildren(newLeaf);
      ((CompositeElement) root).subtreeChanged();
    }
  }
예제 #22
0
  public void rawInsertBeforeMe(@NotNull TreeElement firstNew) {
    final TreeElement anchorPrev = getTreePrev();
    if (anchorPrev == null) {
      firstNew.rawRemoveUpToLast();
      final CompositeElement p = getTreeParent();
      if (p != null) p.setFirstChildNode(firstNew);
      while (true) {
        final TreeElement treeNext = firstNew.getTreeNext();
        assert treeNext != this : "Attempt to create cycle";
        firstNew.setTreeParent(p);
        if (treeNext == null) break;
        firstNew = treeNext;
      }
      setTreePrev(firstNew);
      firstNew.setTreeNext(this);
      if (p != null) {
        p.subtreeChanged();
      }
    } else anchorPrev.rawInsertAfterMe(firstNew);

    DebugUtil.checkTreeStructure(this);
  }
예제 #23
0
  private TreeElement addInternal(TreeElement child, ASTNode anchor, boolean before)
      throws IncorrectOperationException {
    final PomModel model = PomManager.getModel(getProject());
    if (anchor != null && child.getElementType() == XmlElementType.XML_TEXT) {
      XmlText psi = null;
      if (anchor.getPsi() instanceof XmlText) {
        psi = (XmlText) anchor.getPsi();
      } else {
        final ASTNode other = before ? anchor.getTreePrev() : anchor.getTreeNext();
        if (other != null && other.getPsi() instanceof XmlText) {
          before = !before;
          psi = (XmlText) other.getPsi();
        }
      }

      if (psi != null) {
        if (before) {
          psi.insertText(((XmlText) child.getPsi()).getValue(), 0);
        } else {
          psi.insertText(((XmlText) child.getPsi()).getValue(), psi.getValue().length());
        }
        return (TreeElement) psi.getNode();
      }
    }
    LOG.assertTrue(child.getPsi() instanceof XmlAttribute || child.getPsi() instanceof XmlTagChild);
    final InsertTransaction transaction;
    if (child.getElementType() == XmlElementType.XML_ATTRIBUTE) {
      transaction = new InsertAttributeTransaction(child, anchor, before, model);
    } else if (anchor == null) {
      transaction = getBodyInsertTransaction(child);
    } else {
      transaction = new GenericInsertTransaction(child, anchor, before);
    }
    model.runTransaction(transaction);
    return transaction.getFirstInserted();
  }
예제 #24
0
  private List<Pair<StubBasedPsiElementBase, CompositeElement>> calcStubAstBindings(
      final ASTNode root, final Document cachedDocument) {
    final StubTree stubTree = derefStub();
    if (stubTree == null) {
      return Collections.emptyList();
    }

    final Iterator<StubElement<?>> stubs = stubTree.getPlainList().iterator();
    stubs.next(); // Skip file stub;
    final List<Pair<StubBasedPsiElementBase, CompositeElement>> result =
        ContainerUtil.newArrayList();
    final StubBuilder builder = ((IStubFileElementType) getContentElementType()).getBuilder();

    LazyParseableElement.setSuppressEagerPsiCreation(true);
    try {
      ((TreeElement) root)
          .acceptTree(
              new RecursiveTreeElementWalkingVisitor() {
                @Override
                protected void visitNode(TreeElement node) {
                  CompositeElement parent = node.getTreeParent();
                  if (parent != null
                      && builder.skipChildProcessingWhenBuildingStubs(parent, node)) {
                    return;
                  }

                  IElementType type = node.getElementType();
                  if (type instanceof IStubElementType
                      && ((IStubElementType) type).shouldCreateStub(node)) {
                    if (!stubs.hasNext()) {
                      reportStubAstMismatch(
                          "Stub list is less than AST, last AST element: "
                              + node.getElementType()
                              + " "
                              + node,
                          stubTree,
                          cachedDocument);
                    }

                    final StubElement stub = stubs.next();
                    if (stub.getStubType() != node.getElementType()) {
                      reportStubAstMismatch(
                          "Stub and PSI element type mismatch in "
                              + getName()
                              + ": stub "
                              + stub
                              + ", AST "
                              + node.getElementType()
                              + "; "
                              + node,
                          stubTree,
                          cachedDocument);
                    }

                    PsiElement psi = stub.getPsi();
                    assert psi != null
                        : "Stub " + stub + " (" + stub.getClass() + ") has returned null PSI";
                    result.add(Pair.create((StubBasedPsiElementBase) psi, (CompositeElement) node));
                  }

                  super.visitNode(node);
                }
              });
    } finally {
      LazyParseableElement.setSuppressEagerPsiCreation(false);
    }
    if (stubs.hasNext()) {
      reportStubAstMismatch(
          "Stub list in " + getName() + " has more elements than PSI", stubTree, cachedDocument);
    }
    return result;
  }
  private static void createActionsMap(
      @NotNull List<ASTNode> astNodes,
      @NotNull FileViewProvider provider,
      @NotNull final TreeSet<PostprocessFormattingTask> rangesToProcess) {
    final Set<ASTNode> nodesToProcess = new HashSet<ASTNode>(astNodes);
    final Document document = provider.getDocument();
    if (document == null) {
      return;
    }
    for (final ASTNode node : astNodes) {
      nodesToProcess.remove(node);
      final FileElement fileElement = TreeUtil.getFileElement((TreeElement) node);
      if (fileElement == null || ((PsiFile) fileElement.getPsi()).getViewProvider() != provider)
        continue;
      final boolean isGenerated = CodeEditUtil.isNodeGenerated(node);

      ((TreeElement) node)
          .acceptTree(
              new RecursiveTreeElementVisitor() {
                boolean inGeneratedContext = !isGenerated;

                @Override
                protected boolean visitNode(TreeElement element) {
                  if (nodesToProcess.contains(element)) return false;

                  final boolean currentNodeGenerated = CodeEditUtil.isNodeGenerated(element);
                  CodeEditUtil.setNodeGenerated(element, false);
                  if (currentNodeGenerated && !inGeneratedContext) {
                    rangesToProcess.add(
                        new ReformatTask(document.createRangeMarker(element.getTextRange())));
                    inGeneratedContext = true;
                  }
                  if (!currentNodeGenerated && inGeneratedContext) {
                    if (element.getElementType() == TokenType.WHITE_SPACE) return false;
                    final int oldIndent = CodeEditUtil.getOldIndentation(element);
                    CodeEditUtil.setOldIndentation(element, -1);
                    LOG.assertTrue(
                        oldIndent >= 0,
                        "for not generated items old indentation must be defined: element "
                            + element);
                    for (TextRange indentRange : getEnabledRanges(element.getPsi())) {
                      rangesToProcess.add(
                          new ReindentTask(document.createRangeMarker(indentRange), oldIndent));
                    }
                    inGeneratedContext = false;
                  }
                  return true;
                }

                private Iterable<TextRange> getEnabledRanges(@NotNull PsiElement element) {
                  List<TextRange> disabledRanges = new ArrayList<TextRange>();
                  for (DisabledIndentRangesProvider rangesProvider :
                      DisabledIndentRangesProvider.EP_NAME.getExtensions()) {
                    Collection<TextRange> providedDisabledRanges =
                        rangesProvider.getDisabledIndentRanges(element);
                    if (providedDisabledRanges != null) {
                      disabledRanges.addAll(providedDisabledRanges);
                    }
                  }
                  return TextRangeUtil.excludeRanges(element.getTextRange(), disabledRanges);
                }

                @Override
                public void visitComposite(CompositeElement composite) {
                  boolean oldGeneratedContext = inGeneratedContext;
                  super.visitComposite(composite);
                  inGeneratedContext = oldGeneratedContext;
                }

                @Override
                public void visitLeaf(LeafElement leaf) {
                  boolean oldGeneratedContext = inGeneratedContext;
                  super.visitLeaf(leaf);
                  inGeneratedContext = oldGeneratedContext;
                }
              });
    }
  }
예제 #26
0
  // remove nodes from this[including] to end[excluding] from the parent
  protected final void rawRemoveUpToWithoutNotifications(TreeElement end, boolean invalidate) {
    if (this == end) return;

    final CompositeElement parent = getTreeParent();
    final TreeElement startPrev = getTreePrev();
    final TreeElement endPrev = end != null ? end.getTreePrev() : null;

    assert end == null || end.getTreeParent() == parent : "Trying to remove non-child";

    if (end != null) {
      TreeElement element;
      for (element = this; element != end && element != null; element = element.getTreeNext()) ;
      assert element == end : end + " is not successor of " + this + " in the .getTreeNext() chain";
    }
    if (parent != null) {
      if (this == parent.getFirstChildNode()) {
        parent.setFirstChildNode(end);
      }
      if (end == null) {
        parent.setLastChildNode(startPrev);
      }
    }
    if (startPrev != null) {
      startPrev.setTreeNext(end);
    }
    if (end != null) {
      end.setTreePrev(startPrev);
    }

    setTreePrev(null);
    if (endPrev != null) {
      endPrev.setTreeNext(null);
    }

    if (parent != null) {
      for (TreeElement element = this; element != null; element = element.getTreeNext()) {
        element.setTreeParent(null);
        if (invalidate) {
          element.onInvalidated();
        }
      }
    }

    DebugUtil.checkTreeStructure(parent);
    DebugUtil.checkTreeStructure(this);
  }
  public TreeElement process(TreeElement element, boolean addImports, boolean uncompleteCode) {
    IElementType elementType = element.getElementType();
    if (elementType == JavaElementType.JAVA_CODE_REFERENCE
        || elementType == JavaElementType.REFERENCE_EXPRESSION) {
      final IElementType parentElementType = element.getTreeParent().getElementType();
      if (elementType == JavaElementType.JAVA_CODE_REFERENCE
          || parentElementType == JavaElementType.REFERENCE_EXPRESSION
          || parentElementType == JavaElementType.METHOD_REF_EXPRESSION
          || uncompleteCode) {
        final PsiJavaCodeReferenceElement ref =
            (PsiJavaCodeReferenceElement) SourceTreeToPsiMap.treeElementToPsi(element);
        final PsiReferenceParameterList parameterList = ref.getParameterList();
        if (parameterList != null) {
          final PsiTypeElement[] typeParameters = parameterList.getTypeParameterElements();
          for (PsiTypeElement typeParameter : typeParameters) {
            process(
                (TreeElement) SourceTreeToPsiMap.psiElementToTree(typeParameter),
                addImports,
                uncompleteCode);
          }
        }

        boolean rightKind = true;
        if (elementType == JavaElementType.JAVA_CODE_REFERENCE) {
          int kind = ((PsiJavaCodeReferenceElementImpl) element).getKind();
          rightKind =
              kind == PsiJavaCodeReferenceElementImpl.CLASS_NAME_KIND
                  || kind == PsiJavaCodeReferenceElementImpl.CLASS_OR_PACKAGE_NAME_KIND;
        }

        if (rightKind) {
          boolean isInsideDocComment =
              TreeUtil.findParent(element, JavaDocElementType.DOC_COMMENT) != null;
          boolean isShort = !((SourceJavaCodeReference) element).isQualified();
          if (!makeFQ(isInsideDocComment)) {
            if (isShort) return element; // short name already, no need to change
          }
          PsiElement refElement;
          if (!uncompleteCode) {
            refElement = ref.resolve();
          } else {
            PsiResolveHelper helper =
                JavaPsiFacade.getInstance(element.getManager().getProject()).getResolveHelper();
            refElement =
                helper.resolveReferencedClass(
                    ((SourceJavaCodeReference) element).getClassNameText(),
                    SourceTreeToPsiMap.treeElementToPsi(element));
          }
          if (refElement instanceof PsiClass) {
            if (makeFQ(isInsideDocComment)) {
              String qName = ((PsiClass) refElement).getQualifiedName();
              if (qName == null) return element;
              PsiImportHolder file =
                  (PsiImportHolder)
                      SourceTreeToPsiMap.treeElementToPsi(element).getContainingFile();
              if (file instanceof PsiJavaFile
                  && ImportHelper.isImplicitlyImported(qName, (PsiJavaFile) file)) {
                if (isShort) return element;
                return (TreeElement)
                    makeShortReference(
                        (CompositeElement) element, (PsiClass) refElement, addImports);
              }
              if (file instanceof PsiJavaFile) {
                String thisPackageName = ((PsiJavaFile) file).getPackageName();
                if (ImportHelper.hasPackage(qName, thisPackageName)) {
                  if (!isShort) {
                    return (TreeElement)
                        makeShortReference(
                            (CompositeElement) element, (PsiClass) refElement, addImports);
                  }
                }
              }
              return (TreeElement) replaceReferenceWithFQ(element, (PsiClass) refElement);
            } else {
              int oldLength = element.getTextLength();
              TreeElement treeElement =
                  (TreeElement)
                      makeShortReference(
                          (CompositeElement) element, (PsiClass) refElement, addImports);
              if (treeElement.getTextLength() == oldLength
                  && ((PsiClass) refElement).getContainingClass() != null) {
                PsiElement qualifier = ref.getQualifier();
                if (qualifier instanceof PsiJavaCodeReferenceElement
                    && ((PsiJavaCodeReferenceElement) qualifier).resolve() instanceof PsiClass) {
                  process((TreeElement) qualifier.getNode(), addImports, uncompleteCode);
                }
              }
              return treeElement;
            }
          }
        }
      }
    }

    for (TreeElement child = element.getFirstChildNode();
        child != null;
        child = child.getTreeNext()) {
      child = process(child, addImports, uncompleteCode);
    }

    return element;
  }
  private static void createActionsMap(
      final List<ASTNode> astNodes,
      final FileViewProvider provider,
      final TreeSet<PostprocessFormattingTask> rangesToProcess) {
    final Set<ASTNode> nodesToProcess = new HashSet<ASTNode>(astNodes);
    final Document document = provider.getDocument();
    for (final ASTNode node : astNodes) {
      nodesToProcess.remove(node);
      final FileElement fileElement = TreeUtil.getFileElement((TreeElement) node);
      if (fileElement == null || ((PsiFile) fileElement.getPsi()).getViewProvider() != provider)
        continue;
      final boolean isGenerated = CodeEditUtil.isNodeGenerated(node);

      ((TreeElement) node)
          .acceptTree(
              new RecursiveTreeElementVisitor() {
                boolean inGeneratedContext = !isGenerated;

                protected boolean visitNode(TreeElement element) {
                  if (nodesToProcess.contains(element)) return false;
                  if (CodeEditUtil.isPostponedFormattingDisabled(element)) return false;

                  final boolean currentNodeGenerated = CodeEditUtil.isNodeGenerated(element);
                  CodeEditUtil.setNodeGenerated(element, false);
                  if (currentNodeGenerated && !inGeneratedContext) {
                    rangesToProcess.add(
                        new ReformatTask(document.createRangeMarker(element.getTextRange())));
                    inGeneratedContext = true;
                  }
                  if (!currentNodeGenerated && inGeneratedContext) {
                    if (element.getElementType() == TokenType.WHITE_SPACE) return false;
                    final int oldIndent = CodeEditUtil.getOldIndentation(element);
                    LOG.assertTrue(
                        oldIndent >= 0,
                        "for not generated items old indentation must be defined: element "
                            + element);
                    rangesToProcess.add(
                        new ReindentTask(
                            document.createRangeMarker(element.getTextRange()), oldIndent));
                    inGeneratedContext = false;
                  }
                  return true;
                }

                @Override
                public void visitComposite(CompositeElement composite) {
                  boolean oldGeneratedContext = inGeneratedContext;
                  super.visitComposite(composite);
                  inGeneratedContext = oldGeneratedContext;
                }

                @Override
                public void visitLeaf(LeafElement leaf) {
                  boolean oldGeneratedContext = inGeneratedContext;
                  super.visitLeaf(leaf);
                  inGeneratedContext = oldGeneratedContext;
                }
              });

      CodeEditUtil.enablePostponedFormattingInTree(node);
    }
  }