package glslplugin.annotation.impl;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.util.containers.HashSet;
import glslplugin.annotation.Annotator;
import glslplugin.lang.elements.expressions.GLSLExpression;
import glslplugin.lang.elements.statements.GLSLCaseStatement;
import glslplugin.lang.elements.statements.GLSLDefaultStatement;
import glslplugin.lang.elements.statements.GLSLLabelStatement;
import glslplugin.lang.elements.statements.GLSLSwitchStatement;
import glslplugin.lang.elements.types.GLSLScalarType;
import glslplugin.lang.elements.types.GLSLType;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Set;
/**
* Switch statements can only operate on integer expressions.
* This checks that correct expression type is used and warns otherwise.
* <p/>
* Also checks for constant expressions and warns on them.
* <p/>
* For label statements, it is checked that:
* - max one default label exists
* - all case label types are integer scalars
* - no case labels are duplicated
*
* @author Darkyen
*/
public class SwitchAnnotation extends Annotator<GLSLSwitchStatement> {
@Override
public void annotate(GLSLSwitchStatement expr, AnnotationHolder holder) {
final GLSLExpression switchCondition = expr.getSwitchCondition();
if (switchCondition == null) return;
final GLSLType switchConditionType = switchCondition.getType();
if (!switchConditionType.isValidType()) return;
if (!GLSLScalarType.isIntegerScalar(switchConditionType)) {
holder.createErrorAnnotation(switchCondition, "Expression must be of integer scalar type");
} else if (switchCondition.isConstantValue()) {
holder.createWeakWarningAnnotation(switchCondition, "Expression is constant");
}
final List<GLSLLabelStatement> labelStatements = expr.getLabelStatements();
Set<Object> encounteredCases = new HashSet<Object>();
boolean defaultFound = false;
for (GLSLLabelStatement label : labelStatements) {
if (label instanceof GLSLDefaultStatement) {
if (defaultFound) {
holder.createErrorAnnotation(label, "Multiple default labels are not allowed");
}
defaultFound = true;
} else if (label instanceof GLSLCaseStatement) {//This _should_ be the only possible way
final GLSLCaseStatement caseLabel = (GLSLCaseStatement) label;
final GLSLExpression caseExpression = caseLabel.getCaseExpression();
if (caseExpression != null) {
final GLSLType caseExpressionType = caseExpression.getType();
if (caseExpressionType.isValidType()) {
if (!GLSLScalarType.isIntegerScalar(caseExpressionType)) {
holder.createErrorAnnotation(caseExpression, "Case expression must be of integer scalar type");
} else {
//It is a valid type, do dupe check
if (caseExpression.isConstantValue()) {
Object constantValue = caseExpression.getConstantValue();
//constantValue should be Long, but don't dwell on that
if (encounteredCases.contains(constantValue)) {
holder.createWarningAnnotation(caseExpression, "Duplicate case label (" + constantValue + ")");
}
encounteredCases.add(constantValue);
}
}
}
}
}
}
}
@NotNull
@Override
public Class<GLSLSwitchStatement> getElementType() {
return GLSLSwitchStatement.class;
}
}