blob: 07c3a8ac7551836838224ec707ed519c15d77c19 [file] [log] [blame]
/*
* Copyright 2000-2014 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.patterns;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.PairProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
/**
* @author peter
*/
public abstract class PatternCondition<T> {
private static final Logger LOG = Logger.getInstance("#com.intellij.patterns.PatternCondition");
@NonNls private static final String PARAMETER_FIELD_PREFIX = "val$";
private final String myDebugMethodName;
public PatternCondition(@Nullable @NonNls String debugMethodName) {
myDebugMethodName = debugMethodName;
}
public String getDebugMethodName() {
return myDebugMethodName;
}
private static void appendValue(final StringBuilder builder, final String indent, final Object obj) {
if (obj instanceof ElementPattern) {
((ElementPattern)obj).getCondition().append(builder, indent + " ");
} else if (obj instanceof Object[]) {
appendArray(builder, indent, (Object[])obj);
} else if (obj instanceof Collection) {
appendArray(builder, indent, ((Collection) obj).toArray());
}
else if (obj instanceof String) {
builder.append('\"').append(obj).append('\"');
}
else {
builder.append(obj);
}
}
protected static void appendArray(final StringBuilder builder, final String indent, final Object[] objects) {
builder.append("[");
boolean first = true;
for (final Object o : objects) {
if (!first) {
builder.append(", ");
}
first = false;
appendValue(builder, indent, o);
}
builder.append("]");
}
public abstract boolean accepts(@NotNull T t, final ProcessingContext context);
@NonNls
public String toString() {
final StringBuilder builder = new StringBuilder();
append(builder, "");
return builder.toString();
}
public void append(StringBuilder builder, String indent) {
builder.append(myDebugMethodName);
builder.append("(");
appendParams(builder, indent);
builder.append(")");
}
private void appendParams(final StringBuilder builder, final String indent) {
processParameters(new PairProcessor<String, Object>() {
int count;
String prevName;
int prevOffset;
@Override
public boolean process(String name, Object value) {
count ++;
if (count == 2) builder.insert(prevOffset, prevName +"=");
if (count > 1) builder.append(", ");
prevOffset = builder.length();
if (count > 1) builder.append(name).append("=");
appendValue(builder, indent, value);
prevName = name;
return true;
}
});
}
// this code eats CPU, for debug purposes ONLY
public boolean processParameters(final PairProcessor<String, Object> processor) {
for (Class aClass = getClass(); aClass != null; aClass = aClass.getSuperclass()) {
for (final Field field : aClass.getDeclaredFields()) {
if (!Modifier.isStatic(field.getModifiers()) &&
(((field.getModifiers() & 0x1000 /*Modifer.SYNTHETIC*/) == 0 && !aClass.equals(PatternCondition.class))
|| field.getName().startsWith(PARAMETER_FIELD_PREFIX))) {
final String name = field.getName();
final String fixedName = name.startsWith(PARAMETER_FIELD_PREFIX) ?
name.substring(PARAMETER_FIELD_PREFIX.length()) : name;
final Object value = getFieldValue(field);
if (!processor.process(fixedName, value)) return false;
}
}
}
return true;
}
private Object getFieldValue(Field field) {
final boolean accessible = field.isAccessible();
try {
field.setAccessible(true);
return field.get(this);
}
catch (IllegalAccessException e) {
LOG.error(e);
}
finally {
field.setAccessible(accessible);
}
return null;
}
}