diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/validation/XPathAnnotator.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/validation/XPathAnnotator.java index 0c9f9705bafe..2880291e769e 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/validation/XPathAnnotator.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/validation/XPathAnnotator.java @@ -23,7 +23,9 @@ import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.tree.IElementType; @@ -329,6 +331,18 @@ public final class XPathAnnotator extends XPath2ElementVisitor implements Annota qName.getPrefix() + "' has not been declared"); ann.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); + } else if (name != null){ + final String extNS = name.getNamespaceURI(); + if (!StringUtil.isEmpty(extNS)) { + final Set> pairs = contextProvider.getFunctionContext().getFunctions().keySet(); + for (Pair pair : pairs) { + // extension namespace is known + final String uri = pair.first.getNamespaceURI(); + if (uri != null && uri.equals(extNS)) { + holder.createWarningAnnotation(node, "Unknown function '" + name + "'"); + } + } + } } } else { if (name != null) { diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/Xslt2FunctionContext.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/Xslt2FunctionContext.java index 7e140da436bd..12c8c492a7b4 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/Xslt2FunctionContext.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/Xslt2FunctionContext.java @@ -19,16 +19,16 @@ import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.Pair; import com.intellij.util.containers.ContainerUtil; import org.intellij.lang.xpath.context.ContextType; -import org.intellij.lang.xpath.context.functions.DefaultFunctionContext; -import org.intellij.lang.xpath.context.functions.Function; -import org.intellij.lang.xpath.context.functions.FunctionContext; -import org.intellij.lang.xpath.context.functions.FunctionDeclarationParsing; +import org.intellij.lang.xpath.context.functions.*; +import org.intellij.lang.xpath.psi.XPath2Type; import javax.xml.namespace.QName; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import static org.intellij.lang.xpath.xslt.context.XsltFunctionContext.SAXON_7; + /* * Created by IntelliJ IDEA. * User: sweinreuter @@ -110,6 +110,34 @@ public class Xslt2FunctionContext extends DefaultFunctionContext { "$calendar as xs:string?,\n" + "$country as xs:string?) as xs:string?"); + final Parameter optional_string = new Parameter(XPath2Type.STRING, Parameter.Kind.OPTIONAL); + final Parameter required_string = new Parameter(XPath2Type.STRING, Parameter.Kind.REQUIRED); + final Parameter required_nodeset = new Parameter(XPath2Type.NODE_SEQUENCE, Parameter.Kind.REQUIRED); + final Parameter required_any = new Parameter(XPath2Type.ITEM, Parameter.Kind.REQUIRED); + final Parameter optional_any = new Parameter(XPath2Type.ITEM, Parameter.Kind.OPTIONAL); + final Parameter any_list = new Parameter(XPath2Type.ITEM, Parameter.Kind.VARARG); + + addFunction(decls, SAXON_7, new FunctionImpl("dayTimeDuration-from-seconds", XPath2Type.DAYTIMEDURATION, new Parameter(XPath2Type.INTEGER, Parameter.Kind.REQUIRED))); + addFunction(decls, SAXON_7, new FunctionImpl("yearMonthDuration-from-months", XPath2Type.YEARMONTHDURATION, new Parameter(XPath2Type.INTEGER, Parameter.Kind.REQUIRED))); + + addFunction(decls, SAXON_7, new FunctionImpl("distinct", XPath2Type.NODE_SEQUENCE, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("eval", XPath2Type.ITEM, required_any)); + addFunction(decls, SAXON_7, new FunctionImpl("evaluate", XPath2Type.ITEM, required_string, any_list)); + addFunction(decls, SAXON_7, new FunctionImpl("expression", XPath2Type.ITEM, required_string, any_list)); + addFunction(decls, SAXON_7, new FunctionImpl("get-pseudo-attribute", XPath2Type.ITEM, required_string)); + addFunction(decls, SAXON_7, new FunctionImpl("has-same-nodes", XPath2Type.BOOLEAN, required_nodeset, required_nodeset)); + addFunction(decls, SAXON_7, new FunctionImpl("highest", XPath2Type.NODE_SEQUENCE, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("leading", XPath2Type.NODE_SEQUENCE, required_nodeset, required_any)); + addFunction(decls, SAXON_7, new FunctionImpl("line-number", XPath2Type.INTEGER)); + addFunction(decls, SAXON_7, new FunctionImpl("max", XPath2Type.NUMERIC, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("min", XPath2Type.NUMERIC, required_string)); + addFunction(decls, SAXON_7, new FunctionImpl("parse", XPath2Type.NODE_SEQUENCE, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("path", XPath2Type.STRING)); + addFunction(decls, SAXON_7, new FunctionImpl("serialize", XPath2Type.STRING, required_nodeset, required_string)); + addFunction(decls, SAXON_7, new FunctionImpl("sum", XPath2Type.NUMERIC, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("systemId", XPath2Type.STRING)); + addFunction(decls, SAXON_7, new FunctionImpl("tokenize", XPath2Type.NODE_SEQUENCE, required_string, optional_string)); + XSLT2_FUNCTIONS = Collections.unmodifiableMap(decls); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltFunctionContext.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltFunctionContext.java index 144bc4c639d4..01ef5c95b934 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltFunctionContext.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltFunctionContext.java @@ -45,9 +45,20 @@ public class XsltFunctionContext extends DefaultFunctionContext { public static final String EXSLT_DYNAMIC = "http://exslt.org/dynamic"; public static final String EXSLT_STRINGS = "http://exslt.org/strings"; + public static final String SAXON_6 = "http://icl.com/saxon"; + public static final String SAXON_7 = "http://saxon.sf.net/"; + static { final Map, Function> decls = new HashMap, Function>(); + final Parameter optional_string = new Parameter(XPathType.STRING, Parameter.Kind.OPTIONAL); + final Parameter required_string = new Parameter(XPathType.STRING, Parameter.Kind.REQUIRED); + final Parameter required_nodeset = new Parameter(XPathType.NODESET, Parameter.Kind.REQUIRED); + final Parameter required_number = new Parameter(XPathType.NUMBER, Parameter.Kind.REQUIRED); + final Parameter required_any = new Parameter(XPathType.ANY, Parameter.Kind.REQUIRED); + final Parameter optional_any = new Parameter(XPathType.ANY, Parameter.Kind.OPTIONAL); + final Parameter any_list = new Parameter(XPathType.ANY, Parameter.Kind.VARARG); + // string format-number(number, string, string?) addFunction(decls, new FunctionImpl("format-number", XPathType.STRING, new Parameter(XPathType.NUMBER, Parameter.Kind.REQUIRED), @@ -61,7 +72,7 @@ public class XsltFunctionContext extends DefaultFunctionContext { // node-set key(string, object) addFunction(decls, new FunctionImpl("key", XPathType.NODESET, new Parameter(XPathType.STRING, Parameter.Kind.REQUIRED), - new Parameter(XPathType.ANY, Parameter.Kind.REQUIRED))); + required_any)); // string generate-id(node-set?) addFunction(decls, new FunctionImpl("generate-id", XPathType.STRING, @@ -82,11 +93,6 @@ public class XsltFunctionContext extends DefaultFunctionContext { // node-set current() addFunction(decls, new FunctionImpl("current", XPathType.NODESET)); - final Parameter optional_string = new Parameter(XPathType.STRING, Parameter.Kind.OPTIONAL); - final Parameter required_string = new Parameter(XPathType.STRING, Parameter.Kind.REQUIRED); - final Parameter required_nodeset = new Parameter(XPathType.NODESET, Parameter.Kind.REQUIRED); - final Parameter required_number = new Parameter(XPathType.NUMBER, Parameter.Kind.REQUIRED); - // EXSLT (http://www.exslt.org) extensions supported by Xalan & Saxon addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("date", XPathType.STRING, optional_string)); addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("date-time", XPathType.STRING)); @@ -107,8 +113,8 @@ public class XsltFunctionContext extends DefaultFunctionContext { addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("week-in-year", XPathType.NUMBER, optional_string)); addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("year", XPathType.NUMBER, optional_string)); - addFunction(decls, EXSLT_COMMON, new FunctionImpl("node-set", XPathType.NODESET, new Parameter(XPathType.ANY, Parameter.Kind.REQUIRED))); - addFunction(decls, EXSLT_COMMON, new FunctionImpl("object-type", XPathType.STRING, new Parameter(XPathType.ANY, Parameter.Kind.REQUIRED))); + addFunction(decls, EXSLT_COMMON, new FunctionImpl("node-set", XPathType.NODESET, required_any)); + addFunction(decls, EXSLT_COMMON, new FunctionImpl("object-type", XPathType.STRING, required_any)); addFunction(decls, EXSLT_MATH, new FunctionImpl("highest", XPathType.NODESET, required_nodeset)); addFunction(decls, EXSLT_MATH, new FunctionImpl("lowest", XPathType.NODESET, required_nodeset)); @@ -151,6 +157,53 @@ public class XsltFunctionContext extends DefaultFunctionContext { addFunction(decls, EXSLT_STRINGS, new FunctionImpl("tokenize", XPathType.NODESET, required_string, optional_string)); addFunction(decls, EXSLT_STRINGS, new FunctionImpl("split", XPathType.NODESET, required_string, optional_string)); + // Saxon only + addFunction(decls, SAXON_6, new FunctionImpl("after", XPathType.NODESET, required_nodeset, required_nodeset)); + addFunction(decls, SAXON_6, new FunctionImpl("before", XPathType.NODESET, required_nodeset, required_nodeset)); + addFunction(decls, SAXON_6, new FunctionImpl("closure", XPathType.NODESET, required_nodeset, required_any)); + addFunction(decls, SAXON_6, new FunctionImpl("difference", XPathType.NODESET, required_nodeset, required_nodeset)); + addFunction(decls, SAXON_6, new FunctionImpl("distinct", XPathType.NODESET, required_nodeset, optional_any)); + addFunction(decls, SAXON_6, new FunctionImpl("eval", XPathType.ANY, required_any)); + addFunction(decls, SAXON_6, new FunctionImpl("evaluate", XPathType.ANY, required_string, any_list)); + addFunction(decls, SAXON_6, new FunctionImpl("exists", XPathType.BOOLEAN, required_any)); + addFunction(decls, SAXON_6, new FunctionImpl("expression", XPathType.ANY, required_string, any_list)); + addFunction(decls, SAXON_6, new FunctionImpl("for-all", XPathType.BOOLEAN, required_nodeset, required_any)); + addFunction(decls, SAXON_6, new FunctionImpl("get-pseudo-attribute", XPathType.ANY, required_string)); + addFunction(decls, SAXON_6, new FunctionImpl("get-user-data", XPathType.ANY, required_string)); + addFunction(decls, SAXON_6, new FunctionImpl("has-same-nodes", XPathType.BOOLEAN, required_nodeset, required_nodeset)); + addFunction(decls, SAXON_6, new FunctionImpl("highest", XPathType.NODESET, required_nodeset, optional_any)); + addFunction(decls, SAXON_6, new FunctionImpl("if", XPathType.ANY, required_any, required_any)); + addFunction(decls, SAXON_6, new FunctionImpl("if-null", XPathType.BOOLEAN, required_any)); + addFunction(decls, SAXON_6, new FunctionImpl("intersection", XPathType.NODESET, required_nodeset, required_nodeset)); + addFunction(decls, SAXON_6, new FunctionImpl("leading", XPathType.NODESET, required_nodeset, required_any)); + addFunction(decls, SAXON_6, new FunctionImpl("line-number", XPathType.NUMBER)); + addFunction(decls, SAXON_6, new FunctionImpl("lowest", XPathType.NODESET, required_nodeset, optional_any)); + addFunction(decls, SAXON_6, new FunctionImpl("max", XPathType.NUMBER, required_nodeset, optional_any)); + addFunction(decls, SAXON_6, new FunctionImpl("min", XPathType.NUMBER, required_nodeset, optional_any)); + addFunction(decls, SAXON_6, new FunctionImpl("path", XPathType.STRING)); + addFunction(decls, SAXON_6, new FunctionImpl("range", XPathType.NODESET, required_number, required_number)); + addFunction(decls, SAXON_6, new FunctionImpl("set-user-data", XPathType.UNKNOWN, required_string, required_any)); + addFunction(decls, SAXON_6, new FunctionImpl("sum", XPathType.NUMBER, required_nodeset, optional_any)); + addFunction(decls, SAXON_6, new FunctionImpl("systemId", XPathType.STRING)); + addFunction(decls, SAXON_6, new FunctionImpl("tokenize", XPathType.NODESET, required_string, optional_string)); + + addFunction(decls, SAXON_7, new FunctionImpl("distinct", XPathType.NODESET, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("eval", XPathType.ANY, required_any)); + addFunction(decls, SAXON_7, new FunctionImpl("evaluate", XPathType.ANY, required_string)); + addFunction(decls, SAXON_7, new FunctionImpl("expression", XPathType.ANY, required_string)); + addFunction(decls, SAXON_7, new FunctionImpl("get-pseudo-attribute", XPathType.ANY, required_string)); + addFunction(decls, SAXON_7, new FunctionImpl("has-same-nodes", XPathType.BOOLEAN, required_nodeset, required_nodeset)); + addFunction(decls, SAXON_7, new FunctionImpl("highest", XPathType.NODESET, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("leading", XPathType.NODESET, required_nodeset, required_any)); + addFunction(decls, SAXON_7, new FunctionImpl("line-number", XPathType.NUMBER)); + addFunction(decls, SAXON_7, new FunctionImpl("max", XPathType.NUMBER, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("min", XPathType.NUMBER, required_string)); + addFunction(decls, SAXON_7, new FunctionImpl("parse", XPathType.NODESET, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("path", XPathType.STRING)); + addFunction(decls, SAXON_7, new FunctionImpl("serialize", XPathType.STRING, required_nodeset, required_string)); + addFunction(decls, SAXON_7, new FunctionImpl("sum", XPathType.NUMBER, required_nodeset, optional_any)); + addFunction(decls, SAXON_7, new FunctionImpl("systemId", XPathType.STRING)); + addFunction(decls, SAXON_7, new FunctionImpl("tokenize", XPathType.NODESET, required_string, optional_string)); XSLT_FUNCTIONS = Collections.unmodifiableMap(decls); }