XmlTag (final XmlTag currentUsageTag, PsiElement usageBlock, final String referenceName, XmlTag... moreUsages) { // sort tags by document order final Set<XmlTag> usages = new TreeSet<>(POSITION_COMPARATOR); usages.add(currentUsageTag); ContainerUtil.addAll(usages, moreUsages); // collect all other possible unresolved references with the same name in the current template usageBlock.accept(new PsiRecursiveElementVisitor() { @Override public void visitElement(@NotNull PsiElement element) { if (element instanceof XPathVariableReference) { visitXPathVariableReference(((XPathVariableReference)element)); } else { super.visitElement(element); } } private void visitXPathVariableReference(XPathVariableReference reference) { if (referenceName.equals(reference.getReferencedName())) { if (reference.resolve() == null) { usages.add(PsiTreeUtil.getContextOfType(reference, XmlTag.class, true)); } } } public void visitXmlAttribute(XmlAttribute attribute) { if (XsltSupport.isXPathAttribute(attribute)) { final PsiFile[] xpathFiles = XsltSupport.getFiles(attribute); for (PsiFile xpathFile : xpathFiles) { xpathFile.accept(this); } } } }); final Iterator<XmlTag> it = usages.iterator(); final XmlTag firstUsage = it.next(); // find broadest scope to create the variable in XmlTag tag = firstUsage; while (it.hasNext()) { XmlTag xmlTag = it.next(); final PsiElement t = PsiTreeUtil.findCommonParent(tag, xmlTag); if (t instanceof XmlTag) { tag = (XmlTag)t; } else { break; } } // find the actual tag to create the variable before final XmlTag[] subTags = tag.getSubTags(); for (XmlTag xmlTag : subTags) { if (xmlTag.getTextOffset() > firstUsage.getTextOffset()) break; tag = xmlTag; } final XmlTag parentTag = tag.getParentTag(); if (parentTag == null) return tag; final String parentName = parentTag.getLocalName(); if ("apply-templates".equals(parentName) || "call-template".equals(parentName) || "when".equals(parentName) || "choose".equals(parentName)) { if ("when".equals(parentName)) tag = tag.getParentTag(); assert tag != null; tag = tag.getParentTag(); } assert tag != null; return tag; }