/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1989-1999 Microsoft Corporation Module Name: fldattr.cxx Abstract: field attribute handling routines Notes: Author: GregJen Oct-27-1993 Created. Notes: ----------------------------------------------------------------------------*/ #pragma warning ( disable : 4514 ) /**************************************************************************** * include files ***************************************************************************/ #include "allnodes.hxx" #include "fldattr.hxx" #include "semantic.hxx" /**************************************************************************** * local data ***************************************************************************/ expr_constant * pZero = NULL; expr_constant * pOne = NULL; node_skl * pInt = NULL; /**************************************************************************** * externs ***************************************************************************/ /**************************************************************************** * definitions ***************************************************************************/ ///////////////// // helper routines for Normalize functions; //Don't add or subtract 0. expr_node * CreateSimpleBinaryArithExpression( OPERATOR Op, expr_node * pL, expr_node * pR ) { MIDL_ASSERT( (Op==OP_PLUS) || (Op==OP_MINUS) ); MIDL_ASSERT( pL ); MIDL_ASSERT( pR ); if ( pR->IsConstant() && (pR->GetValue() == 0) ) return pL; if ( pL->IsConstant() && (pL->GetValue() == 0) ) return pR; expr_node * pRet = new expr_b_arithmetic( Op, pL, pR ); if ( pL->GetType() ) pRet->SetType( pL->GetType() ); else if ( pR->GetType() ) pRet->SetType( pR->GetType() ); else MIDL_ASSERT( !"no type for expression" ); return pRet; } // return the constant 0 over and over expr_constant * GetConstant0() { if ( pZero ) return pZero; pZero = new expr_constant( 0L, VALUE_TYPE_NUMERIC ); if ( !pInt ) GetBaseTypeNode( &pInt, SIGN_SIGNED, SIZE_UNDEF, TYPE_INT ); pZero->SetType( pInt ); return pZero; } // return the constant 1 over and over expr_constant * GetConstant1() { if ( pOne ) return pOne; pOne = new expr_constant( 1L, VALUE_TYPE_NUMERIC ); if ( !pInt ) GetBaseTypeNode( &pInt, SIGN_SIGNED, SIZE_UNDEF, TYPE_INT ); pOne->SetType( pInt ); return pOne; } BOOL IsInValidOutOnly( SEM_ANALYSIS_CTXT * pCtxt ) { // an out-only size is valid only on out-only non-top-level things // in, in/out things not allowed if ( pCtxt->AnyAncestorBits( UNDER_IN_PARAM ) ) return TRUE; // look up the stack for a pointer (or array) that is unique SEM_ANALYSIS_CTXT * pCurCtxt = pCtxt; NODE_T Kind; node_skl * pNode; while ( pCurCtxt ) { pNode = pCurCtxt->GetParent(); Kind = pNode->NodeKind(); switch ( Kind ) { case NODE_DEF: case NODE_ARRAY: break; case NODE_POINTER: if ( pCtxt->AnyAncestorBits( IN_NON_REF_PTR ) ) return FALSE; break; case NODE_PARAM: case NODE_PROC: default: return TRUE; } pCurCtxt = ( SEM_ANALYSIS_CTXT * ) pCurCtxt->GetParentContext(); } return TRUE; } BOOL Xxx_Is_Type_OK( node_skl * pType) { if ( !pType ) return FALSE; for (;;) { switch ( pType->NodeKind() ) { case NODE_PARAM: case NODE_FIELD: if ( !pType->GetChild() ) return FALSE; break; // make sure that there is no transmit_as or represent_as case NODE_DEF: if ( pType->FInSummary( ATTR_TRANSMIT ) || pType->FInSummary( ATTR_REPRESENT_AS ) || pType->FInSummary( ATTR_USER_MARSHAL ) || pType->FInSummary( ATTR_WIRE_MARSHAL ) ) return FALSE; break; // for an ID, make sure it is a const decl, then use its type case NODE_ID: { node_id * pID = (node_id *) pType; if ( !pID->pInit ) return FALSE; break; } case NODE_ENUM: case NODE_LONG: case NODE_SHORT: case NODE_INT: case NODE_INT32: case NODE_SMALL: case NODE_CHAR: case NODE_BOOLEAN: case NODE_BYTE: return TRUE; // 64b expr support case NODE_INT3264: case NODE_INT64: case NODE_HYPER: return FALSE; // no 128b expr support case NODE_INT128: case NODE_FLOAT80: case NODE_FLOAT128: return FALSE; default: return FALSE; } pType = pType->GetChild(); } } BOOL IID_Is_Type_OK( node_skl * pType ) { if ( !pType ) return FALSE; for (;;) { switch ( pType->NodeKind() ) { case NODE_PARAM: case NODE_FIELD: if ( !pType->GetChild() ) return FALSE; break; case NODE_DEF: if ( pType->FInSummary( ATTR_TRANSMIT ) || pType->FInSummary( ATTR_REPRESENT_AS ) || pType->FInSummary( ATTR_USER_MARSHAL ) || pType->FInSummary( ATTR_WIRE_MARSHAL ) ) return FALSE; break; case NODE_POINTER: if ( pType->GetChild() ) return ( 16 == pType->GetChild()->GetSize() ); default: return FALSE; } pType = pType->GetChild(); } } // validate the bunch of attributes for pointers: check combinations, ranges, // and expressions void FIELD_ATTR_INFO::Validate( SEM_ANALYSIS_CTXT * pCtxt ) { if ( Kind == FA_NONE ) return; node_skl * pParent = pCtxt->GetParent(); // things to check: // expression types (must be integral types) if ( pMaxIsExpr ) { EXPR_CTXT MaxCtxt( pCtxt ); pMaxIsExpr->ExprAnalyze( &MaxCtxt ); if ( MaxCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( MaxCtxt.AnyUpFlags( EX_OUT_ONLY_PARAM ) && IsInValidOutOnly( pCtxt ) ) RpcSemError( pParent, *pCtxt, SIZE_SPECIFIER_CANT_BE_OUT, NULL ); if ( !MaxCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pMaxIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) RpcSemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pMinIsExpr ) { EXPR_CTXT MinCtxt( pCtxt ); pMinIsExpr->ExprAnalyze( &MinCtxt ); if ( MinCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) RpcSemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( MinCtxt.AnyUpFlags( EX_OUT_ONLY_PARAM ) && IsInValidOutOnly( pCtxt ) ) SemError( pParent, *pCtxt, SIZE_SPECIFIER_CANT_BE_OUT, NULL ); if ( !MinCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pMinIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pSizeIsExpr ) { EXPR_CTXT SizeCtxt( pCtxt ); pSizeIsExpr->ExprAnalyze( &SizeCtxt ); if ( SizeCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( SizeCtxt.AnyUpFlags( EX_OUT_ONLY_PARAM ) && IsInValidOutOnly( pCtxt ) ) SemError( pParent, *pCtxt, SIZE_SPECIFIER_CANT_BE_OUT, NULL ); if ( !SizeCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pSizeIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pFirstIsExpr ) { EXPR_CTXT FirstCtxt( pCtxt ); pFirstIsExpr->ExprAnalyze( &FirstCtxt ); if ( FirstCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( !FirstCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pFirstIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pLastIsExpr ) { EXPR_CTXT LastCtxt( pCtxt ); pLastIsExpr->ExprAnalyze( &LastCtxt ); if ( LastCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( !LastCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pLastIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pLengthIsExpr ) { EXPR_CTXT LengthCtxt( pCtxt ); pLengthIsExpr->ExprAnalyze( &LengthCtxt ); if ( LengthCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( !LengthCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pLengthIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pIIDIsExpr ) { EXPR_CTXT IIDCtxt( pCtxt ); pIIDIsExpr->ExprAnalyze( &IIDCtxt ); if ( IIDCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( !IIDCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !IID_Is_Type_OK( pIIDIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, IID_IS_EXPR_NON_POINTER, NULL ); } // min_is == 0 ( for now ) // constant min_is <= constant max_is // size_is not with max_is if ( pMaxIsExpr && pSizeIsExpr ) SemError( pParent, *pCtxt, MAX_AND_SIZE, NULL ); // min_is not alone // constant first_is <= constant last_is + 1 // length_is not with last_is if ( pLengthIsExpr && pLastIsExpr ) SemError( pParent, *pCtxt, LAST_AND_LENGTH, NULL ); // constant first_is, last_is both within min<->max range // length_is <= size_is // string attrs not with varying attrs // string and bstring not together // conformant strings may leave out size_is if [in] or [in,out] // accept the NULL value ( turn expression back null, clear kind bits ) // make sure variables come from the correct context // lengthed, unsized pointer if ( ( pLengthIsExpr || pFirstIsExpr || pLastIsExpr || pMinIsExpr) && !( pSizeIsExpr || pMaxIsExpr ) ) SemError( pParent, *pCtxt, UNSIZED_ARRAY, NULL ); } void FIELD_ATTR_INFO::Validate( SEM_ANALYSIS_CTXT * pCtxt, expr_node * pLower, expr_node * pUpper ) { node_skl * pParent = pCtxt->GetParent(); if ( pUpper == (expr_node *) -1 ) { pUpper = NULL; Kind |= FA_CONFORMANT; } else if ( pUpper ) { if ( pUpper->GetValue() <= 0 ) { SemError( pParent, *pCtxt, ILLEGAL_ARRAY_BOUNDS, NULL ); } } if ( pLower && ( pLower != (expr_node *) -1 ) && ( pLower->GetValue() != 0 ) ) { SemError( pParent, *pCtxt, ARRAY_BOUNDS_CONSTRUCT_BAD, NULL ); } if ( pUpper && ( pMaxIsExpr || pSizeIsExpr ) ) { SemError( pParent, *pCtxt, SIZING_ON_FIXED_ARRAYS, NULL ); } // things to check: // expression types (must be integral types) if ( pMaxIsExpr ) { EXPR_CTXT MaxCtxt( pCtxt ); pMaxIsExpr->ExprAnalyze( &MaxCtxt ); if ( MaxCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( MaxCtxt.AnyUpFlags( EX_OUT_ONLY_PARAM ) ) SemError( pParent, *pCtxt, SIZE_SPECIFIER_CANT_BE_OUT, NULL ); if ( !MaxCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pMaxIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pMinIsExpr ) { EXPR_CTXT MinCtxt( pCtxt ); pMinIsExpr->ExprAnalyze( &MinCtxt ); if ( MinCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( MinCtxt.AnyUpFlags( EX_OUT_ONLY_PARAM ) ) SemError( pParent, *pCtxt, SIZE_SPECIFIER_CANT_BE_OUT, NULL ); if ( !MinCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pMinIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pSizeIsExpr ) { EXPR_CTXT SizeCtxt( pCtxt ); pSizeIsExpr->ExprAnalyze( &SizeCtxt ); if ( SizeCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( SizeCtxt.AnyUpFlags( EX_OUT_ONLY_PARAM ) ) SemError( pParent, *pCtxt, SIZE_SPECIFIER_CANT_BE_OUT, NULL ); if ( !SizeCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pSizeIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pFirstIsExpr ) { EXPR_CTXT FirstCtxt( pCtxt ); pFirstIsExpr->ExprAnalyze( &FirstCtxt ); if ( FirstCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( !FirstCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pFirstIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pLastIsExpr ) { EXPR_CTXT LastCtxt( pCtxt ); pLastIsExpr->ExprAnalyze( &LastCtxt ); if ( LastCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( !LastCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pLastIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pLengthIsExpr ) { EXPR_CTXT LengthCtxt( pCtxt ); pLengthIsExpr->ExprAnalyze( &LengthCtxt ); if ( LengthCtxt.AnyUpFlags( EX_UNSAT_FWD ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_UNRESOLVED, NULL ); if ( !LengthCtxt.AnyUpFlags( EX_VALUE_INVALID ) ) SemError( pParent, *pCtxt, ATTRIBUTE_ID_MUST_BE_VAR, NULL ); if ( !Xxx_Is_Type_OK( pLengthIsExpr->GetType() ) && pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, ATTR_MUST_BE_INT, NULL ); } if ( pIIDIsExpr ) { SemError( pParent, *pCtxt, IID_IS_NON_POINTER, NULL ); } // min_is == 0 ( for now ) // constant min_is <= constant max_is // size_is not with max_is if ( pMaxIsExpr && pSizeIsExpr ) SemError( pParent, *pCtxt, MAX_AND_SIZE, NULL ); // a conformant unsized array: // must have string // must not be out_only if ( ( Kind & FA_CONFORMANT ) && !pMaxIsExpr && !pSizeIsExpr && !pUpper ) { if ( !( Kind & FA_STRING ) ) { if ( pCtxt->AnyAncestorBits( IN_RPC ) ) SemError( pParent, *pCtxt, UNSIZED_ARRAY, NULL ); } else { if ( pCtxt->AllAncestorBits( IN_RPC | IN_PARAM_LIST | UNDER_OUT_PARAM ) && !pCtxt->AnyAncestorBits( UNDER_IN_PARAM ) ) SemError( pParent, *pCtxt, DERIVES_FROM_UNSIZED_STRING, NULL ); } } // min_is not alone // constant first_is <= constant last_is + 1 // length_is not with last_is if ( pLengthIsExpr && pLastIsExpr ) SemError( pParent, *pCtxt, LAST_AND_LENGTH, NULL ); // constant first_is, last_is both within min<->max range // length_is <= size_is // string attrs not with varying attrs // string and bstring not together // conformant strings may leave out size_is if [in] or [in,out] // accept the NULL value ( turn expression back null, clear kind bits ) // make sure variables come from the correct context } // // normalize for pointers ( no default bound ) void FIELD_ATTR_INFO::Normalize() { expr_node * pTmp1; expr_node * pTmp2; // convert the set: min_is, max_is, size_is to min_is + size_is if ( Kind & FA_CONFORMANT ) { // default min_is is 0 if ( ! pMinIsExpr ) { pMinIsExpr = GetConstant0(); } // size_is = (max_is - min_is) + 1; if ( ! pSizeIsExpr ) { if ( pMaxIsExpr ) { pTmp1 = GetConstant1(); pTmp2 = CreateSimpleBinaryArithExpression( OP_MINUS, pMaxIsExpr, pMinIsExpr); pSizeIsExpr = CreateSimpleBinaryArithExpression( OP_PLUS, pTmp2, pTmp1 ); } } } // convert the set: first_is, last_is, length_is to: first_is + length_is if ( Kind & FA_VARYING ) { // default first_is is 0 if ( ! pFirstIsExpr ) { pFirstIsExpr = GetConstant0(); } // default last_is is max_is or size_is+1 if ( ! pLastIsExpr ) { if ( pMaxIsExpr ) pLastIsExpr = pMaxIsExpr; else if ( pSizeIsExpr ) pLastIsExpr = CreateSimpleBinaryArithExpression( OP_MINUS, pSizeIsExpr, GetConstant1() ); } // length_is = (last_is - first_is) + 1; if ( ! pLengthIsExpr ) { if ( pLastIsExpr ) { pTmp1 = GetConstant1(); pTmp2 = CreateSimpleBinaryArithExpression( OP_MINUS, pLastIsExpr, pFirstIsExpr); pLengthIsExpr = CreateSimpleBinaryArithExpression( OP_PLUS, pTmp2, pTmp1 ); } } } } // normalize for arrays (provided lower and upper bound) void FIELD_ATTR_INFO::Normalize(expr_node * pLower, expr_node * pUpper) { expr_node * pTmp1; expr_node * pTmp2; BOOL OneBound = FALSE; if ( pLower == (expr_node *) 0 ) { pLower = GetConstant0(); OneBound = TRUE; } if ( pUpper == (expr_node *) -1 ) { pUpper = NULL; Kind |= FA_CONFORMANT; } // convert the set: min_is, max_is, size_is to: min_is + size_is // first, copy from the bounds if ( ! pMinIsExpr ) { pMinIsExpr = pLower; } if ( ! pMaxIsExpr && ! pSizeIsExpr && pUpper ) { // note that the [n..m] case has m already incremented by 1 pTmp1 = GetConstant1(); pMaxIsExpr = CreateSimpleBinaryArithExpression( OP_MINUS, pUpper, pTmp1 ); } // size_is = (max_is - min_is) + 1; if ( ! pSizeIsExpr ) { if ( pMaxIsExpr ) { pTmp1 = GetConstant1(); pTmp2 = CreateSimpleBinaryArithExpression( OP_MINUS, pMaxIsExpr, pMinIsExpr); pSizeIsExpr = CreateSimpleBinaryArithExpression( OP_PLUS, pTmp2, pTmp1 ); } } // convert the set: first_is, last_is, length_is to: first_is + length_is // default first_is is min_is if ( ! pFirstIsExpr ) { pFirstIsExpr = pMinIsExpr; } // default last_is is max_is or size_is+1 if ( ! pLastIsExpr ) { if ( pMaxIsExpr ) pLastIsExpr = pMaxIsExpr; else if ( pSizeIsExpr ) pLastIsExpr = CreateSimpleBinaryArithExpression( OP_MINUS, pSizeIsExpr, GetConstant1() ); } // length_is = (last_is - first_is) + 1; if ( ! pLengthIsExpr ) { if ( pLastIsExpr ) { pTmp1 = GetConstant1(); pTmp2 = CreateSimpleBinaryArithExpression( OP_MINUS, pLastIsExpr, pFirstIsExpr); pLengthIsExpr = CreateSimpleBinaryArithExpression( OP_PLUS, pTmp2, pTmp1 ); } } } bool FIELD_ATTR_INFO::VerifyOnlySimpleExpression() { const int nExprTypes = 7; expr_node *pExpr[nExprTypes] = { pSizeIsExpr, pMinIsExpr, pMaxIsExpr, pLengthIsExpr, pFirstIsExpr, pIIDIsExpr, pLastIsExpr, }; for ( int i = 0; i < nExprTypes; i++ ) { // No expression is ok if ( NULL == pExpr[i] ) continue; // A simple variable is ok if ( pExpr[i]->IsAVariable() ) continue; // A pointer to a simple variable is ok if ( OP_UNARY_INDIRECTION == pExpr[i]->GetOperator() && pExpr[i]->GetLeft()->IsAVariable() ) { continue; } // Everything else is not ok return false; } return true; } BOOL FIELD_ATTR_INFO::SetExpressionVariableUsage( SIZE_LENGTH_USAGE ) { return TRUE; } #if 0 BUGBUG: CG_INTERFACE_POINTER has a bug. See nodeskl.h for details BOOL FIELD_ATTR_INFO::SetExpressionVariableUsage( SIZE_LENGTH_USAGE usage ) { const int nExprTypes = 7; expr_node *pExpr[nExprTypes] = { pSizeIsExpr, pMinIsExpr, pMaxIsExpr, pLengthIsExpr, pFirstIsExpr, pIIDIsExpr, pLastIsExpr, }; for ( int i = 0; i < nExprTypes; i++ ) if ( ! SetExpressionVariableUsage( pExpr[i], usage ) ) return false; return true; } BOOL FIELD_ATTR_INFO::SetExpressionVariableUsage( expr_node *pExpr, SIZE_LENGTH_USAGE usage ) { if ( !pExpr ) return true; if ( pExpr->IsAVariable() ) { node_skl *pParent = NULL; node_skl *pType = pExpr->GetType(); while ( NULL != pType && !pType->IsBasicType() ) { pParent = pType; pType = pType->GetChild(); } if ( NULL != pType && pType->IsBasicType() ) { SIZE_LENGTH_USAGE TypeUsage = ((node_base_type *) pType) ->GetSizeLengthUsage(); if ( CSSizeLengthUsage == usage && NoSizeLengthUsage != TypeUsage ) { return FALSE; } if ( CSSizeLengthUsage == TypeUsage && NoSizeLengthUsage != usage ) { return FALSE; } if ( NoSizeLengthUsage != usage ) { // Typically base type nodes are preallocated and identical. // Pointing at them with size_is, etc makes the different // because we need to note that fact. So clone it to get // a new one. MIDL_ASSERT( NULL != pParent ); pType = new node_base_type( (node_base_type *) pType ); ((node_base_type *) pType)->SetSizeLengthUsage( usage ); pParent->SetChild( pType ); } } } if ( ! SetExpressionVariableUsage( pExpr->GetLeft(), usage ) ) return false; return SetExpressionVariableUsage( pExpr->GetRight(), usage ); } #endif