@Nullable public static PsiElement searchNonSpaceNonCommentBack(PsiElement element) { if (element == null || element.getNode() == null) return null; ASTNode leftNeibour = TreeUtil.prevLeaf(element.getNode()); while (leftNeibour != null && (leftNeibour.getElementType() == TokenType.WHITE_SPACE || leftNeibour.getPsi() instanceof PsiComment)) { leftNeibour = TreeUtil.prevLeaf(leftNeibour); } return leftNeibour != null ? leftNeibour.getPsi() : null; }
public static void replaceLastWhiteSpace( final ASTNode astNode, final String whiteSpace, final TextRange textRange) { ASTNode lastWS = TreeUtil.findLastLeaf(astNode); if (lastWS == null) { return; } if (lastWS.getElementType() != TokenType.WHITE_SPACE) { lastWS = null; } if (lastWS != null && !lastWS.getTextRange().equals(textRange)) { return; } if (whiteSpace.isEmpty() && lastWS == null) { return; } if (lastWS != null && whiteSpace.isEmpty()) { lastWS.getTreeParent().removeRange(lastWS, null); return; } LeafElement whiteSpaceElement = ASTFactory.whitespace(whiteSpace); if (lastWS == null) { astNode.addChild(whiteSpaceElement, null); } else { ASTNode treeParent = lastWS.getTreeParent(); treeParent.replaceChild(lastWS, whiteSpaceElement); } }
public static <T> void diffTrees( @NotNull final ASTNode oldRoot, @NotNull final DiffTreeChangeBuilder<ASTNode, T> builder, @NotNull final ShallowNodeComparator<ASTNode, T> comparator, @NotNull final FlyweightCapableTreeStructure<T> newTreeStructure, @NotNull ProgressIndicator indicator) { TreeUtil.ensureParsedRecursivelyCheckingProgress(oldRoot, indicator); DiffTree.diff( createInterruptibleASTStructure(oldRoot, indicator), newTreeStructure, comparator, builder); }
@Override protected String replaceWithPsiInLeaf( final TextRange textRange, String whiteSpace, ASTNode leafElement) { if (!myCanModifyAllWhiteSpaces) { if (leafElement.getElementType() == TokenType.WHITE_SPACE) return null; LOG.assertTrue(leafElement.getPsi().isValid()); ASTNode prevNode = TreeUtil.prevLeaf(leafElement); if (prevNode != null) { IElementType type = prevNode.getElementType(); if (type == TokenType.WHITE_SPACE) { final String text = prevNode.getText(); final @NonNls String cdataStartMarker = "<![CDATA["; final int cdataPos = text.indexOf(cdataStartMarker); if (cdataPos != -1 && whiteSpace.indexOf(cdataStartMarker) == -1) { whiteSpace = mergeWsWithCdataMarker(whiteSpace, text, cdataPos); if (whiteSpace == null) return null; } prevNode = TreeUtil.prevLeaf(prevNode); type = prevNode != null ? prevNode.getElementType() : null; } final @NonNls String cdataEndMarker = "]]>"; if (type == XmlTokenType.XML_CDATA_END && whiteSpace.indexOf(cdataEndMarker) == -1) { final ASTNode at = findElementAt(prevNode.getStartOffset()); if (at != null && at.getPsi() instanceof PsiWhiteSpace) { final String s = at.getText(); final int cdataEndPos = s.indexOf(cdataEndMarker); whiteSpace = mergeWsWithCdataMarker(whiteSpace, s, cdataEndPos); leafElement = at; } else { whiteSpace = null; } if (whiteSpace == null) return null; } } } FormatterUtil.replaceWhiteSpace(whiteSpace, leafElement, TokenType.WHITE_SPACE, textRange); return whiteSpace; }
public StubTree calcStubTree() { FileElement fileElement = calcTreeElement(); synchronized (myStubFromTreeLock) { SoftReference<StubTree> ref = fileElement.getUserData(STUB_TREE_IN_PARSED_TREE); StubTree tree = SoftReference.dereference(ref); if (tree == null) { ApplicationManager.getApplication().assertReadAccessAllowed(); IElementType contentElementType = getContentElementType(); if (!(contentElementType instanceof IStubFileElementType)) { VirtualFile vFile = getVirtualFile(); String message = "ContentElementType: " + contentElementType + "; file: " + this + "\n\t" + "Boolean.TRUE.equals(getUserData(BUILDING_STUB)) = " + Boolean.TRUE.equals(getUserData(BUILDING_STUB)) + "\n\t" + "getTreeElement() = " + getTreeElement() + "\n\t" + "vFile instanceof VirtualFileWithId = " + (vFile instanceof VirtualFileWithId) + "\n\t" + "StubUpdatingIndex.canHaveStub(vFile) = " + StubTreeLoader.getInstance().canHaveStub(vFile); rebuildStub(); throw new AssertionError(message); } StubElement currentStubTree = ((IStubFileElementType) contentElementType).getBuilder().buildStubTree(this); if (currentStubTree == null) { throw new AssertionError( "Stub tree wasn't built for " + contentElementType + "; file: " + this); } tree = new StubTree((PsiFileStub) currentStubTree); tree.setDebugInfo("created in calcStubTree"); try { TreeUtil.bindStubsToTree(this, tree); } catch (TreeUtil.StubBindingException e) { rebuildStub(); throw new RuntimeException("Stub and PSI element type mismatch in " + getName(), e); } fileElement.putUserData(STUB_TREE_IN_PARSED_TREE, new SoftReference<StubTree>(tree)); } return tree; } }
@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; }
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(); } }
@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; }
static void registerProblem( BnfExpression choice, BnfExpression branch, String message, ProblemsHolder problemsHolder, LocalQuickFix... fixes) { TextRange textRange = branch.getTextRange(); if (textRange.isEmpty()) { ASTNode nextOr = TreeUtil.findSibling(branch.getNode(), BnfTypes.BNF_OP_OR); ASTNode prevOr = TreeUtil.findSiblingBackward(branch.getNode(), BnfTypes.BNF_OP_OR); int shift = choice.getTextRange().getStartOffset(); int startOffset = prevOr != null ? prevOr.getStartOffset() - shift : 0; TextRange range = new TextRange( startOffset, nextOr != null ? nextOr.getStartOffset() + 1 - shift : Math.min(startOffset + 2, choice.getTextLength())); problemsHolder.registerProblem(choice, range, message, fixes); } else { problemsHolder.registerProblem(branch, message, fixes); } }
private static void removeEndingAsterisksFromTag(CompositeElement tag) { ASTNode current = tag.getLastChildNode(); while (current != null && current.getElementType() == DOC_COMMENT_DATA) { current = current.getTreePrev(); } if (current != null && current.getElementType() == DOC_COMMENT_LEADING_ASTERISKS) { final ASTNode prevWhiteSpace = TreeUtil.skipElementsBack(current.getTreePrev(), ElementType.JAVA_WHITESPACE_BIT_SET); ASTNode toBeDeleted = prevWhiteSpace.getTreeNext(); while (toBeDeleted != null) { ASTNode next = toBeDeleted.getTreeNext(); tag.deleteChildInternal(toBeDeleted); toBeDeleted = next; } } }
/** * Tries to find previous node adjacent to the given node that has the same {@link * AlignmentInColumnsConfig#getTargetDeclarationTypes() target type}. * * @param baseNode base node to use * @param config current processing config * @param blankLinesToBeKeptOnReformat * @return previous node to the given base node that has that same type and is adjacent to it if * possible; <code>null</code> otherwise */ @SuppressWarnings({"StatementWithEmptyBody"}) @Nullable private static ASTNode getPreviousAdjacentNodeOfTargetType( ASTNode baseNode, AlignmentInColumnsConfig config, final double blankLinesToBeKeptOnReformat) { ASTNode nodeOfTargetType = deriveNodeOfTargetType(baseNode, config.getTargetDeclarationTypes()); if (nodeOfTargetType == null) { return null; } final ASTNode[] prev = new ASTNode[1]; findPreviousNode( config, baseNode, new NodeProcessor() { @Override public boolean targetTypeFound(ASTNode node) { prev[0] = node; return true; } @Override public boolean whitespaceFound(ASTNode node) { return blankLinesToBeKeptOnReformat > 0 && StringUtil.countChars(node.getText(), '\n') > 1; } }); if (prev[0] == null) return null; // ensure there are no non-whitespace, non-comment elements on the top level between baseNode // and the found one Pair<ASTNode, ASTNode> siblingParents = TreeUtil.findTopmostSiblingParents(prev[0], baseNode); if (siblingParents.first != null && siblingParents.second != null) { for (ASTNode each = siblingParents.second.getTreePrev(); each != null && each != siblingParents.first; each = each.getTreePrev()) { IElementType eachType = each.getElementType(); if (!config.getCommentTokenTypes().contains(eachType) && !config.getWhiteSpaceTokenTypes().contains(eachType)) return null; } } return deriveNodeOfTargetType(prev[0], TokenSet.create(nodeOfTargetType.getElementType())); }
public ASTNode findChildByRole(int role) { LOG.assertTrue(ChildRole.isUnique(role)); switch (role) { default: return null; case ChildRole.PACKAGE_KEYWORD: return findChildByType(JavaTokenType.PACKAGE_KEYWORD); case ChildRole.PACKAGE_REFERENCE: return findChildByType(JavaElementType.JAVA_CODE_REFERENCE); case ChildRole.CLOSING_SEMICOLON: return TreeUtil.findChildBackward(this, JavaTokenType.SEMICOLON); case ChildRole.MODIFIER_LIST: return findChildByType(JavaElementType.MODIFIER_LIST); } }
@Nullable public static ASTNode getPreviousNonWhitespaceLeaf(@Nullable ASTNode node) { if (node == null) return null; ASTNode treePrev = node.getTreePrev(); if (treePrev != null) { ASTNode candidate = TreeUtil.getLastChild(treePrev); if (candidate != null && !isWhitespaceOrEmpty(candidate)) { return candidate; } else { return getPreviousNonWhitespaceLeaf(candidate); } } final ASTNode treeParent = node.getTreeParent(); if (treeParent == null || treeParent.getTreeParent() == null) { return null; } else { return getPreviousNonWhitespaceLeaf(treeParent); } }
private static Collection<String> suggestKeywords(PsiElement position) { TextRange posRange = position.getTextRange(); BnfFile posFile = (BnfFile) position.getContainingFile(); BnfRule statement = PsiTreeUtil.getTopmostParentOfType(position, BnfRule.class); final TextRange range; if (statement != null) { range = new TextRange(statement.getTextRange().getStartOffset(), posRange.getStartOffset()); } else { int offset = posRange.getStartOffset(); for (PsiElement cur = GrammarUtil.getDummyAwarePrevSibling(position); cur != null; cur = GrammarUtil.getDummyAwarePrevSibling(cur)) { if (cur instanceof BnfAttrs) offset = cur.getTextRange().getEndOffset(); else if (cur instanceof BnfRule) offset = cur.getTextRange().getStartOffset(); else continue; break; } range = new TextRange(offset, posRange.getStartOffset()); } final String text = range.isEmpty() ? CompletionInitializationContext.DUMMY_IDENTIFIER : range.substring(posFile.getText()); PsiFile file = PsiFileFactory.getInstance(posFile.getProject()) .createFileFromText("a.bnf", BnfLanguage.INSTANCE, text, true, false); int completionOffset = posRange.getStartOffset() - range.getStartOffset(); GeneratedParserUtilBase.CompletionState state = new GeneratedParserUtilBase.CompletionState(completionOffset) { @Override public String convertItem(Object o) { // we do not have other keywords return o instanceof String ? (String) o : null; } }; file.putUserData(GeneratedParserUtilBase.COMPLETION_STATE_KEY, state); TreeUtil.ensureParsed(file.getNode()); return state.items; }
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(); }
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; }
/** * This method searches ast node that could be reparsed incrementally and returns pair of target * reparseable node and new replacement node. Returns null if there is no any chance to make * incremental parsing. */ @Nullable public Couple<ASTNode> findReparseableRoots( @NotNull PsiFileImpl file, @NotNull TextRange changedPsiRange, @NotNull CharSequence newFileText) { Project project = file.getProject(); final FileElement fileElement = file.getTreeElement(); final CharTable charTable = fileElement.getCharTable(); int lengthShift = newFileText.length() - fileElement.getTextLength(); if (fileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) { // unable to perform incremental reparse for template data in JSP, or in exceptionally deep // trees return null; } final ASTNode leafAtStart = fileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); final ASTNode leafAtEnd = fileElement.findLeafElementAt( Math.min(changedPsiRange.getEndOffset(), fileElement.getTextLength() - 1)); ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : fileElement; Language baseLanguage = file.getViewProvider().getBaseLanguage(); while (node != null && !(node instanceof FileElement)) { IElementType elementType = node.getElementType(); if (elementType instanceof IReparseableElementType) { final TextRange textRange = node.getTextRange(); final IReparseableElementType reparseable = (IReparseableElementType) elementType; if (baseLanguage.isKindOf(reparseable.getLanguage()) && textRange.getLength() + lengthShift > 0) { final int start = textRange.getStartOffset(); final int end = start + textRange.getLength() + lengthShift; if (end > newFileText.length()) { reportInconsistentLength(file, newFileText, node, start, end); break; } CharSequence newTextStr = newFileText.subSequence(start, end); if (reparseable.isParsable(node.getTreeParent(), newTextStr, baseLanguage, project)) { ASTNode chameleon = reparseable.createNode(newTextStr); if (chameleon != null) { DummyHolder holder = DummyHolderFactory.createHolder( file.getManager(), null, node.getPsi(), charTable); holder.getTreeElement().rawAddChildren((TreeElement) chameleon); if (holder.getTextLength() != newTextStr.length()) { String details = ApplicationManager.getApplication().isInternal() ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";" : ""; LOG.error("Inconsistent reparse: " + details + " type=" + elementType); } return Couple.of(node, chameleon); } } } } node = node.getTreeParent(); } return null; }
@Override public ASTNode process( @NotNull ASTNode element, boolean addImports, boolean incompleteCode, boolean useFqInJavadoc, boolean useFqInCode) { IElementType elementType = element.getElementType(); if ((elementType == JavaElementType.JAVA_CODE_REFERENCE || elementType == JavaElementType.REFERENCE_EXPRESSION) && !isAnnotated(element)) { IElementType parentType = element.getTreeParent().getElementType(); if (elementType == JavaElementType.JAVA_CODE_REFERENCE || incompleteCode || parentType == JavaElementType.REFERENCE_EXPRESSION || parentType == JavaElementType.METHOD_REF_EXPRESSION) { PsiJavaCodeReferenceElement ref = (PsiJavaCodeReferenceElement) element.getPsi(); PsiReferenceParameterList parameterList = ref.getParameterList(); if (parameterList != null) { PsiTypeElement[] typeParameters = parameterList.getTypeParameterElements(); for (PsiTypeElement typeParameter : typeParameters) { process( typeParameter.getNode(), addImports, incompleteCode, useFqInJavadoc, useFqInCode); } } boolean rightKind = true; if (elementType == JavaElementType.JAVA_CODE_REFERENCE) { PsiJavaCodeReferenceElementImpl impl = (PsiJavaCodeReferenceElementImpl) element; int kind = impl.getKind(impl.getContainingFile()); rightKind = kind == PsiJavaCodeReferenceElementImpl.CLASS_NAME_KIND || kind == PsiJavaCodeReferenceElementImpl.CLASS_OR_PACKAGE_NAME_KIND; } if (rightKind) { // annotations may jump out of reference (see PsiJavaCodeReferenceImpl#setAnnotations()) // so they should be processed first List<PsiAnnotation> annotations = PsiTreeUtil.getChildrenOfTypeAsList(ref, PsiAnnotation.class); for (PsiAnnotation annotation : annotations) { process(annotation.getNode(), addImports, incompleteCode, useFqInJavadoc, useFqInCode); } boolean isInsideDocComment = TreeUtil.findParent(element, JavaDocElementType.DOC_COMMENT) != null; boolean isShort = !ref.isQualified(); if (isInsideDocComment ? !useFqInJavadoc : !useFqInCode) { if (isShort) return element; // short name already, no need to change } PsiElement refElement; if (!incompleteCode) { refElement = ref.resolve(); } else { PsiResolveHelper helper = JavaPsiFacade.getInstance(ref.getManager().getProject()).getResolveHelper(); final SourceJavaCodeReference reference = (SourceJavaCodeReference) element; refElement = helper.resolveReferencedClass(reference.getClassNameText(), ref); } if (refElement instanceof PsiClass) { PsiClass psiClass = (PsiClass) refElement; if (isInsideDocComment ? useFqInJavadoc : useFqInCode) { String qName = psiClass.getQualifiedName(); if (qName == null) return element; PsiFile file = ref.getContainingFile(); if (file instanceof PsiJavaFile) { if (ImportHelper.isImplicitlyImported(qName, (PsiJavaFile) file)) { if (isShort) return element; return makeShortReference((CompositeElement) element, psiClass, addImports); } String thisPackageName = ((PsiJavaFile) file).getPackageName(); if (ImportHelper.hasPackage(qName, thisPackageName)) { if (!isShort) { return makeShortReference((CompositeElement) element, psiClass, addImports); } } } return replaceReferenceWithFQ(element, psiClass); } else { int oldLength = element.getTextLength(); ASTNode treeElement = makeShortReference((CompositeElement) element, psiClass, addImports); if (treeElement.getTextLength() == oldLength && psiClass.getContainingClass() != null) { PsiElement qualifier = ref.getQualifier(); if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement) qualifier).resolve() instanceof PsiClass) { process( qualifier.getNode(), addImports, incompleteCode, useFqInJavadoc, useFqInCode); } } return treeElement; } } } } } for (ASTNode child = element.getFirstChildNode(); child != null; child = child.getTreeNext()) { //noinspection AssignmentToForLoopParameter child = process(child, addImports, incompleteCode, useFqInJavadoc, useFqInCode); } 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); } }
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; } }); } }