diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntStringResolver.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntStringResolver.java index 512d86d5f018..062c0c782676 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/AntStringResolver.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntStringResolver.java @@ -86,7 +86,7 @@ public class AntStringResolver extends PropertyProviderFinder{ } } - private static class CachedPropertiesProvider implements PropertiesProvider { + private static class CachedPropertiesProvider implements PropertiesProvider, PropertiesProvider.SkipPropertyExpansionInValues { Set allNames; private final Map myCached; diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/PropertiesProvider.java b/plugins/ant/src/com/intellij/lang/ant/dom/PropertiesProvider.java index 66810f5ddf88..6849948f2ee0 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/PropertiesProvider.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/PropertiesProvider.java @@ -26,6 +26,11 @@ import java.util.Iterator; * Date: Apr 21, 2010 */ public interface PropertiesProvider { + + // if provider implements this interface, returned property values will be treated + // as not requiring further resolution of any property occurrences + interface SkipPropertyExpansionInValues {} + @NotNull Iterator getNamesIterator(); diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/PropertyExpander.java b/plugins/ant/src/com/intellij/lang/ant/dom/PropertyExpander.java index d68e5fa439b0..983b8f4e2588 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/PropertyExpander.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/PropertyExpander.java @@ -18,10 +18,7 @@ package com.intellij.lang.ant.dom; import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; +import java.util.*; import java.util.regex.Pattern; /** @@ -32,6 +29,7 @@ public class PropertyExpander { private static final Pattern $$_PATTERN = Pattern.compile("\\$\\$"); final List myProviders = new ArrayList(); final Resolver myResolver; + final Set myNamesToSkip = new HashSet(); private PropertyExpansionListener myPropertyExpansionListener; public interface PropertyExpansionListener { @@ -39,7 +37,12 @@ public class PropertyExpander { } public PropertyExpander(final @NotNull String str) { - myResolver = new Resolver(str); + this(str, Collections.emptySet()); + } + + private PropertyExpander(final @NotNull String str, Set namesToSkip) { + myResolver = new Resolver(str, namesToSkip); + myNamesToSkip.addAll(namesToSkip); } /** @@ -62,17 +65,27 @@ public class PropertyExpander { final String propName = myResolver.next(); final String value = provider.getPropertyValue(propName); if (value != null) { - final PropertyExpander propertyValueExpander = new PropertyExpander(value); - propertyValueExpander.setPropertyExpansionListener(myPropertyExpansionListener); - if (propertyValueExpander.hasPropertiesToExpand()) { - for (PropertiesProvider p : myProviders) { - propertyValueExpander.acceptProvider(p); - if (!propertyValueExpander.hasPropertiesToExpand()) { - break; + myNamesToSkip.add(propName); // prevent infinite recursion + final String propValue; + if (provider instanceof PropertiesProvider.SkipPropertyExpansionInValues) { + propValue = value; + } + else { + final PropertyExpander propertyValueExpander = new PropertyExpander(value, myNamesToSkip); + propertyValueExpander.setPropertyExpansionListener(myPropertyExpansionListener); + if (propertyValueExpander.hasPropertiesToExpand()) { + for (PropertiesProvider p : myProviders) { + propertyValueExpander.acceptProvider(p); + if (!propertyValueExpander.hasPropertiesToExpand()) { + break; + } + } + if (propertyValueExpander.hasPropertiesToExpand()) { + propertyValueExpander.acceptProvider(provider); } } + propValue = propertyValueExpander.getResult(); } - final String propValue = propertyValueExpander.getResult(); myResolver.replace(propValue); notifyPropertyExpanded(propName, propValue); } @@ -99,7 +112,7 @@ public class PropertyExpander { private List> myPropertyNames; private StringBuilder myBuilder; - private Resolver(final String str) { + private Resolver(final String str, Set namesToSkip) { myBuilder = new StringBuilder(str); int startProp = 0; while ((startProp = str.indexOf("${", startProp)) >= 0) { @@ -114,10 +127,12 @@ public class PropertyExpander { continue; } final String prop = str.substring(startProp + 2, endProp); - if (myPropertyNames == null) { - myPropertyNames = new ArrayList>(); + if (!namesToSkip.contains(prop)) { + if (myPropertyNames == null) { + myPropertyNames = new ArrayList>(); + } + myPropertyNames.add(new Pair(prop, startProp)); } - myPropertyNames.add(new Pair(prop, startProp)); startProp += 2; } if (myPropertyNames == null) { diff --git a/plugins/ant/tests/src/com/intellij/lang/ant/AntPropertyExpansionTest.java b/plugins/ant/tests/src/com/intellij/lang/ant/AntPropertyExpansionTest.java index 960e4a5bf632..164bb855abc1 100644 --- a/plugins/ant/tests/src/com/intellij/lang/ant/AntPropertyExpansionTest.java +++ b/plugins/ant/tests/src/com/intellij/lang/ant/AntPropertyExpansionTest.java @@ -51,6 +51,19 @@ public class AntPropertyExpansionTest extends TestCase{ assertEquals("dValue", expand(providers, "${d}")); assertEquals("${d}cValuedValue", expand(providers, "${c}${d}")); + PropertiesProvider[] providers2 = new PropertiesProvider[] { + new PropertiesProviderImpl("loop.me1", "prefix-${loop.me2}"), + new PropertiesProviderImpl("loop.me2", "prefix-${loop.me1}"), + new PropertiesProviderImpl("loop.me3", "prefix-${loop.me3}"), + new PropertiesProviderImpl("aaa", "aaa_val_${bbb}"), + new PropertiesProviderImpl("bbb", "bbb_val"), + new PropertiesProviderImpl("ccc", "${aaa}_${bbb}"), + }; + + assertEquals("prefix-${loop.me2}", expand(providers2, "${loop.me1}")); + assertEquals("prefix-prefix-${loop.me2}", expand(providers2, "${loop.me2}")); + assertEquals("prefix-${loop.me3}", expand(providers2, "${loop.me3}")); + assertEquals("aaa_val_${bbb}_bbb_val", expand(providers2, "${ccc}")); } private static String expand(PropertiesProvider[] providers, String str) {