/*! * \brief Creates an assignment to "pack" a local variable back into * an outlined-function parameter that has been passed as a pointer * value. * * This routine takes the original "unpack" definition, of the form * * TYPE local_unpack_var = *outlined_func_arg; * int i = *(int *)(__out_argv[1]); // parameter wrapping case * * and creates the "re-pack" assignment expression, * * *outlined_func_arg = local_unpack_var * *(int *)(__out_argv[1]) =i; // parameter wrapping case * * C++ variables of reference types do not need this step. */ static SgAssignOp * createPackExpr (SgInitializedName* local_unpack_def) { if (!Outliner::temp_variable) { if (is_C_language()) //skip for pointer dereferencing used in C language return NULL; } // reference types do not need copy the value back in any cases if (isSgReferenceType (local_unpack_def->get_type ())) return NULL; if (local_unpack_def && !isReadOnlyType (local_unpack_def->get_type ())) // && !isSgReferenceType (local_unpack_def->get_type ())) { SgName local_var_name (local_unpack_def->get_name ()); SgAssignInitializer* local_var_init = isSgAssignInitializer (local_unpack_def->get_initializer ()); ROSE_ASSERT (local_var_init); // Create the LHS, which derefs the function argument, by // copying the original dereference expression. // SgPointerDerefExp* param_deref_unpack = isSgPointerDerefExp (local_var_init->get_operand_i ()); if (param_deref_unpack == NULL) { cout<<"packing statement is:"<<local_unpack_def->get_declaration()->unparseToString()<<endl; cout<<"local unpacking stmt's initializer's operand has non-pointer deferencing type:"<<local_var_init->get_operand_i ()->class_name()<<endl; ROSE_ASSERT (param_deref_unpack); } SgPointerDerefExp* param_deref_pack = isSgPointerDerefExp (ASTtools::deepCopy (param_deref_unpack)); ROSE_ASSERT (param_deref_pack); // Create the RHS, which references the local variable. SgScopeStatement* scope = local_unpack_def->get_scope (); ROSE_ASSERT (scope); SgVariableSymbol* local_var_sym = scope->lookup_var_symbol (local_var_name); ROSE_ASSERT (local_var_sym); SgVarRefExp* local_var_ref = SageBuilder::buildVarRefExp (local_var_sym); ROSE_ASSERT (local_var_ref); // Assemble the final assignment expression. return SageBuilder::buildAssignOp (param_deref_pack, local_var_ref); } return 0; }
bool isMethodCall(SgFunctionCallExp *functionCall, bool &isDotExp) { ROSE_ASSERT(functionCall != NULL); SgExpression *expression = functionCall->get_function(); ROSE_ASSERT(expression != NULL); bool isMethod = false; isDotExp = false; switch(expression->variantT()) { case V_SgDotExp: { isMethod = true; SgDotExp *dotExp = isSgDotExp(expression); ROSE_ASSERT(dotExp != NULL); SgExpression *lhs = dotExp->get_lhs_operand(); ROSE_ASSERT(lhs != NULL); SgPointerDerefExp *pointerDerefExp = isSgPointerDerefExp(lhs); if ( pointerDerefExp != NULL ) { ; } else { isDotExp = true; } break; } case V_SgMemberFunctionRefExp: case V_SgArrowExp: { isMethod = true; break; } case V_SgFunctionRefExp: case V_SgPointerDerefExp: { isMethod = false; break; } default: { std::cerr << "Was not expecting an " << expression->sage_class_name() << std::endl; std::cerr << "in a function call." << std::endl; ROSE_ABORT(); } } return isMethod; }
// on other nodes lrRecord (lrRecord &parent, SgNode* n) { SgBinaryOp* binOp; SgUnaryOp* unOp; SgFunctionCallExp* funcCall; //SgPntrArrRefExp* arrRef; char typeStr[100]; // if this node is on the read, write or read-write side of an assignment operation, set its access appropriately if(parent.readSubtree == n) access = readAccess; else if(n == parent.writeSubtree) access = writeAccess; else if(n == parent.rwSubtree) access = rwAccess; else access = parent.access; if((binOp = isSgBinaryOp(n))) { // writeSubtree = readSubtree if(isSgAssignOp(binOp)) { writeSubtree = binOp->get_lhs_operand(); readSubtree = binOp->get_rhs_operand(); rwSubtree = (void*)NULL; strcpy(typeStr, "SgAssignOp"); } // rwSubtree op= readSubtree else if(isSgCompoundAssignOp(binOp)) { rwSubtree = binOp->get_lhs_operand(); readSubtree = binOp->get_rhs_operand(); writeSubtree = (void*)NULL; strcpy(typeStr, "Sg*AssignOp"); } else if(isSgPntrArrRefExp(binOp)) { // all the references involved in an array reference, whether they are used to compute the array name // or used in the argument, are read-only writeSubtree = (void*)NULL; readSubtree = (void*)NULL; readSubtree.wildMatch(); rwSubtree = (void*)NULL; strcpy(typeStr, "SgPntrArrRefExp"); } else { readSubtree = (void*)NULL; writeSubtree = (void*)NULL; rwSubtree = (void*)NULL; strcpy(typeStr, "???"); } //printf("SgBinaryNode 0x%x type %s access=%d: %s\n", binOp, typeStr, access, binOp->unparseToString().c_str()); } else if((unOp = isSgUnaryOp(n))) { // unary update operations have only one operand, which is read-write // writeSubtree if(isSgMinusMinusOp(unOp) || isSgPlusPlusOp(unOp)) { writeSubtree = (void*)NULL; readSubtree = (void*)NULL; rwSubtree = unOp->get_operand(); strcpy(typeStr, "Sg**Op"); } // dereference operations have a read-only operand else if(isSgPointerDerefExp(unOp)) { writeSubtree = (void*)NULL; readSubtree = unOp->get_operand(); rwSubtree = (void*)NULL; strcpy(typeStr, "isSgPointerDerefExp"); } else { readSubtree = (void*)NULL; writeSubtree = (void*)NULL; rwSubtree = (void*)NULL; strcpy(typeStr, "???"); } //printf("SgUnaryNode 0x%x %s access=%d: %s\n", unOp, typeStr, access, unOp->unparseToString().c_str()); } else if((funcCall = isSgFunctionCallExp(n))) { // all the references involved in a function call, whether they are used to compute the function pointer // or used in the argument, are read-only writeSubtree = (void*)NULL; readSubtree = (void*)NULL; readSubtree.wildMatch(); rwSubtree = (void*)NULL; //printf("SgFunctionCall 0x%x access=%d: %s\n", funcCall, access, funcCall->unparseToString().c_str()); } // else, if this is neither a binary, nor unary operation node else { // leave subtree fields of this record as NULL readSubtree = (void*)NULL; writeSubtree = (void*)NULL; rwSubtree = (void*)NULL; //printf("SgNode 0x%x access=%d: %s\n", n, access, n->unparseToString().c_str()); } }
/** * Const-qualify immutable objects * * \todo count assignments, if only one, report violation */ bool DCL00_C( const SgNode *node ) { const SgInitializedName *varName = isSgInitializedName(node); if (!varName) return false; /** * Ignore variables generated by macros */ if ((varName->get_name().getString().substr(0,2) == "__") || isCompilerGeneratedNode(node)) return false; /** * Ignore global variables */ if (isGlobalVar(varName)) return false; /** * Ignore variables that are already const, are function pointers, or are * declared inside of a struct, enum, or as an argument to a function */ SgType *varType = varName->get_type(); if (isConstType(varType) || isConstType(varType->dereference()) || isConstType(varType->dereference()->dereference()) || isSgFunctionType(varType) || isSgClassType(varType) || findParentOfType(varName, SgCtorInitializerList) || findParentOfType(varName, SgEnumDeclaration) || findParentOfType(varName, SgClassDeclaration)) return false; /** * DCL13-C is a subset of this rule, figure out which rule we are dealing * with here */ std::string ruleStr; std::string errStr; if (findParentOfType(varName, SgFunctionParameterList)) { /** ignore function prototypes, just worry about the definitions */ const SgFunctionDeclaration *fnDecl = findParentOfType(varName, SgFunctionDeclaration); /** * Disabling assertion due to C++ code */ if (!fnDecl) return false; // assert(fnDecl); if (!fnDecl->get_definition()) return false; if (isSgPointerType(varName->get_type()) || isSgArrayType(varName->get_type())) { ruleStr = "DCL13-C"; errStr = "Declare function parameters that are pointers to values not changed by the function as const: "; } else { return false; } } else { ruleStr = "DCL00-C"; errStr = "Const-qualify immutable objects: "; } /** * Ignore global variables or variables declared as extern */ const SgScopeStatement *varScope = varName->get_scope(); if (isSgGlobal(varScope) || isExternVar(varName)) return false; FOREACH_SUBNODE(varScope, nodes, i, V_SgVarRefExp) { const SgVarRefExp *iVar = isSgVarRefExp(*i); assert(iVar); if (getRefDecl(iVar) != varName) continue; const SgNode *parent = iVar->get_parent(); while(isSgCastExp(parent)) { parent = parent->get_parent(); } assert(parent); /** * If the variable is written to or it's address is taken, we can no * longer be sure it should be const, if it's a struct and gets * dereferenced, who knows what's getting written there :/ */ if (varWrittenTo(iVar) || isSgArrowExp(parent) || findParentOfType(iVar, SgAddressOfOp)) return false; /** * If the variable is a pointer or array, and we pass it to a function * or as an argument to pointer arithmetic, or assign it's value * somewhere, we can longer be sure it should be const */ if ((isSgPointerType(varType) || isSgArrayType(varType)) && (findParentOfType(iVar, SgFunctionCallExp) || isSgAddOp(parent) || isSgSubtractOp(parent) || isSgAssignOp(parent) || isSgPntrArrRefExp(parent) || isSgPointerDerefExp(parent) || isSgAssignInitializer(parent))) return false; } const std::string msg = errStr + varName->get_name().getString(); print_error(node, ruleStr.c_str(), msg.c_str(), true); return true; }