added handling for available task when resolving properties (IDEADEV-40561)

Currently supporting conditions on files
This commit is contained in:
Eugene Zhuravlev
2009-11-20 20:04:29 +03:00
parent 267c795826
commit 852128e5b1
4 changed files with 130 additions and 31 deletions
@@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -73,6 +74,8 @@ public interface AntFile extends PsiFile, AntElement, PsiNamedElement, Modificat
@Nullable
AntProperty getProperty(@NonNls final String name);
void processAllProperties(@NonNls final String name, Processor<AntProperty> processor);
void setProperty(final String name, final AntProperty element);
@NotNull
@@ -50,6 +50,7 @@ import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.Alarm;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.Processor;
import com.intellij.util.StringBuilderSpinAllocator;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.TaskContainer;
@@ -101,7 +102,7 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
private ClassLoader myClassLoader;
private Hashtable myProjectProperties;
private boolean myNeedPropertiesRebuild = false;
private Map<String, AntProperty> myProperties;
private Map<String, List<AntProperty>> myProperties;
private volatile AntProperty[] myPropertiesArray;
private volatile PropertiesWatcher myDependentFilesWatcher;
private List<String> myEnvPrefixes;
@@ -219,7 +220,16 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
copy.myProjectElements = myProjectElements == null ? null : new HashMap<AntTypeId, String>(myProjectElements);
copy.myClassLoader = myClassLoader;
copy.myExternalProperties = myExternalProperties != null? new HashMap<String, String>(myExternalProperties) : null;
copy.myProperties = myProperties != null? new HashMap<String, AntProperty>(myProperties) : null;
if (myProperties != null) {
final HashMap<String, List<AntProperty>> map = new HashMap<String, List<AntProperty>>();
for (Map.Entry<String, List<AntProperty>> entry : myProperties.entrySet()) {
map.put(entry.getKey(), new ArrayList<AntProperty>(entry.getValue()));
}
copy.myProperties = map;
}
else {
copy.myProperties = null;
}
return copy;
}
@@ -411,6 +421,10 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
return getPropertyRecursively(name, new HashSet<AntFile>());
}
public void processAllProperties(@NonNls String name, Processor<AntProperty> processor) {
processAllPropertiesRecursively(name, new HashSet<AntFile>(), processor);
}
@Nullable
private AntProperty getPropertyRecursively(final String name, final Set<AntFile> processed) {
if (name == null || processed.contains(this)) {
@@ -422,7 +436,13 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
AntProperty antProperty;
synchronized (PsiLock.LOCK) {
antProperty = myProperties != null ? myProperties.get(name) : null;
if (myProperties != null) {
final List<AntProperty> antProperties = myProperties.get(name);
antProperty = antProperties != null && !antProperties.isEmpty()? antProperties.get(0) : null;
}
else {
antProperty = null;
}
}
if (antProperty == null) {
@@ -444,6 +464,43 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
}
}
private void processAllPropertiesRecursively(final String name, final Set<AntFile> processed, Processor<AntProperty> processor) {
if (name == null || processed.contains(this)) {
return;
}
processed.add(this);
try {
synchronized (PsiLock.LOCK) {
if (myProperties != null) {
final List<AntProperty> antProperties = myProperties.get(name);
if (antProperties != null) {
for (AntProperty property : antProperties) {
if (!processor.process(property)) {
return;
}
}
}
}
}
final AntProject antProject = getAntProject();
if (antProject != null) {
for (AntFile imported : antProject.getImportedFiles()) {
if (imported instanceof AntFileImpl) {
((AntFileImpl)imported).processAllPropertiesRecursively(name, processed, processor);
}
else {
imported.processAllProperties(name, processor);
}
}
}
}
finally {
processed.remove(this);
}
}
public void buildPropertiesIfNeeded() {
if (myNeedPropertiesRebuild || (myDependentFilesWatcher != null && myDependentFilesWatcher.needRebuildProperties())) {
buildPropertiesMap();
@@ -453,7 +510,7 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
private void buildPropertiesMap() {
myNeedPropertiesRebuild = false;
myDependentFilesWatcher = null;
myProperties = new HashMap<String, AntProperty>();
myProperties = new HashMap<String, List<AntProperty>>();
myPropertiesArray = null;
loadPredefinedProperties(myProjectProperties, myExternalProperties);
final List<PsiFile> dependentFiles = PropertiesBuilder.defineProperties(this);
@@ -577,7 +634,7 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
return super.getNavigationElement();
}
};
myProperties.put(property.getName(), property);
appendProperty(property.getName(), property);
}
}
finally {
@@ -591,17 +648,22 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
if (myNeedPropertiesRebuild) {
buildPropertiesMap();
}
if (myProperties == null) {
myProperties = new HashMap<String, AntProperty>();
myPropertiesArray = null;
}
if (!myProperties.containsKey(name)) {
myProperties.put(name, element);
myPropertiesArray = null;
}
appendProperty(name, element);
}
}
private void appendProperty(String name, AntProperty element) {
if (myProperties == null) {
myProperties = new HashMap<String, List<AntProperty>>();
}
List<AntProperty> props = myProperties.get(name);
if (props == null) {
myProperties.put(name, props = new ArrayList<AntProperty>());
}
props.add(element);
myPropertiesArray = null;
}
@NotNull
public AntProperty[] getProperties() {
synchronized (PsiLock.LOCK) {
@@ -612,7 +674,13 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
return AntProperty.EMPTY_ARRAY;
}
if (myPropertiesArray == null) {
myPropertiesArray = myProperties.values().toArray(new AntProperty[myProperties.size()]);
final List<AntProperty> props = new ArrayList<AntProperty>(myProperties.size());
for (List<AntProperty> list : myProperties.values()) {
if (!list.isEmpty()) {
props.add(list.get(0));
}
}
myPropertiesArray = props.toArray(new AntProperty[props.size()]);
}
return myPropertiesArray;
}
@@ -26,10 +26,10 @@ import com.intellij.psi.PsiLock;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.StringSetSpinAllocator;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -42,6 +42,13 @@ import java.util.*;
public class AntPropertyImpl extends AntTaskImpl implements AntProperty {
private PsiElement myPropertiesFile;
private static final Set<String> ourPropertyDefiningTags = new HashSet<String>(Arrays.asList(
AntFileImpl.PROPERTY,
"param",
"condition",
"input",
"available"
));
public AntPropertyImpl(final AntElement parent,
final XmlTag sourceElement,
@@ -111,7 +118,7 @@ public class AntPropertyImpl extends AntTaskImpl implements AntProperty {
synchronized (PsiLock.LOCK) {
final XmlTag se = getSourceElement();
final String tagName = se.getName();
if (AntFileImpl.PROPERTY.equals(tagName) || "param".equals(tagName) || "condition".equals(tagName) || "input".equals(tagName)) { // todo: support conditions separately
if (ourPropertyDefiningTags.contains(tagName)) { // todo: support conditions separately
String value = getPropertyValue();
if (value == null && propName != null) {
final PropertiesFile propertiesFile = getPropertiesFile();
@@ -241,6 +248,20 @@ public class AntPropertyImpl extends AntTaskImpl implements AntProperty {
@Nullable
private String getPropertyValue() {
final XmlTag sourceElement = getSourceElement();
final String tagName = sourceElement.getName();
if ("available".equals(tagName)) {
// check only 'file' tag because others could be examined only at runtime
final String filePath = sourceElement.getAttributeValue("file");
if (filePath != null) {
final String _filePath = computeAttributeValue(filePath);
if (_filePath != null) {
if (!new File(_filePath).exists()) {
return null;
}
}
}
}
String value = sourceElement.getAttributeValue("value");
if (value == null) {
value = sourceElement.getAttributeValue("location");
@@ -24,6 +24,7 @@ import com.intellij.lang.ant.psi.introspection.AntTypeDefinition;
import com.intellij.lang.ant.psi.introspection.AntTypeId;
import com.intellij.lang.ant.psi.introspection.impl.AntTypeDefinitionImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
@@ -33,10 +34,7 @@ import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SpinAllocator;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.StringSetSpinAllocator;
import com.intellij.util.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -527,28 +525,37 @@ public class AntStructuredElementImpl extends AntElementImpl implements AntStruc
continue;
}
final String prop = value.substring(startProp + 2, endProp);
final AntProperty propElement = antFile.getProperty(prop);
String resolvedValue = null;
if (propElement != null) {
resolvedValue = propElement.getValue(prop);
if (resolvedValue != null) {
if (elementStack.contains(new Pair<PsiElement, String>(propElement, resolvedValue))) {
return value; // prevent cycles
final Ref<String> resolvedValueRef = new Ref<String>(null);
final Ref<Boolean> shouldReturnOriginalValue = new Ref<Boolean>(Boolean.FALSE);
antFile.processAllProperties(prop, new Processor<AntProperty>() {
public boolean process(AntProperty antProperty) {
final String resolvedValue = antProperty.getValue(prop);
if (resolvedValue == null) {
return true;
}
resolvedValue = ((AntStructuredElementImpl)propElement).computeAttributeValue(resolvedValue, elementStack, antConfig);
if (elementStack.contains(new Pair<PsiElement, String>(antProperty, resolvedValue))) {
shouldReturnOriginalValue.set(Boolean.TRUE);
}
else {
resolvedValueRef.set(((AntStructuredElementImpl)antProperty).computeAttributeValue(resolvedValue, elementStack, antConfig));
}
return false;
}
});
if (shouldReturnOriginalValue.get()) {
return value; // prevent cycles
}
if (resolvedValue == null) {
if (resolvedValueRef.get() == null) {
startProp += 2;
}
else {
if (resolvedValue.equals(value) /*prevent tail recursion*/) {
if (resolvedValueRef.get().equals(value) /*prevent tail recursion*/) {
return value;
}
final StringBuilder builder = StringBuilderSpinAllocator.alloc();
try {
builder.append(value, 0, startProp);
builder.append(resolvedValue);
builder.append(resolvedValueRef.get());
if (endProp < value.length() - 1) {
builder.append(value, endProp + 1, value.length());
}