@NotNull public static <T extends PsiJavaCodeReferenceElement> JavaResolveResult[] multiResolveImpl( @NotNull T element, boolean incompleteCode, @NotNull ResolveCache.PolyVariantContextResolver<? super T> resolver) { FileASTNode fileElement = SharedImplUtil.findFileElement(element.getNode()); if (fileElement == null) { PsiUtilCore.ensureValid(element); LOG.error("fileElement == null!"); return JavaResolveResult.EMPTY_ARRAY; } PsiFile psiFile = SharedImplUtil.getContainingFile(fileElement); PsiManager manager = psiFile == null ? null : psiFile.getManager(); if (manager == null) { PsiUtilCore.ensureValid(element); LOG.error("getManager() == null!"); return JavaResolveResult.EMPTY_ARRAY; } boolean valid = psiFile.isValid(); if (!valid) { PsiUtilCore.ensureValid(element); LOG.error("psiFile.isValid() == false!"); return JavaResolveResult.EMPTY_ARRAY; } if (element instanceof PsiMethodReferenceExpression) { // method refs: do not cache results during parent conflict resolving, acceptable checks, etc final Map<PsiElement, PsiType> map = LambdaUtil.ourFunctionTypes.get(); if (map != null && map.containsKey(element)) { return (JavaResolveResult[]) resolver.resolve(element, psiFile, incompleteCode); } } return multiResolveImpl(manager.getProject(), psiFile, element, incompleteCode, resolver); }
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 PsiElement addRangeBefore( @NotNull PsiElement first, @NotNull PsiElement last, PsiElement anchor) throws IncorrectOperationException { return SharedImplUtil.addRange( this, first, last, SourceTreeToPsiMap.psiElementToTree(anchor), Boolean.TRUE); }
protected final PsiElement getParentByStub() { final StubElement<?> stub = getStub(); if (stub != null) { return stub.getParentStub().getPsi(); } return SharedImplUtil.getParent(getNode()); }
/** * 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); }
@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 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; }
public <Stub extends StubElement, Psi extends PsiElement> Psi[] getStubOrPsiChildren( final IStubElementType<Stub, Psi> elementType, ArrayFactory<Psi> f) { T stub = myStub; if (stub != null) { //noinspection unchecked return (Psi[]) stub.getChildrenByType(elementType, f); } else { final ASTNode[] nodes = SharedImplUtil.getChildrenOfType(getNode(), elementType); Psi[] psiElements = f.create(nodes.length); for (int i = 0; i < nodes.length; i++) { psiElements[i] = (Psi) nodes[i].getPsi(); } return psiElements; } }
public <Stub extends StubElement, Psi extends PsiElement> Psi[] getStubOrPsiChildren( final IStubElementType<Stub, Psi> elementType, Psi[] array) { T stub = myStub; if (stub != null) { //noinspection unchecked return (Psi[]) stub.getChildrenByType(elementType, array); } else { final ASTNode[] nodes = SharedImplUtil.getChildrenOfType(getNode(), elementType); Psi[] psiElements = (Psi[]) Array.newInstance(array.getClass().getComponentType(), nodes.length); for (int i = 0; i < nodes.length; i++) { psiElements[i] = (Psi) nodes[i].getPsi(); } return psiElements; } }
@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); }
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); }
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(); }
@Override public PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException { CompositeElement treeElement = calcTreeElement(); return SharedImplUtil.doReplace(this, treeElement, newElement); }
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); } }
protected final PsiElement getParentByTree() { return SharedImplUtil.getParent(getNode()); }
@Override public PsiElement addRange(PsiElement first, PsiElement last) throws IncorrectOperationException { return SharedImplUtil.addRange(this, first, last, null, null); }
@Override public void acceptChildren(@NotNull PsiElementVisitor visitor) { SharedImplUtil.acceptChildren(visitor, calcTreeElement()); }
@Override public PsiElement getLastChild() { return SharedImplUtil.getLastChild(calcTreeElement()); }
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(); } } } } }