blob: 8ff70644f82b6419d41d74c475232ff962e6a834 [file] [log] [blame]
package fuchsia.developer.plugin.fidl;
import com.intellij.lang.ASTNode;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import fuchsia.developer.plugin.fidl.psi.Types;
import java.util.logging.Logger;
import org.jetbrains.annotations.NotNull;
public class ContextAwareHighlighter implements Annotator {
private static final TextAttributesKey IDENTIFIER_ATTRIBUTE;
static {
SyntaxHighlighter highlighter = new SyntaxHighlighter();
TextAttributesKey[] key = highlighter.getTokenHighlights(Types.IDENTIFIER);
IDENTIFIER_ATTRIBUTE = key[0];
}
/**
* @param literalNode An ASTNode of type NUMERIC_LITERAL.
* @return null if the value associated with the node isn't supported or is an unsigned power of
* two, an error message otherwise.
*/
private static String unsignedLongPowerOfTwoOrError(ASTNode literalNode) {
// Assume decimal
String value = literalNode.getText();
int radix = 10;
if (literalNode.findChildByType(Types.BINARY_INTEGRAL_LITERAL) != null) {
String[] pieces = value.split("0[bB]");
value = pieces[0] + pieces[1];
radix = 2;
} else if (literalNode.findChildByType(Types.HEX_INTEGRAL_LITERAL) != null) {
String[] pieces = value.split("0[xX]");
value = pieces[0] + pieces[1];
radix = 16;
}
Long lval = null;
try {
lval = Long.parseLong(value, radix);
} catch (NumberFormatException e) {
// Probably not worth throwing anything.
Logger logger = Logger.getLogger(ContextAwareHighlighter.class.getName());
logger.warning("Unknown numeric value " + value);
return null;
}
if (lval < 0 || Long.bitCount(lval) != 1) {
return "Bit value must be non-negative power of two, is " + Long.toString(lval, radix);
}
return null;
}
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
PsiElement parent = element.getParent();
if (parent == null || parent.getNode() == null) {
return;
}
IElementType parentType = parent.getNode().getElementType();
if (parentType == Types.IDENTIFIER_TOKEN) {
Annotation annotation = holder.createInfoAnnotation(element, null);
annotation.setTextAttributes(IDENTIFIER_ATTRIBUTE);
}
if (element.getNode().getElementType() == Types.XUNION) {
holder.createWarningAnnotation(element,
"Xunions are transitional, and will be removed in a future language revision");
}
if (element.getNode().getElementType() == Types.BITS_OR_ENUM_MEMBER_VALUE) {
IElementType grandParentType = parent.getParent().getNode().getElementType();
if (grandParentType == Types.BITS_DECLARATION) {
ASTNode literalNode = element.getNode().findChildByType(Types.INTEGRAL_LITERAL);
if (literalNode != null) {
// is a numeric value
String value = unsignedLongPowerOfTwoOrError(literalNode);
if (value != null) {
holder.createErrorAnnotation(element, value);
}
}
}
}
}
}