/* * Copyright 2013-2017 Grzegorz Ligas <ligasgr@gmail.com> and other contributors * (see the CONTRIBUTORS file). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.intellij.xquery.psi; import com.intellij.extapi.psi.PsiFileBase; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.util.Condition; import com.intellij.psi.FileViewProvider; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiTreeUtil; import org.intellij.xquery.XQueryFileType; import org.intellij.xquery.XQueryFlavour; import org.intellij.xquery.XQueryLanguage; import org.intellij.xquery.completion.function.BuiltInFunctionSignature; import org.intellij.xquery.completion.function.BuiltInFunctionTable; import org.intellij.xquery.model.XQueryLanguageVersion; import org.intellij.xquery.reference.namespace.PredeclaredNamespaces; import org.intellij.xquery.settings.XQuerySettings; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.Icon; import javax.xml.XMLConstants; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import static com.intellij.util.containers.ContainerUtil.findAll; import static org.intellij.xquery.model.XQueryLanguageVersion.V0_9_ML; import static org.intellij.xquery.model.XQueryLanguageVersion.V1_0_ML; import static org.intellij.xquery.model.XQueryLanguageVersion.V3_1; import static org.intellij.xquery.psi.XQueryUtil.getReferencesToExistingFilesInImport; import static org.intellij.xquery.reference.namespace.XQuery30PredeclaredNamespaces.FN; import static org.intellij.xquery.util.StringUtils.removeQuotOrApos; public class XQueryFile extends PsiFileBase { public XQueryFile(@NotNull FileViewProvider viewProvider) { super(viewProvider, XQueryLanguage.INSTANCE); } @NotNull @Override public FileType getFileType() { return XQueryFileType.INSTANCE; } @Override public String toString() { return "XQuery File"; } @Override public Icon getIcon(int flags) { return super.getIcon(flags); } private CachedValue<Collection<XQueryVarDecl>> variableDeclarations; private CachedValue<Collection<XQueryModuleImport>> moduleImports; private CachedValue<Collection<XQueryNamespaceDecl>> namespaceDeclarations; private CachedValue<Collection<XQueryFunctionDecl>> functionDeclarations; private CachedValue<Collection<XQueryFunctionInvocation>> functionInvocations; private CachedValue<Collection<XQueryVarRef>> variableReferences; private CachedValue<Collection<XQueryVarName>> variableNames; private CachedValue<Collection<XQueryNamespaceDecl>> namespacesMatchingDefault; private CachedValue<String> defaultFunctionNamespace; private CachedValue<Map<String, String>> functionPrefixToNamespaceMapping; private CachedValue<XQueryModuleDecl> moduleDeclaration; private CachedValue<Map<String, String>> variablePrefixToNamespaceMapping; private CachedValue<XQueryVersionDecl> versionDeclaration; private CachedValue<Collection<XQueryAnnotation>> annotations; private CachedValue<BuiltInFunctionTable> builtInFunctionTable; @NotNull public Collection<XQueryVarDecl> getVariableDeclarations() { if (variableDeclarations == null) { variableDeclarations = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryVarDecl>>() { @Override public Result<Collection<XQueryVarDecl>> compute() { return CachedValueProvider.Result.create(calcVariableDeclarations(), XQueryFile.this); } }, false); } return variableDeclarations.getValue(); } @NotNull public Collection<XQueryModuleImport> getModuleImports() { if (moduleImports == null) { moduleImports = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryModuleImport>>() { @Override public Result<Collection<XQueryModuleImport>> compute() { return CachedValueProvider.Result.create(calcModuleImports(), XQueryFile.this); } }, false); } return moduleImports.getValue(); } @NotNull public Collection<XQueryNamespaceDecl> getNamespaceDeclarations() { if (namespaceDeclarations == null) { namespaceDeclarations = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryNamespaceDecl>>() { @Override public Result<Collection<XQueryNamespaceDecl>> compute() { return CachedValueProvider.Result.create(calcNamespaceDeclarations(), XQueryFile.this); } }, false); } return namespaceDeclarations.getValue(); } @NotNull public Collection<XQueryFunctionDecl> getFunctionDeclarations() { if (functionDeclarations == null) { functionDeclarations = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryFunctionDecl>>() { @Override public Result<Collection<XQueryFunctionDecl>> compute() { return CachedValueProvider.Result.create(calcFunctionDeclarations(), XQueryFile.this); } }, false); } return functionDeclarations.getValue(); } public Collection<XQueryVarRef> getVariableReferences() { if (variableReferences == null) { variableReferences = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryVarRef>>() { @Override public Result<Collection<XQueryVarRef>> compute() { return CachedValueProvider.Result.create(calcVariableReferences(), XQueryFile.this); } }, false); } return variableReferences.getValue(); } public Collection<XQueryVarName> getVariableNames() { if (variableNames == null) { variableNames = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryVarName>>() { @Override public Result<Collection<XQueryVarName>> compute() { return CachedValueProvider.Result.create(calcVariableNames(), XQueryFile.this); } }, false); } return variableNames.getValue(); } @NotNull public Collection<XQueryFunctionInvocation> getFunctionInvocations() { if (functionInvocations == null) { functionInvocations = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryFunctionInvocation>>() { @Override public Result<Collection<XQueryFunctionInvocation>> compute() { return CachedValueProvider.Result.create(calcFunctionsInvocations(), XQueryFile.this); } }, false); } return functionInvocations.getValue(); } @NotNull public Collection<XQueryNamespaceDecl> getNamespaceDeclarationsMatchingDefaultNamespace() { if (namespacesMatchingDefault == null) { namespacesMatchingDefault = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryNamespaceDecl>>() { @Override public Result<Collection<XQueryNamespaceDecl>> compute() { return CachedValueProvider.Result.create (calcNamespaceDeclarationsMatchingDefaultNamespace(), XQueryFile.this); } }, false); } return namespacesMatchingDefault.getValue(); } @NotNull public String getDefaultFunctionNamespace() { if (defaultFunctionNamespace == null) { defaultFunctionNamespace = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<String>() { @Override public Result<String> compute() { return CachedValueProvider.Result.create (calcDefaultFunctionNamespace(), XQueryFile.this, getSettings()); } }, false); } return defaultFunctionNamespace.getValue(); } @Nullable public XQueryModuleDecl getModuleDeclaration() { if (moduleDeclaration == null) { moduleDeclaration = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<XQueryModuleDecl>() { @Override public Result<XQueryModuleDecl> compute() { return CachedValueProvider.Result.create (calcModuleDeclaration(), XQueryFile.this); } }, false); } return moduleDeclaration.getValue(); } @Nullable public XQueryVersionDecl getVersionDeclaration() { if (versionDeclaration == null) { versionDeclaration = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<XQueryVersionDecl>() { @Override public Result<XQueryVersionDecl> compute() { return CachedValueProvider.Result.create (calcVersionDeclaration(), XQueryFile.this); } }, false); } return versionDeclaration.getValue(); } public Collection<XQueryAnnotation> getAnnotations() { if (annotations == null) { annotations = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Collection<XQueryAnnotation>>() { @Override public Result<Collection<XQueryAnnotation>> compute() { return CachedValueProvider.Result.create(calcAnnotations(), XQueryFile.this); } }, false); } return annotations.getValue(); } public Collection<XQueryXmlTagName> getXmlTagNames() { return PsiTreeUtil.findChildrenOfType(this, XQueryXmlTagName.class); } private Collection<XQueryVarDecl> calcVariableDeclarations() { Collection<XQueryVarDecl> variableDeclarations = PsiTreeUtil.findChildrenOfType(this, XQueryVarDecl.class); return variableDeclarations; } private Collection<XQueryVarRef> calcVariableReferences() { Collection<XQueryVarRef> variableReferences = PsiTreeUtil.findChildrenOfType(this, XQueryVarRef.class); return variableReferences; } private Collection<XQueryVarName> calcVariableNames() { Collection<XQueryVarName> variableNames = PsiTreeUtil.findChildrenOfType(this, XQueryVarName.class); return variableNames; } private Collection<XQueryModuleImport> calcModuleImports() { Collection<XQueryModuleImport> moduleImports = PsiTreeUtil.findChildrenOfType(this, XQueryModuleImport.class); return moduleImports; } private Collection<XQueryNamespaceDecl> calcNamespaceDeclarations() { Collection<XQueryNamespaceDecl> namespaceDeclarations = PsiTreeUtil.findChildrenOfType(this, XQueryNamespaceDecl.class); return namespaceDeclarations; } private Collection<XQueryFunctionDecl> calcFunctionDeclarations() { Collection<XQueryFunctionDecl> functionDeclarations = PsiTreeUtil.findChildrenOfType(this, XQueryFunctionDecl.class); return functionDeclarations; } private Collection<XQueryFunctionInvocation> calcFunctionsInvocations() { Collection<XQueryFunctionInvocation> functionsInvocations = PsiTreeUtil.findChildrenOfType(this, XQueryFunctionInvocation.class); return functionsInvocations; } private Collection<XQueryAnnotation> calcAnnotations() { return PsiTreeUtil.findChildrenOfType(this, XQueryAnnotation.class); } private Collection<XQueryNamespaceDecl> calcNamespaceDeclarationsMatchingDefaultNamespace() { Collection<XQueryNamespaceDecl> all = getNamespaceDeclarations(); return findAll(all, new Condition<XQueryNamespaceDecl>() { @Override public boolean value(XQueryNamespaceDecl declaration) { return declaration.getNamespacePrefix() != null && declaration.getURILiteral() != null && getDefaultFunctionNamespace().equals(removeQuotOrApos(declaration.getURILiteral().getText())); } }); } private XQueryModuleDecl calcModuleDeclaration() { return PsiTreeUtil.findChildOfType(this, XQueryModuleDecl.class); } private String calcDefaultFunctionNamespace() { XQueryDefaultFunctionNamespaceDecl defaultFunctionNamespaceDecl = getDefaultNamespaceFunctionDeclaration(); if (defaultFunctionNamespaceDecl != null && defaultFunctionNamespaceDecl.getURILiteral() != null) return removeQuotOrApos(defaultFunctionNamespaceDecl.getURILiteral().getText()); else if (isLibraryModule() && (versionIsMarklogicSpecific() || getSettings().isMarklogicFlavour()) && getModuleDeclaration().getURILiteral() != null) { return removeQuotOrApos(getModuleDeclaration().getURILiteral().getText()); } return FN.getNamespace(); } private XQueryVersionDecl calcVersionDeclaration() { return PsiTreeUtil.findChildOfType(this, XQueryVersionDecl.class); } public XQueryNamespacePrefix getModuleNamespaceName() { XQueryModuleDecl moduleDecl = getModuleDeclaration(); return moduleDecl != null ? moduleDecl.getNamespacePrefix() : null; } public Collection<XQueryFile> getImportedFilesThatExist(Condition<XQueryModuleImport> condition) { Collection<XQueryFile> result = new LinkedList<XQueryFile>(); for (XQueryModuleImport moduleImport : findAll(getModuleImports(), condition)) { result.addAll(getReferencesToExistingFilesInImport(moduleImport)); } return result; } public XQueryDefaultFunctionNamespaceDecl getDefaultNamespaceFunctionDeclaration() { return PsiTreeUtil.findChildOfType(this, XQueryDefaultFunctionNamespaceDecl.class); } public String mapFunctionPrefixToNamespace(String prefix) { return getFunctionPrefixToNamespaceMap().get(prefix); } public Map<String, String> getFunctionPrefixToNamespaceMap() { if (functionPrefixToNamespaceMapping == null) { functionPrefixToNamespaceMapping = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Map<String, String>>() { @Override public Result<Map<String, String>> compute() { return CachedValueProvider.Result.create(calcFunctionPrefixToNamespaceMap(), XQueryFile.this, getSettings()); } }, false); } return functionPrefixToNamespaceMapping.getValue(); } private Map<String, String> calcFunctionPrefixToNamespaceMap() { Map<String, String> namespaceMapping = calcPrefixToNamespaceMap(); namespaceMapping.put(null, getDefaultFunctionNamespace()); return namespaceMapping; } private Map<String, String> calcPrefixToNamespaceMap() { XQueryNamespacePrefix moduleNamespaceName = getModuleNamespaceName(); Collection<XQueryNamespaceDecl> namespaceDeclarations = getNamespaceDeclarations(); Map<String, String> namespaceMapping = new HashMap<String, String>(getPrefixToNamespaceMap()); if (moduleNamespaceName != null && getModuleDeclaration().getURILiteral() != null) { namespaceMapping.put(moduleNamespaceName.getName(), removeQuotOrApos(getModuleDeclaration().getURILiteral().getText())); } for (XQueryNamespaceDecl namespaceDeclaration : namespaceDeclarations) { if (namespaceDeclaration.getNamespacePrefix() != null && namespaceDeclaration.getURILiteral() != null) { namespaceMapping.put(namespaceDeclaration.getNamespacePrefix().getText(), removeQuotOrApos(namespaceDeclaration.getURILiteral().getText())); } } for (XQueryModuleImport moduleImport : getModuleImports()) { if (moduleImport.getNamespacePrefix() != null && moduleImport.getModuleImportNamespace() != null) { namespaceMapping.put(moduleImport.getNamespacePrefix().getText(), removeQuotOrApos(moduleImport.getModuleImportNamespace().getText())); } } return namespaceMapping; } public boolean isLibraryModule() { XQueryModuleDecl moduleDecl = PsiTreeUtil.findChildOfType(this, XQueryModuleDecl.class); return moduleDecl != null; } public XQueryContextItemDecl getContextItem() { return PsiTreeUtil.findChildOfType(this, XQueryContextItemDecl.class); } public boolean isPrefixForDefaultFunctionNamespace(String prefix) { return isDefaultFunctionNamespace(mapFunctionPrefixToNamespace(prefix)); } public boolean isDefaultFunctionNamespace(String namespace) { return getDefaultFunctionNamespace().equals(namespace); } private Map<String, String> calcVariablePrefixToNamespaceMap() { Map<String, String> namespaceMapping = calcPrefixToNamespaceMap(); namespaceMapping.put(null, getVariableDefaultNamespace()); return namespaceMapping; } private String getVariableDefaultNamespace() { if (isLibraryModule() && (versionIsMarklogicSpecific() || getSettings().isMarklogicFlavour()) && getModuleDeclaration().getURILiteral() != null) { return removeQuotOrApos(getModuleDeclaration().getURILiteral().getText()); } return XMLConstants.NULL_NS_URI; } public String mapVariablePrefixToNamespace(String prefix) { return getVariablePrefixToNamespaceMap().get(prefix); } public Map<String, String> getVariablePrefixToNamespaceMap() { if (variablePrefixToNamespaceMapping == null) { variablePrefixToNamespaceMapping = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<Map<String, String>>() { @Override public Result<Map<String, String>> compute() { return CachedValueProvider.Result.create(calcVariablePrefixToNamespaceMap(), XQueryFile.this, getSettings()); } }, false); } return variablePrefixToNamespaceMapping.getValue(); } public XQueryQueryBody getQueryBody() { return PsiTreeUtil.findChildOfType(this, XQueryQueryBody.class); } private XQuerySettings getSettings() { return XQuerySettings.getInstance(getProject()); } private PredeclaredNamespaces predeclaredNamespaces() { return getBuiltInFunctionTable().predeclaredNamespaces(); } public boolean isPredeclaredNamespacePrefix(String namespacePrefix) { return predeclaredNamespaces().isPredeclaredNamespacePrefix(namespacePrefix); } public boolean isPredeclaredNamespace(String namespace) { return predeclaredNamespaces().isPredeclaredNamespace(namespace); } Map<String, String> getPrefixToNamespaceMap() { return predeclaredNamespaces().getPrefixToNamespaceMap(this); } public BuiltInFunctionTable calcBuiltInFunctionTable() { if (versionIsMarklogicSpecific()) { return XQueryFlavour.MARKLOGIC.getBifTable(); } return getSettings().getFlavour().getBifTable(); } public BuiltInFunctionTable getBuiltInFunctionTable() { if (builtInFunctionTable == null) { builtInFunctionTable = CachedValuesManager .getManager(getProject()) .createCachedValue(new CachedValueProvider<BuiltInFunctionTable>() { @Override public Result<BuiltInFunctionTable> compute() { return CachedValueProvider.Result.create(calcBuiltInFunctionTable(), XQueryFile.this, getSettings()); } }, false); } return builtInFunctionTable.getValue(); } public boolean versionIsNotMarklogicSpecific() { return !versionIsMarklogicSpecific(); } public boolean versionIs31() { XQueryVersionDecl versionDecl = getVersionDeclaration(); XQueryVersion version = versionDecl != null ? versionDecl.getVersion() : null; boolean versionIs31 = false; if (version != null) { String versionString = version.getVersionString(); XQueryLanguageVersion languageVersion = XQueryLanguageVersion.valueFor(versionString); if (V3_1 == languageVersion) { versionIs31 = true; } } else if (getSettings().isFlavourWithVersion31()) { versionIs31 = true; } return versionIs31; } public boolean versionIsMarklogicSpecific() { XQueryVersionDecl versionDecl = getVersionDeclaration(); XQueryVersion version = versionDecl != null ? versionDecl.getVersion() : null; boolean versionIsMarklogicSpecific = false; if (version != null) { String versionString = version.getVersionString(); XQueryLanguageVersion languageVersion = XQueryLanguageVersion.valueFor(versionString); if (V1_0_ML == languageVersion || V0_9_ML == languageVersion) { versionIsMarklogicSpecific = true; } } else if (getSettings().isMarklogicFlavour()) { versionIsMarklogicSpecific = true; } return versionIsMarklogicSpecific; } public boolean isBuiltInFunction(String namespace, String name) { return getBuiltInFunctionTable().isBuiltInFunction(namespace, name); } public boolean isBuiltInFunction(XQueryFunctionName functionName) { String name = functionName.getLocalNameText(); String prefix = functionName.getPrefixText(); String namespace = mapFunctionPrefixToNamespace(prefix); return isBuiltInFunction(namespace, name); } public Collection<BuiltInFunctionSignature> getFunctionsSignatures(String namespace, String name) { return getBuiltInFunctionTable().getFunctionsSignatures(namespace, name); } }