001package eu.cqse.check.util.clang;
002
003import java.util.List;
004import java.util.Optional;
005
006import org.apache.logging.log4j.LogManager;
007import org.apache.logging.log4j.Logger;
008import org.conqat.lib.commons.assertion.CCSMAssert;
009
010import com.google.common.base.Preconditions;
011
012import eu.cqse.check.util.clang.misra.EEssentialType;
013import eu.cqse.clang.CXCursor;
014import eu.cqse.clang.Clang;
015
016/**
017 * Class for representing a binary operator with type information about both
018 * operands.
019 */
020public class BinaryOperatorExpression {
021
022        private static final Logger LOGGER = LogManager.getLogger();
023
024        /** {@link CXCursor} of the whole binary expression. */
025        public final CXCursor binaryExpressionCursor;
026
027        /** {@link EEssentialType} of the left hand operand. */
028        public final EEssentialType leftHandOperandEssentialType;
029
030        /** {@link EEssentialType} of the right hand operand. */
031        public final EEssentialType rightHandOperandEssentialType;
032
033        /** The operator (e.g. {@code +}, {@code -}, {@code +=}). */
034        public final String operator;
035
036        private BinaryOperatorExpression(CXCursor binaryExpressionCursor, EEssentialType leftHandOperandEssentialType,
037                        EEssentialType rightHandOperandEssentialType, String operator) {
038                this.binaryExpressionCursor = binaryExpressionCursor;
039                this.leftHandOperandEssentialType = leftHandOperandEssentialType;
040                this.rightHandOperandEssentialType = rightHandOperandEssentialType;
041                this.operator = operator;
042        }
043
044        /**
045         * Creates a {@link BinaryOperatorExpression} from the {@link CXCursor} if
046         * possible. Errors are logged in case this fails. The {@link CXCursor} must
047         * satisfy {@link ClangUtils#isBinaryOperatorOrCompoundAssignment(CXCursor)}.
048         */
049        public static Optional<BinaryOperatorExpression> createFromCursor(CXCursor cursor, String fileText) {
050                CCSMAssert.isTrue(ClangUtils.isBinaryOperatorOrCompoundAssignment(cursor),
051                                "Cursor must be of kind CXCursor_BinaryOperator or CXCursor_CompoundAssignOperator to use this "
052                                                + "method. It was " + Clang.clang_getCursorKind(cursor).toString() + " instead.");
053                List<CXCursor> operands = ClangUtils.getDirectChildren(cursor);
054                Preconditions.checkState(operands.size() == 2, "Expected exactly two operands for binary operator.");
055                Optional<String> operator = ClangUtils.getOperatorText(cursor, fileText);
056
057                if (!operator.isPresent()) {
058                        LOGGER.warn("Unable to determine operator for binary operator expression: "
059                                        + ClangUtils.getCompleteNodeText(cursor, fileText));
060                        return Optional.empty();
061                }
062
063                CXCursor leftHandSideOperandCursor = operands.get(0);
064                CXCursor rightHandSideOperandCursor = operands.get(1);
065
066                Optional<EEssentialType> leftHandOperandEssentialType = EEssentialType
067                                .getEssentialTypeOfCursor(leftHandSideOperandCursor);
068                Optional<EEssentialType> rightHandOperandEssentialType = EEssentialType
069                                .getEssentialTypeOfCursor(rightHandSideOperandCursor);
070
071                if (!leftHandOperandEssentialType.isPresent() || !rightHandOperandEssentialType.isPresent()) {
072                        LOGGER.warn("Unable to determine essential type for operands in binary operator: "
073                                        + ClangUtils.getCompleteNodeText(cursor, fileText) + ", leftHandOperandEssentialType="
074                                        + leftHandOperandEssentialType + ", rightHandOperandEssentialType="
075                                        + rightHandOperandEssentialType);
076                        return Optional.empty();
077                }
078
079                return Optional.of(new BinaryOperatorExpression(cursor, leftHandOperandEssentialType.get(),
080                                rightHandOperandEssentialType.get(), operator.get()));
081        }
082}