blob: 044f992d75b859e4c01feb1af1e25058945cb5f4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.java.hints.declarative;
import com.sun.source.util.TreePath;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import javax.lang.model.type.TypeMirror;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.modules.java.hints.declarative.conditionapi.Context;
import org.netbeans.modules.java.hints.declarative.conditionapi.Variable;
/**
*
* @author lahvac
*/
public abstract class Condition {
public final boolean not;
private Condition(boolean not) {
this.not = not;
}
public abstract boolean holds(Context ctx, boolean global);
@Override
public abstract String toString();
public static final class Instanceof extends Condition {
public final String variable;
public final String constraint;
public final int[] constraintSpan;
public Instanceof(boolean not, String variable, String constraint, int[] constraintSpan) {
super(not);
this.variable = variable;
this.constraint = constraint;
this.constraintSpan = constraintSpan;
}
@Override
public boolean holds(Context ctx, boolean global) {
TreePath boundTo = APIAccessor.IMPL.getSingleVariable(ctx, new Variable(variable));
if (boundTo == null) {
throw new IllegalStateException();
}
CompilationInfo info = APIAccessor.IMPL.getHintContext(ctx).getInfo();
TypeMirror realType = info.getTrees().getTypeMirror(boundTo);
TypeMirror designedType = Hacks.parseFQNType(info, constraint);
return not ^ info.getTypes().isSubtype(realType, designedType);
}
@Override
public String toString() {
return "(INSTANCEOF " + (not ? "!" : "") + variable + "/" + constraint + ")";
}
}
public static final class MethodInvocation extends Condition {
private final String methodName;
private final Map<? extends String, ? extends ParameterKind> params;
private final MethodInvocationContext mic;
private final AtomicReference<Method> toCall = new AtomicReference<Method>();
public MethodInvocation(boolean not, String methodName, Map<? extends String, ? extends ParameterKind> params, MethodInvocationContext mic) {
super(not);
this.methodName = methodName;
this.params = params;
this.mic = mic;
}
@Override
public boolean holds(Context ctx, boolean global) {
if (toCall.get() == null) {
//not linked yet?
if (!link()) {
throw new IllegalStateException();
}
}
return mic.invokeMethod(ctx, toCall.get(), params) ^ not;
}
boolean link() {
Method m = mic.linkMethod(methodName, params);
toCall.set(m);
return m != null;
}
@Override
public String toString() {
return "(METHOD_INVOCATION " + (not ? "!" : "") + ":" + methodName + "(" + params.toString() + "))";
}
public enum ParameterKind {
VARIABLE,
STRING_LITERAL,
ENUM_CONSTANT;
}
}
public static final class False extends Condition {
public False() {
super(false);
}
@Override
public boolean holds(Context ctx, boolean global) {
return false;
}
@Override
public String toString() {
return "(FALSE)";
}
}
public static final class Otherwise extends Condition {
public Otherwise() {
super(false);
}
@Override
public boolean holds(Context ctx, boolean global) {
return false;
}
@Override
public String toString() {
return "(OTHERWISE)";
}
}
}