diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomDependentTargetReference.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomDependentTargetReference.java new file mode 100644 index 000000000000..07664fbe6fac --- /dev/null +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomDependentTargetReference.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * 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 com.intellij.lang.ant.dom; + +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.StringBuilderSpinAllocator; +import org.jetbrains.annotations.NotNull; + +/** +* @author Eugene Zhuravlev +* Date: Apr 13, 2010 +*/ +class AntDomDependentTargetReference extends AntDomReference { + public AntDomDependentTargetReference(AntDomTarget target, String targetName, int start) { + super(target, targetName, TextRange.from(start, start + targetName.length())); + } + + public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { + final AntDomTarget hostTarget = getAntElement(); + final XmlAttribute dependsAttribute = hostTarget.getDependsList().getXmlAttribute(); + if (dependsAttribute != null) { + final TextRange refRange = getRangeInElement(); + final int start = refRange.getStartOffset(); + final String value = hostTarget.getDependsList().getValue(); + final StringBuilder builder = StringBuilderSpinAllocator.alloc(); + try { + if (start > 0) { + builder.append(value.substring(0, start)); + } + builder.append(newElementName); + if (value.length() > start + refRange.getLength()) { + builder.append(value.substring(start + refRange.getLength())); + } + dependsAttribute.setValue(builder.toString()); + } + finally { + StringBuilderSpinAllocator.dispose(builder); + } + } + return getElement(); + } + + public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { + return null; // todo + } + + public AntDomTarget getAntElement() { + return (AntDomTarget)super.getAntElement(); + } + + public PsiElement resolveInner() { + // todo: handle imported targets + final AntDomProject antProject = getAntElement().getAntProject(); + if (antProject == null) { + return null; + } + final AntDomTarget resolved = antProject.getTarget(getCanonicalText()); + if (resolved == null) { + return null; + } + return resolved.getXmlElement(); + } +} diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomProject.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomProject.java index 8c373b5afe33..d8213a0fc671 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomProject.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomProject.java @@ -25,6 +25,7 @@ import com.intellij.util.xml.Attribute; import com.intellij.util.xml.GenericAttributeValue; import com.intellij.util.xml.SubTagList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -46,7 +47,17 @@ public abstract class AntDomProject extends AntDomElement { public abstract GenericAttributeValue getBasedir(); @SubTagList("target") - public abstract List getTargets(); + public abstract List getTargets(); + + @Nullable + public final AntDomTarget getTarget(String name) { + for (AntDomTarget target : getTargets()) { + if (name.equals(target.getName().getValue())) { + return target; + } + } + return null; + } @NotNull public final ClassLoader getClassLoader() { diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomReference.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomReference.java new file mode 100644 index 000000000000..df6bc508f795 --- /dev/null +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomReference.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * 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 com.intellij.lang.ant.dom; + +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.resolve.reference.impl.CachingReference; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author Eugene Zhuravlev + * Date: Apr 13, 2010 + */ +public abstract class AntDomReference extends CachingReference{ + private final AntDomElement myAntElement; + private final String myText; + private final TextRange myTextRange; + + protected AntDomReference(final AntDomElement element, final String text, final TextRange textRange) { + myAntElement = element; + myText = text; + myTextRange = textRange; + } + + public AntDomElement getAntElement() { + return myAntElement; + } + + public PsiElement getElement() { + return myAntElement.getXmlElement(); + } + + public TextRange getRangeInElement() { + return myTextRange; + } + + public String getCanonicalText() { + return myText; + } + + @NotNull + public Object[] getVariants() { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + + @Override + public PsiElement resolveInner() { + throw new UnsupportedOperationException(); + } + + public String getUnresolvedMessagePattern() { + return CodeInsightBundle.message("error.cannot.resolve.default.message", ""); + } + +} diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntTarget.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomTarget.java similarity index 81% rename from plugins/ant/src/com/intellij/lang/ant/dom/AntTarget.java rename to plugins/ant/src/com/intellij/lang/ant/dom/AntDomTarget.java index 534496e99eab..278d6f49c6fc 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/AntTarget.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomTarget.java @@ -23,7 +23,7 @@ import com.intellij.util.xml.GenericAttributeValue; * Date: Apr 6, 2010 */ @SuppressWarnings({"AbstractClassNeverImplemented"}) -public abstract class AntTarget extends AntDomElement { +public abstract class AntDomTarget extends AntDomElement { @Attribute("name") public abstract GenericAttributeValue getName(); @@ -32,4 +32,11 @@ public abstract class AntTarget extends AntDomElement { @Attribute("unless") public abstract GenericAttributeValue getUnlessPropertyName(); + + @Attribute("depends") + public abstract GenericAttributeValue getDependsList(); + + public AntDomProject getAntProject() { + return getParentOfType(AntDomProject.class, true); + } } diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntReferenceInjector.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntReferenceInjector.java index 6b4cbca38fb9..ea5f45229575 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/AntReferenceInjector.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntReferenceInjector.java @@ -15,14 +15,20 @@ */ package com.intellij.lang.ant.dom; +import com.intellij.lang.ant.misc.PsiReferenceListSpinAllocator; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.xml.ConvertContext; import com.intellij.util.xml.DomElement; import com.intellij.util.xml.DomReferenceInjector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; +import java.util.List; + /** * @author Eugene Zhuravlev * Date: Apr 9, 2010 @@ -37,4 +43,52 @@ class AntReferenceInjector implements DomReferenceInjector { public PsiReference[] inject(@Nullable String unresolvedText, @NotNull PsiElement element, @NotNull ConvertContext context) { return PsiReference.EMPTY_ARRAY; } + + private List getDependentTargetReferences(AntDomTarget target) { + final String xmlAttributeValue = target.getDependsList().getValue(); + if (xmlAttributeValue == null) { + return Collections.emptyList(); + } + final XmlAttribute attr = target.getDependsList().getXmlAttribute(); + if (attr == null) { + return Collections.emptyList(); + } + final int offsetInPosition = attr.getValueTextRange().getStartOffset(); + final List result = PsiReferenceListSpinAllocator.alloc(); + try { + final StringBuilder builder = StringBuilderSpinAllocator.alloc(); + try { + int i = 0; + int rightBound; + final int valueLen = xmlAttributeValue.length(); + do { + rightBound = (i < valueLen) ? xmlAttributeValue.indexOf(',', i) : valueLen; + if (rightBound < 0) rightBound = valueLen; + builder.setLength(0); + int j = i; + for (; j < rightBound; ++j) { + builder.append(xmlAttributeValue.charAt(j)); + } + j = 0; + final int len = builder.length(); + for (; j < len; ++j) { + if (!Character.isWhitespace(builder.charAt(j))) break; + } + final String targetName = (len == 0 || j == len) ? "" : builder.substring(j); + final int start = offsetInPosition + i + j; + result.add(new AntDomDependentTargetReference(target, targetName, start)); + i = rightBound + 1; + } + while (rightBound < valueLen); + return result; + } + finally { + StringBuilderSpinAllocator.dispose(builder); + } + } + finally { + PsiReferenceListSpinAllocator.dispose(result); + } + } + }