private static void addNewLineToTag(CompositeElement tag, Project project) { LOG.assertTrue(tag != null && tag.getElementType() == DOC_TAG); ASTNode current = tag.getLastChildNode(); while (current != null && current.getElementType() == DOC_COMMENT_DATA && isWhitespaceCommentData(current)) { current = current.getTreePrev(); } if (current != null && current.getElementType() == DOC_COMMENT_LEADING_ASTERISKS) return; final CharTable treeCharTab = SharedImplUtil.findCharTableByTree(tag); final ASTNode newLine = Factory.createSingleLeafElement( DOC_COMMENT_DATA, "\n", 0, 1, treeCharTab, SharedImplUtil.getManagerByTree(tag)); tag.addChild(newLine, null); ASTNode leadingWhitespaceAnchor = null; if (JavaCodeStyleSettingsFacade.getInstance(project).isJavaDocLeadingAsterisksEnabled()) { final TreeElement leadingAsterisk = Factory.createSingleLeafElement( DOC_COMMENT_LEADING_ASTERISKS, "*", 0, 1, treeCharTab, SharedImplUtil.getManagerByTree(tag)); leadingWhitespaceAnchor = tag.addInternal(leadingAsterisk, leadingAsterisk, null, Boolean.TRUE); } final TreeElement commentData = Factory.createSingleLeafElement( DOC_COMMENT_DATA, " ", 0, 1, treeCharTab, SharedImplUtil.getManagerByTree(tag)); tag.addInternal(commentData, commentData, leadingWhitespaceAnchor, Boolean.TRUE); }
@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; }
@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); }
/** * There is a possible case that we want to adjust white space which is not represented at the * AST/PSI tree, e.g. we might have a multiline comment which uses tabs for inner lines indents * and want to replace them by spaces. There is no white space element then, the only leaf is the * comment itself. * * <p>This method allows such 'inner element modifications', i.e. it receives information on what * new text should be used at the target inner element range and performs corresponding * replacement by generating new leaf with adjusted text and replacing the old one by it. * * @param newWhiteSpaceText new text to use at the target inner element range * @param holder target range holder * @param whiteSpaceRange target range which text should be replaced by the given one */ public static void replaceInnerWhiteSpace( @NotNull final String newWhiteSpaceText, @NotNull final ASTNode holder, @NotNull final TextRange whiteSpaceRange) { final CharTable charTable = SharedImplUtil.findCharTableByTree(holder); StringBuilder newText = createNewLeafChars(holder, whiteSpaceRange, newWhiteSpaceText); LeafElement newElement = Factory.createSingleLeafElement( holder.getElementType(), newText, charTable, holder.getPsi().getManager()); holder.getTreeParent().replaceChild(holder, newElement); }
@NotNull public GrStatement addStatementBefore(@NotNull GrStatement element, @Nullable GrStatement anchor) throws IncorrectOperationException { if (anchor == null && getRBrace() == null) { throw new IncorrectOperationException(); } if (anchor != null && !this.equals(anchor.getParent())) { throw new IncorrectOperationException(); } final LeafElement nls = Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, getManager()); PsiElement actualAnchor = anchor == null ? getRBrace() : anchor; if (mayUseNewLinesAsSeparators()) { PsiElement prev = actualAnchor.getPrevSibling(); if (prev instanceof GrParameterList && prev.getTextLength() == 0 && prev.getPrevSibling() != null) { prev = prev.getPrevSibling(); } if (!PsiUtil.isLineFeed(prev)) { addBefore(nls.getPsi(), actualAnchor); } } element = (GrStatement) addBefore(element, actualAnchor); if (mayUseNewLinesAsSeparators()) { addBefore(nls.getPsi(), actualAnchor); } else { addBefore( Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, getManager()) .getPsi(), actualAnchor); } return element; }
public PomModelEvent runInner() { final String value = ((XmlAttribute) myChild).getValue(); final String name = ((XmlAttribute) myChild).getName(); if (myAnchor == null) { ASTNode startTagEnd = XmlChildRole.START_TAG_END_FINDER.findChild(XmlTagImpl.this); if (startTagEnd == null) startTagEnd = XmlChildRole.EMPTY_TAG_END_FINDER.findChild(XmlTagImpl.this); if (startTagEnd == null) { ASTNode anchor = getLastChildNode(); while (anchor instanceof PsiWhiteSpace) { anchor = anchor.getTreePrev(); } if (anchor instanceof PsiErrorElement) { final LeafElement token = Factory.createSingleLeafElement( XmlTokenType.XML_EMPTY_ELEMENT_END, "/>", 0, 2, SharedImplUtil.findCharTableByTree(anchor), getManager()); replaceChild(anchor, token); startTagEnd = token; } } if (startTagEnd == null) { ASTNode anchor = XmlChildRole.START_TAG_NAME_FINDER.findChild(XmlTagImpl.this); myFirstInserted = XmlTagImpl.super.addInternal(myChild, myChild, anchor, Boolean.FALSE); } else { myFirstInserted = XmlTagImpl.super.addInternal(myChild, myChild, startTagEnd, Boolean.TRUE); } } else { myFirstInserted = XmlTagImpl.super.addInternal(myChild, myChild, myAnchor, Boolean.valueOf(myBefore)); } return XmlAttributeSetImpl.createXmlAttributeSet(myModel, XmlTagImpl.this, name, value); }
private static void generateRaw(final @NotNull XmlTag newTag) { XmlElementDescriptor selected = newTag.getDescriptor(); if (selected == null) return; switch (selected.getContentType()) { case XmlElementDescriptor.CONTENT_TYPE_EMPTY: newTag.collapseIfEmpty(); ASTNode node = newTag.getNode(); assert node != null; ASTNode elementEnd = node.findChildByType(XmlTokenType.XML_EMPTY_ELEMENT_END); if (elementEnd == null) { LeafElement emptyTagEnd = Factory.createSingleLeafElement( XmlTokenType.XML_EMPTY_ELEMENT_END, "/>", 0, 2, null, newTag.getManager()); node.addChild(emptyTagEnd); } break; case XmlElementDescriptor.CONTENT_TYPE_MIXED: newTag.getValue().setText(""); } for (XmlAttributeDescriptor descriptor : selected.getAttributesDescriptors(newTag)) { if (descriptor.isRequired()) { newTag.setAttribute(descriptor.getName(), ""); } } List<XmlElementDescriptor> tags = getRequiredSubTags(selected); for (XmlElementDescriptor descriptor : tags) { if (descriptor == null) { XmlTag tag = XmlElementFactory.getInstance(newTag.getProject()) .createTagFromText("<", newTag.getLanguage()); newTag.addSubTag(tag, false); } else { XmlTag subTag = newTag.addSubTag(createTag(newTag, descriptor), false); generateRaw(subTag); } } }
public static void replaceWhiteSpace( final String whiteSpace, final ASTNode leafElement, final IElementType whiteSpaceToken, @Nullable final TextRange textRange) { final CharTable charTable = SharedImplUtil.findCharTableByTree(leafElement); ASTNode treePrev = findPreviousWhiteSpace(leafElement, whiteSpaceToken); if (treePrev == null) { treePrev = getWsCandidate(leafElement); } if (treePrev != null && treePrev.getText().trim().isEmpty() && treePrev.getElementType() != whiteSpaceToken && treePrev.getTextLength() > 0 && !whiteSpace.isEmpty()) { LeafElement whiteSpaceElement = Factory.createSingleLeafElement( treePrev.getElementType(), whiteSpace, charTable, SharedImplUtil.getManagerByTree(leafElement)); ASTNode treeParent = treePrev.getTreeParent(); treeParent.replaceChild(treePrev, whiteSpaceElement); } else { LeafElement whiteSpaceElement = Factory.createSingleLeafElement( whiteSpaceToken, whiteSpace, charTable, SharedImplUtil.getManagerByTree(leafElement)); if (treePrev == null) { if (!whiteSpace.isEmpty()) { addWhiteSpace(leafElement, whiteSpaceElement); } } else { if (!(treePrev.getElementType() == whiteSpaceToken)) { if (!whiteSpace.isEmpty()) { addWhiteSpace(treePrev, whiteSpaceElement); } } else { if (treePrev.getElementType() == whiteSpaceToken) { final CompositeElement treeParent = (CompositeElement) treePrev.getTreeParent(); if (!whiteSpace.isEmpty()) { // LOG.assertTrue(textRange == null || // treeParent.getTextRange().equals(textRange)); treeParent.replaceChild(treePrev, whiteSpaceElement); } else { treeParent.removeChild(treePrev); } // There is a possible case that more than one PSI element is matched by the target text // range. // That is the case, for example, for Python's multi-line expression. It may looks like // below: // import contextlib,\ // math, decimal // Here single range contains two blocks: '\' & '\n '. So, we may want to replace that // range to another text, hence, // we replace last element located there with it ('\n ') and want to remove any // remaining elements ('\'). ASTNode removeCandidate = findPreviousWhiteSpace(whiteSpaceElement, whiteSpaceToken); while (textRange != null && removeCandidate != null && removeCandidate.getStartOffset() >= textRange.getStartOffset()) { treePrev = findPreviousWhiteSpace(removeCandidate, whiteSpaceToken); removeCandidate.getTreeParent().removeChild(removeCandidate); removeCandidate = treePrev; } // treeParent.subtreeChanged(); } } } } }
private static void processMethodUsage( PsiElement element, JavaChangeInfo changeInfo, boolean toChangeArguments, boolean toCatchExceptions, GrClosureSignatureUtil.ArgInfo<PsiElement>[] map, PsiSubstitutor substitutor) { if (map == null) return; if (changeInfo.isNameChanged()) { if (element instanceof GrReferenceElement) { element = ((GrReferenceElement) element).handleElementRename(changeInfo.getNewName()); } } if (toChangeArguments) { JavaParameterInfo[] parameters = changeInfo.getNewParameters(); GrArgumentList argumentList = PsiUtil.getArgumentsList(element); GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(element.getProject()); if (argumentList == null) { if (element instanceof GrEnumConstant) { argumentList = factory.createArgumentList(); argumentList = (GrArgumentList) element.add(argumentList); } else { return; } } Set<PsiElement> argsToDelete = new HashSet<PsiElement>(map.length * 2); for (GrClosureSignatureUtil.ArgInfo<PsiElement> argInfo : map) { argsToDelete.addAll(argInfo.args); } for (JavaParameterInfo parameter : parameters) { int index = parameter.getOldIndex(); if (index >= 0) { argsToDelete.removeAll(map[index].args); } } for (PsiElement arg : argsToDelete) { arg.delete(); } boolean skipOptionals = false; PsiElement anchor = null; // PsiTreeUtil.getChildOfAnyType(argumentList, GrExpression.class, // GrNamedArgument.class); for (int i = 0; i < parameters.length; i++) { JavaParameterInfo parameter = parameters[i]; int index = parameter.getOldIndex(); if (index >= 0) { GrClosureSignatureUtil.ArgInfo<PsiElement> argInfo = map[index]; List<PsiElement> arguments = argInfo.args; if (argInfo.isMultiArg) { // arguments for Map and varArg if ((i != 0 || !(!arguments.isEmpty() && arguments.iterator().next() instanceof GrNamedArgument)) && (i != parameters.length - 1 || !parameter.isVarargType())) { final PsiType type = parameter.createType( changeInfo.getMethod().getParameterList(), argumentList.getManager()); final GrExpression arg = GroovyRefactoringUtil.generateArgFromMultiArg( substitutor, arguments, type, element.getProject()); for (PsiElement argument : arguments) { argument.delete(); } anchor = argumentList.addAfter(arg, anchor); JavaCodeStyleManager.getInstance(anchor.getProject()).shortenClassReferences(anchor); } } else { // arguments for simple parameters if (arguments.size() == 1) { // arg exists PsiElement arg = arguments.iterator().next(); if (i == parameters.length - 1 && parameter.isVarargType()) { if (arg instanceof GrSafeCastExpression) { PsiElement expr = ((GrSafeCastExpression) arg).getOperand(); if (expr instanceof GrListOrMap && !((GrListOrMap) expr).isMap()) { final PsiElement copy = expr.copy(); PsiElement[] newVarargs = ((GrListOrMap) copy).getInitializers(); for (PsiElement vararg : newVarargs) { anchor = argumentList.addAfter(vararg, anchor); } arg.delete(); continue; } } } PsiElement curArg = getNextOfType(argumentList, anchor, GrExpression.class); if (curArg == arg) { anchor = arg; } else { final PsiElement copy = arg.copy(); anchor = argumentList.addAfter(copy, anchor); arg.delete(); } } else { // arg is skipped. Parameter is optional skipOptionals = true; } } } else { if (skipOptionals && isParameterOptional(parameter)) continue; if (forceOptional(parameter)) { skipOptionals = true; continue; } try { GrExpression value = createDefaultValue(factory, changeInfo, parameter, argumentList); if (i > 0 && (value == null || anchor == null)) { PsiElement comma = Factory.createSingleLeafElement( GroovyTokenTypes.mCOMMA, ",", 0, 1, SharedImplUtil.findCharTableByTree(argumentList.getNode()), argumentList.getManager()) .getPsi(); if (anchor == null) anchor = argumentList.getLeftParen(); anchor = argumentList.addAfter(comma, anchor); } if (value != null) { anchor = argumentList.addAfter(value, anchor); } } catch (IncorrectOperationException e) { LOG.error(e.getMessage()); } } } GrCall call = GroovyRefactoringUtil.getCallExpressionByMethodReference(element); if (argumentList.getText().trim().isEmpty() && (call == null || !PsiImplUtil.hasClosureArguments(call))) { argumentList = argumentList.replaceWithArgumentList(factory.createArgumentList()); } CodeStyleManager.getInstance(argumentList.getProject()).reformat(argumentList); } if (toCatchExceptions) { final ThrownExceptionInfo[] exceptionInfos = changeInfo.getNewExceptions(); PsiClassType[] exceptions = getExceptions(exceptionInfos, element, element.getManager()); fixExceptions(element, exceptions); } }