Skip to content

Commit

Permalink
heavily improved oid inlay provider, download intention, deprecated a…
Browse files Browse the repository at this point in the history
…nnotator

(cherry picked from commit 9f69d2a)
  • Loading branch information
1azyman committed Mar 4, 2024
1 parent 2d3a44a commit 84932f4
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package com.evolveum.midpoint.studio.impl.lang.annotation;

import com.evolveum.midpoint.schema.SchemaConstantsGenerated;
import com.evolveum.midpoint.studio.util.MidPointUtils;
import com.evolveum.midpoint.studio.util.PsiUtils;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.xml.TagNameReference;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTagValue;
import org.jetbrains.annotations.NotNull;
Expand All @@ -24,41 +19,16 @@ public class DeprecatedElementAnnotator implements Annotator {

@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
Project project = element.getProject();
if (!MidPointUtils.hasMidPointFacet(project)) {
return;
}

if (element == null || !element.isValid()) {
return;
}

PsiFile file = element.getContainingFile();
if (!(file instanceof XmlFile)) {
return;
}

if (!(element instanceof XmlElement)) {
if (!PsiUtils.isXmlElement(element)) {
return;
}

XmlElement xmlElement = (XmlElement) element;

PsiReference psiReference = xmlElement.getReference();
if (!(psiReference instanceof TagNameReference)) {
return;
}

TagNameReference ref = (TagNameReference) psiReference;
PsiElement reference = ref.resolve();

if (!(reference instanceof XmlTag)) {
XmlTag xsd = PsiUtils.getXsdReference(xmlElement);
if (xsd == null) {
return;
}

XmlTag xsd = (XmlTag) reference;


XmlTag annotation = getFirstSubTag(xsd, "annotation", SchemaConstantsGenerated.NS_XSD);
if (annotation == null) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

import com.evolveum.midpoint.studio.impl.psi.search.ObjectFileBasedIndexImpl;
import com.evolveum.midpoint.studio.impl.psi.search.OidNameValue;
import com.evolveum.midpoint.studio.util.MidPointUtils;
import com.intellij.codeInsight.hints.HintInfo;
import com.evolveum.midpoint.studio.util.PsiUtils;
import com.intellij.codeInsight.hints.InlayInfo;
import com.intellij.codeInsight.hints.InlayParameterHintsProvider;
import com.intellij.psi.PsiElement;
Expand All @@ -13,9 +12,11 @@
import com.intellij.psi.xml.XmlTag;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
* Created by Viliam Repan (lazyman).
Expand All @@ -25,23 +26,22 @@ public class OidInlayParameterHintsProvider implements InlayParameterHintsProvid
@NotNull
@Override
public List<InlayInfo> getParameterHints(PsiElement element) {
PsiElement parent = element.getParent();
if (!(element instanceof XmlAttributeValue)
|| !(parent instanceof XmlAttribute)
|| !"oid".equals(((XmlAttribute) parent).getLocalName())) {
if (!isReferenceOidAttribute(element) && !PsiUtils.isReferenceOidTag(element)) {
return Collections.emptyList();
}

XmlAttributeValue value = (XmlAttributeValue) element;
int offset = inlayOffset(element, false);
XmlTag ref = PsiUtils.findObjectReferenceTag(element);
if (ref == null) {
return Collections.emptyList();
}

XmlAttribute attr = (XmlAttribute) parent;
XmlTag tag = attr.getParent();
if (MidPointUtils.isObjectTypeElement(tag, false)) { // check even without namespaces MID-7468
String oid = PsiUtils.getOidFromReferenceTag(ref);
if (oid == null) {
return Collections.emptyList();
}

List<OidNameValue> result = ObjectFileBasedIndexImpl.getOidNamesByOid(value.getValue(), element.getProject());
int offset = inlayOffset(element, false);
List<OidNameValue> result = ObjectFileBasedIndexImpl.getOidNamesByOid(oid, element.getProject());
if (result == null || result.isEmpty()) {
return Collections.emptyList();
}
Expand All @@ -68,10 +68,21 @@ public List<InlayInfo> getParameterHints(PsiElement element) {
} else {
label = label + " (multiple objects)";
}
}

return List.of(new InlayInfo(label, offset, false, true, false));
}

private boolean isReferenceOidAttribute(PsiElement element) {
if (!(element instanceof XmlAttributeValue value)) {
return false;
}

if (!(value.getParent() instanceof XmlAttribute attribute)) {
return false;
}

return Arrays.asList(new InlayInfo(label, offset, false, true, false));
return "oid".equals(attribute.getLocalName());
}

private int inlayOffset(PsiElement expr, boolean atEnd) {
Expand All @@ -89,11 +100,6 @@ private int inlayOffset(PsiElement expr, boolean atEnd) {
return expr.getTextRange().getStartOffset();
}

@Nullable
@Override
public HintInfo getHintInfo(@NotNull PsiElement element) {
return null;
}

@NotNull
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package com.evolveum.midpoint.studio.util;

import com.evolveum.midpoint.util.QNameUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.xml.TagNameReference;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import org.apache.commons.lang3.StringUtils;

import javax.xml.namespace.QName;
import java.util.Arrays;
import java.util.Objects;

public class PsiUtils {

public static boolean isXmlElement(PsiElement element) {
Project project = element.getProject();
if (!MidPointUtils.hasMidPointFacet(project)) {
return false;
}

if (element == null || !element.isValid()) {
return false;
}

PsiFile file = element.getContainingFile();
if (!(file instanceof XmlFile)) {
return false;
}

return (element instanceof XmlElement);
}

public static XmlTag getParentTag(PsiElement element) {
if (element == null) {
return null;
}

if (!(element instanceof XmlElement xmlElement)) {
return null;
}

if (element instanceof XmlTag tag) {
return tag;
}

return getParentTag(element.getParent());
}

/**
* @param element
* @return XmlTag if element is inside c:ObjectReferenceType, null otherwise
*/
public static XmlTag findObjectReferenceTag(PsiElement element) {
XmlTag parentTag = PsiUtils.getParentTag(element);
if (parentTag == null) {
return null;
}

// parentTag should be type of c:ObjectReferenceType or
// <oid> with parent c:ObjectReferenceType (undocumented, experimental)
XmlTag possibleReference = parentTag;

QName parentTagName = MidPointUtils.createQName(parentTag);
if (possibleReference.getParentTag() != null && (
Objects.equals(parentTagName, ObjectReferenceType.F_OID)
|| Objects.equals(parentTagName, ObjectReferenceType.F_TYPE))) {
possibleReference = possibleReference.getParentTag();
}

XmlTag xsd = getXsdReference(possibleReference);
if (xsd == null || xsd == possibleReference) {
// xsd definition not found or tag points to itself (in case schema is not available or not indexed yet)
return null;
}

String type = xsd.getAttributeValue("type", xsd.getNamespace());
if (type == null) {
return null;
}

QNameUtil.PrefixedName name = QNameUtil.parsePrefixedName(type);
if (!Objects.equals(name.localName(), ObjectReferenceType.COMPLEX_TYPE.getLocalPart())) {
return null;
}

String namespace = xsd.getNamespaceByPrefix(name.prefix());
if (!Objects.equals(namespace, ObjectReferenceType.COMPLEX_TYPE.getNamespaceURI())) {
return null;
}

return possibleReference;
}

public static XmlTag getXsdReference(XmlElement tag) {
PsiReference ref = tag.getReference();
if (!(ref instanceof TagNameReference tagNameReference)) {
return null;
}

PsiElement reference = tagNameReference.resolve();
if (!(reference instanceof XmlTag xsd)) {
return null;
}

return xsd;
}

public static QName getTypeFromReferenceTag(XmlTag reference) {
return getTypeFromReferenceTag(reference, null);
}

public static QName getTypeFromReferenceTag(XmlTag reference, QName defaultType) {
if (reference == null) {
return defaultType;
}

String type = reference.getAttributeValue("type");
if (type != null) {
return getTextToQName(type, reference);
}

return Arrays.stream(reference.getSubTags())
.filter(tag -> Objects.equals(tag.getLocalName(), "type"))
.map(t -> t.getValue().getText())
.map(v -> getTextToQName(v, reference))
.filter(q -> q != null)
.findFirst()
.orElse(null);
}

private static QName getTextToQName(String value, XmlTag tag) {
QNameUtil.PrefixedName prefixed = QNameUtil.parsePrefixedName(value);
String ns = tag.getNamespaceByPrefix(prefixed.prefix());
return new QName(ns, prefixed.localName());
}

/**
* Check whether tag is <c:oid>, doesn't check parent whether it's reference.
*
* @param element
* @return
*/
public static boolean isReferenceOidTag(PsiElement element) {
if (element == null) {
return false;
}

if (!(element instanceof XmlTag tag)) {
return false;
}

QName name = MidPointUtils.createQName(tag);
return Objects.equals(name, ObjectReferenceType.F_OID);
}

public static String getOidFromReferenceTag(XmlTag reference) {
if (reference == null) {
return null;
}

String oid = reference.getAttributeValue("oid");
if (oid != null) {
return oid;
}

return Arrays.stream(reference.getSubTags())
.filter(tag -> isReferenceOidTag(tag))
.map(t -> t.getValue().getText())
.filter(StringUtils::isNotBlank)
.findFirst()
.orElse(null);
}
}

0 comments on commit 84932f4

Please sign in to comment.