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}