/***************************************************Project Mutator****************************************************/
//-*-c++-*-
/*first line intentionally left blank.*/
/*the source code for SaferCPP's automatic refactoring of C/C++ arrays.*/
/*Copyright (C) 2017 Noah L.,Farzad Sadeghi
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/
/*code structure inspired by Eli Bendersky's tutorial on Rewriters.*/
/**********************************************************************************************************************/
/**********************************************************************************************************************/
/*included modules*/
/*Project Headers*/
#include "safercpp-arr.h"
#include "../mutator_aux.h"
/*Standard headers*/
#include <string>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <locale>
/*Clang Headers*/
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Rewrite/Core/Rewriter.h"
/*LLVM Headers*/
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Function.h"
/**********************************************************************************************************************/
/*used namespaces*/
using namespace llvm;
using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::driver;
using namespace clang::tooling;
/**********************************************************************************************************************/
static llvm::cl::OptionCategory MatcherSampleCategory("TBD");
cl::opt<bool> CheckSystemHeader("SysHeader", cl::desc("safercpp will run through System Headers"), cl::init(false), cl::cat(MatcherSampleCategory), cl::ZeroOrMore);
cl::opt<bool> MainFileOnly("MainOnly", cl::desc("safercpp will only report the results that reside in the main file"), cl::init(false), cl::cat(MatcherSampleCategory), cl::ZeroOrMore);
cl::opt<bool> SafeSubset("SafeSubset", cl::desc("safercpp will check for elements outside of the (memory) safe subset of the language"), cl::init(true), cl::cat(MatcherSampleCategory), cl::ZeroOrMore);
cl::opt<bool> ConvertToSCPP("ConvertToSCPP", cl::desc("safercpp will translate the source to a (memory) safe subset of the language"), cl::init(false), cl::cat(MatcherSampleCategory), cl::ZeroOrMore);
/**********************************************************************************************************************/
SourceRange nice_source_range(const SourceRange& sr, Rewriter &Rewrite) {
SourceLocation SL = sr.getBegin();
SourceLocation SLE = sr.getEnd();
if (SL.isMacroID() || SLE.isMacroID()) {
int q = 5;
}
SL = Devi::SourceLocationHasMacro(SL, Rewrite, "start");
SLE = Devi::SourceLocationHasMacro(SLE, Rewrite, "end");
return SourceRange(SL, SLE);
}
bool filtered_out_by_location(const ast_matchers::MatchFinder::MatchResult &MR, SourceLocation SL) {
bool retval = false;
if (Devi::IsTheMatchInSysHeader(CheckSystemHeader, MR, SL)) {
retval = true;
} else if (!Devi::IsTheMatchInMainFile(MainFileOnly, MR, SL)) {
retval = true;
} else {
bool filename_is_invalid = false;
std::string full_path_name = MR.SourceManager->getBufferName(SL, &filename_is_invalid);
std::string filename = full_path_name;
auto last_slash_pos = full_path_name.find_last_of('/');
if (std::string::npos != last_slash_pos) {
if (last_slash_pos + 1 < full_path_name.size()) {
filename = full_path_name.substr(last_slash_pos+1);
} else {
filename = "";
}
}
static const std::string mse_str = "mse";
if (0 == filename.compare(0, mse_str.size(), mse_str)) {
retval = true;
}
}
return retval;
}
static std::string with_whitespace_removed(const std::string& str) {
std::string retval = str;
retval.erase(std::remove_if(retval.begin(), retval.end(), isspace), retval.end());
return retval;
}
static std::string with_newlines_removed(const std::string& str) {
std::string retval = str;
auto riter1 = retval.rbegin();
while (retval.rend() != riter1) {
if ('\n' == *riter1) {
auto riter2 = riter1;
riter2++;
retval.erase(riter1.base()--);
while (retval.rend() != riter2) {
/* look for and remove 'continued on the next line' backslash if present. */
if ('\\' == (*riter2)) {
riter1++;
retval.erase(riter2.base()--);
break;
} else if (!std::isspace(*riter2)) {
break;
}
riter2++;
}
}
riter1++;
}
return retval;
}
/* No longer used. This function extracts the text of individual declarations when multiple
* pointers are declared in the same declaration statement. */
static std::vector<std::string> f_declared_object_strings(const std::string& decl_stmt_str) {
std::vector<std::string> retval;
auto nice_decl_stmt_str = with_newlines_removed(decl_stmt_str);
auto semicolon_position = std::string::npos;
for (size_t pos = 3; pos < nice_decl_stmt_str.size(); pos += 1) {
if (';' == nice_decl_stmt_str[pos]) {
semicolon_position = pos;
}
}
if (std::string::npos == semicolon_position) {
assert(false);
return retval;
}
std::vector<size_t> delimiter_positions;
for (size_t pos = 3; ((pos < nice_decl_stmt_str.size()) && (pos < semicolon_position)); pos += 1) {
if (',' == nice_decl_stmt_str[pos]) {
delimiter_positions.push_back(pos);
}
}
delimiter_positions.push_back(semicolon_position);
auto first_delimiter_pos = delimiter_positions[0];
{
auto pos1 = first_delimiter_pos - 1;
auto pos2 = pos1;
bool nonspace_found = false;
while ((2 <= pos1) && (!nonspace_found)) {
if (!std::isspace(nice_decl_stmt_str[pos1])) {
pos2 = pos1 + 1;
nonspace_found = true;
}
pos1 -= 1;
}
if (!nonspace_found) {
assert(false);
return retval;
}
bool space_found = false;
while ((1 <= pos1) && (!space_found)) {
if (std::isspace(nice_decl_stmt_str[pos1])) {
space_found = true;
}
pos1 -= 1;
}
if (!space_found) {
assert(false);
return retval;
}
pos1 += 2;
std::string first_declaration_string = nice_decl_stmt_str.substr(pos1, pos2 - pos1);
retval.push_back(first_declaration_string);
}
{
size_t delimiter_index = 0;
while (delimiter_positions.size() > (delimiter_index + 1)) {
if (!(delimiter_positions[delimiter_index] + 1 < delimiter_positions[(delimiter_index + 1)])) {
//assert(false);
} else {
std::string declaration_string = nice_decl_stmt_str.substr(delimiter_positions[delimiter_index] + 1, delimiter_positions[(delimiter_index + 1)] - (delimiter_positions[delimiter_index] + 1));
retval.push_back(declaration_string);
}
delimiter_index += 1;
}
}
return retval;
}
class CState1;
class CReplacementAction {
public:
virtual ~CReplacementAction() {}
virtual void do_replacement(CState1& state1) const = 0;
};
std::string tolowerstr(const std::string& a) {
std::string retval;
for (const auto& ch : a) {
retval += tolower(ch);
}
return retval;
}
/* This function returns a list of individual declarations contained in the same declaration statement
* as the given declaration. (eg.: "int a, b = 3, *c;" ) */
static std::vector<const DeclaratorDecl*> IndividualDeclaratorDecls(const DeclaratorDecl* DD, Rewriter &Rewrite) {
/* There's probably a more efficient way to do this, but this implementation seems to work. */
std::vector<const DeclaratorDecl*> retval;
if (!DD) {
assert(false);
return retval;
}
auto SR = nice_source_range(DD->getSourceRange(), Rewrite);
SourceLocation SL = SR.getBegin();
std::string source_text;
if (SR.isValid()) {
source_text = Rewrite.getRewrittenText(SR);
} else {
return retval;
}
auto decl_context = DD->getDeclContext();
if ((!decl_context) || (!SL.isValid())) {
assert(false);
retval.push_back(DD);
} else {
for (auto decl_iter = decl_context->decls_begin(); decl_iter != decl_context->decls_end(); decl_iter++) {
auto decl = (*decl_iter);
auto l_DD = dynamic_cast<const DeclaratorDecl*>(decl);
if (l_DD) {
auto DDSR = nice_source_range(l_DD->getSourceRange(), Rewrite);
SourceLocation l_SL = DDSR.getBegin();
if (l_SL == SL) {
retval.push_back(l_DD);
}
}
}
}
if (0 == retval.size()) {
//assert(false);
int q = 7;
}
return retval;
}
/* This class specifies a declaration and a level of "indirection"(/"dereference") relative to the declared
* object. For example, given the declaration "int **var1[5];", (*var1) and (**var1) are 1 and 2 "levels of
* indirection", respectively, relative to var1. */
class CDDeclIndirection {
public:
CDDeclIndirection(const clang::DeclaratorDecl& ddecl_cref, size_t indirection_level = 0) :
m_ddecl_cptr(&ddecl_cref), m_indirection_level(indirection_level) {}
CDDeclIndirection(const CDDeclIndirection&) = default;
bool operator <(const CDDeclIndirection &rhs) const {
if (m_ddecl_cptr == rhs.m_ddecl_cptr) {
return (m_indirection_level < rhs.m_indirection_level);
} else {
return (m_ddecl_cptr < rhs.m_ddecl_cptr);
}
}
const clang::DeclaratorDecl* m_ddecl_cptr = nullptr;
size_t m_indirection_level = 0;
};
class CDDecl2ReplacementAction : public CReplacementAction {
public:
CDDecl2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR,
const CDDeclIndirection& ddecl_indirection) : m_Rewrite(Rewrite), m_MR(MR), m_ddecl_indirection(ddecl_indirection) {
}
virtual ~CDDecl2ReplacementAction() {}
virtual void do_replacement(CState1& state1) const = 0;
virtual const clang::DeclaratorDecl* get_ddecl_cptr() const { return m_ddecl_indirection.m_ddecl_cptr; }
virtual const CDDeclIndirection& ddecl_indirection_cref() const { return m_ddecl_indirection; }
clang::SourceRange source_range() {
clang::SourceRange retval = m_ddecl_indirection.m_ddecl_cptr->getSourceRange();
return retval;
}
clang::SourceLocation start_location() {
clang::SourceLocation retval = source_range().getBegin();
return retval;
}
std::string get_var_name() {
std::string retval = m_ddecl_indirection.m_ddecl_cptr->getNameAsString();
return retval;
}
Rewriter& m_Rewrite;
const MatchFinder::MatchResult m_MR;
CDDeclIndirection m_ddecl_indirection;
};
class CArray2ReplacementAction : public CDDecl2ReplacementAction {
public:
using CDDecl2ReplacementAction::CDDecl2ReplacementAction;
virtual ~CArray2ReplacementAction() {}
};
class CDynamicArray2ReplacementAction : public CArray2ReplacementAction {
public:
using CArray2ReplacementAction::CArray2ReplacementAction;
virtual ~CDynamicArray2ReplacementAction() {}
};
class CSetArrayPointerToNull2ReplacementAction : public CDynamicArray2ReplacementAction {
public:
CSetArrayPointerToNull2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection,
const BinaryOperator* BO, const std::string& bo_replacement_code) :
CDynamicArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_BO(BO), m_DD(ddecl_indirection.m_ddecl_cptr),
m_bo_replacement_code(bo_replacement_code) {
}
virtual ~CSetArrayPointerToNull2ReplacementAction() {}
virtual void do_replacement(CState1& state1) const;
const BinaryOperator* m_BO = nullptr;
//const DeclRefExpr* m_DRE = nullptr;
//const MemberExpr* m_ME = nullptr;
const DeclaratorDecl* m_DD = nullptr;
std::string m_bo_replacement_code;
};
class CFreeDynamicArray2ReplacementAction : public CDynamicArray2ReplacementAction {
public:
CFreeDynamicArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection,
const CallExpr* CE, const std::string& ce_replacement_code) :
CDynamicArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_CE(CE), m_DD(ddecl_indirection.m_ddecl_cptr),
m_ce_replacement_code(ce_replacement_code) {
}
virtual ~CFreeDynamicArray2ReplacementAction() {}
virtual void do_replacement(CState1& state1) const;
const CallExpr* m_CE = nullptr;
//const DeclRefExpr* m_DRE = nullptr;
//const MemberExpr* m_ME = nullptr;
const DeclaratorDecl* m_DD = nullptr;
std::string m_ce_replacement_code;
};
class CMallocArray2ReplacementAction : public CDynamicArray2ReplacementAction {
public:
CMallocArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection,
const BinaryOperator* BO, const std::string& bo_replacement_code) :
CDynamicArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_BO(BO), m_DD(ddecl_indirection.m_ddecl_cptr),
m_bo_replacement_code(bo_replacement_code) {
}
virtual ~CMallocArray2ReplacementAction() {}
virtual void do_replacement(CState1& state1) const;
const BinaryOperator* m_BO = nullptr;
//const CallExpr* m_CE = nullptr;
//const DeclRefExpr* m_DRE = nullptr;
//const MemberExpr* m_ME = nullptr;
const DeclaratorDecl* m_DD = nullptr;
std::string m_bo_replacement_code;
};
class CMallocInitializerArray2ReplacementAction : public CDynamicArray2ReplacementAction {
public:
CMallocInitializerArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection,
const DeclStmt* DS, const std::string& initializer_info_str) :
CDynamicArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_DS(DS), m_DD(ddecl_indirection.m_ddecl_cptr),
m_initializer_info_str(initializer_info_str) {
}
virtual ~CMallocInitializerArray2ReplacementAction() {}
virtual void do_replacement(CState1& state1) const;
const DeclStmt* m_DS = nullptr;
//const CallExpr* m_CE = nullptr;
const DeclaratorDecl* m_DD = nullptr;
std::string m_initializer_info_str;
};
class CDDecl2ReplacementActionMap : public std::multimap<CDDeclIndirection, std::shared_ptr<CDDecl2ReplacementAction>> {
public:
typedef std::multimap<CDDeclIndirection, std::shared_ptr<CDDecl2ReplacementAction>> base_class;
iterator insert( const std::shared_ptr<CDDecl2ReplacementAction>& cr_shptr ) {
iterator retval(end());
if (!cr_shptr) { assert(false); } else {
value_type val((*cr_shptr).ddecl_indirection_cref(), cr_shptr);
retval = base_class::insert(val);
}
return retval;
}
void do_and_dispose_matching_replacements(CState1& state1, const CDDeclIndirection& ddecl_indirection) {
auto range = base_class::equal_range(ddecl_indirection);
while (range.first != range.second) {
for (auto iter = range.first; range.second != iter; iter++) {
(*((*iter).second)).do_replacement(state1);
}
base_class::erase(range.first, range.second);
range = base_class::equal_range(ddecl_indirection);
}
}
};
class CDynamicArray2ReplacementActionMap : public CDDecl2ReplacementActionMap {
public:
iterator insert( const std::shared_ptr<CDynamicArray2ReplacementAction>& cr_shptr ) {
return CDDecl2ReplacementActionMap::insert(static_cast<std::shared_ptr<CDDecl2ReplacementAction> >(cr_shptr));
}
};
class CArray2ReplacementActionMap : public CDDecl2ReplacementActionMap {
public:
iterator insert( const std::shared_ptr<CArray2ReplacementAction>& cr_shptr ) {
return CDDecl2ReplacementActionMap::insert(static_cast<std::shared_ptr<CDDecl2ReplacementAction> >(cr_shptr));
}
};
class CIndirectionState {
public:
CIndirectionState(std::string original, std::string current)
: m_original(original), m_current(current) {}
CIndirectionState(const CIndirectionState& src) = default;
std::string m_original;
std::string m_current;
};
class CIndirectionStateStack : public std::vector<CIndirectionState> {};
/* Given a type and an (empty) CIndirectionStateStack, this function will fill the stack with indications of
* whether each level of indirection (if any) of the type is of the pointer or the array variety. Pointers
* can, of course, function as arrays, but context is required to identify those situations. Such identification
* is not done in this function. It is done elsewhere. */
const clang::QualType& populateQTypeIndirectionStack(CIndirectionStateStack& stack, const clang::QualType& qtype, int depth = 0) {
std::string qtype_str = qtype.getAsString();
auto TP = qtype.getTypePtr();
if (TP->isArrayType()) {
auto type_class = qtype->getTypeClass();
if (clang::Type::Decayed == type_class) {
int q = 5;
} else if (clang::Type::ConstantArray == type_class) {
int q = 5;
}
const clang::ArrayType* ATP = TP->getAsArrayTypeUnsafe();
if (ATP) {
clang::QualType QT = ATP->getElementType();
auto l_TP = QT.getTypePtr();
auto l_type_str = QT.getAsString();
stack.push_back(CIndirectionState("native array", "native array"));
return populateQTypeIndirectionStack(stack, QT, depth+1);
} else {
assert(false);
}
} else if (qtype->isPointerType()) {
auto type_class = qtype->getTypeClass();
if (clang::Type::Decayed == type_class) {
int q = 5;
} else if (clang::Type::Pointer == type_class) {
int q = 5;
}
if (llvm::isa<const clang::PointerType>(qtype)) {
auto PQT = llvm::cast<const clang::PointerType>(qtype);
if (PQT) {
int q = 5;
} else {
int q = 5;
}
} else {
int q = 5;
}
clang::QualType QT = qtype->getPointeeType();
auto l_type_str = QT.getAsString();
stack.push_back(CIndirectionState("native pointer", "native pointer"));
return populateQTypeIndirectionStack(stack, QT, depth+1);
}
return qtype;
}
/* Given an expression (in the form of a clang::Stmt) and an (empty) (string) stack,
* this function will fill the stack with indications of whether each level of indirection
* (if any) (in the expression) is a pointer dereference or an array subscript. */
const clang::Expr* populateStmtIndirectionStack(std::vector<std::string>& stack, const clang::Stmt& stmt, int depth = 0) {
const clang::Expr* retval = nullptr;
const clang::Stmt* ST = &stmt;
auto stmt_class = ST->getStmtClass();
auto stmt_class_name = ST->getStmtClassName();
bool process_child_flag = false;
if (clang::Stmt::StmtClass::ArraySubscriptExprClass == stmt_class) {
stack.push_back("ArraySubscriptExpr");
process_child_flag = true;
} else if (clang::Stmt::StmtClass::UnaryOperatorClass == stmt_class) {
auto UO = llvm::cast<const clang::UnaryOperator>(ST);
if (UO) {
if (clang::UnaryOperatorKind::UO_Deref == UO->getOpcode()) {
stack.push_back("Deref");
process_child_flag = true;
} else {
auto QT = UO->getType();
const clang::Type* TP = QT.getTypePtr();
if (TP && TP->isPointerType()) {
if ((clang::UnaryOperatorKind::UO_PreInc == UO->getOpcode())
|| (clang::UnaryOperatorKind::UO_PostInc == UO->getOpcode())
|| (clang::UnaryOperatorKind::UO_PreDec == UO->getOpcode())
|| (clang::UnaryOperatorKind::UO_PostDec == UO->getOpcode())) {
/* Incrementing/decrementing a pointer type is pointer arithmetic and
* implies the pointer is being used as an array iterator. */
/* To do: modify the stack entry to reflect this. */
}
}
}
} else {
assert(false);
}
} else if ((clang::Stmt::StmtClass::ImplicitCastExprClass == stmt_class)) {
auto ICE = llvm::cast<const clang::ImplicitCastExpr>(ST);
if (ICE) {
auto cast_kind_name = ICE->getCastKindName();
auto cast_kind = ICE->getCastKind();
if ((clang::CK_FunctionToPointerDecay == cast_kind)) {
process_child_flag = false;
} else {
if ((clang::CK_ArrayToPointerDecay == cast_kind) || (clang::CK_LValueToRValue == cast_kind)) {
process_child_flag = true;
} else {
process_child_flag = true;
}
}
} else { assert(false); }
} else if ((clang::Stmt::StmtClass::ParenExprClass == stmt_class)) {
process_child_flag = true;
} else if(clang::Stmt::StmtClass::DeclRefExprClass == stmt_class) {
auto DRE = llvm::cast<const clang::DeclRefExpr>(ST);
if (DRE) {
retval = DRE;
process_child_flag = true;
} else {
assert(false);
}
} else if(clang::Stmt::StmtClass::MemberExprClass == stmt_class) {
auto ME = llvm::cast<const clang::MemberExpr>(ST);
if (ME) {
retval = ME;
} else {
assert(false);
}
}
if (process_child_flag) {
auto child_iter = ST->child_begin();
if (child_iter != ST->child_end()) {
if (nullptr != (*child_iter)) {
const auto noted_stack_size = stack.size();
auto res = populateStmtIndirectionStack(stack, *(*child_iter), depth+1);
if ((nullptr == retval) || (stack.size() > noted_stack_size)) {
retval = res;
}
} else {
assert(false);
}
} else {
int q = 5;
}
}
return retval;
}
class CDDeclConversionState {
public:
CDDeclConversionState(const clang::DeclaratorDecl& ddecl) : m_ddecl_cptr(&ddecl) {
QualType QT = ddecl.getType();
m_direct_qtype = populateQTypeIndirectionStack(m_indirection_state_stack, QT);
//std::reverse(m_indirection_state_stack.begin(), m_indirection_state_stack.end());
}
const DeclaratorDecl* m_ddecl_cptr = nullptr;
CIndirectionStateStack m_indirection_state_stack;
clang::QualType m_direct_qtype;
std::string m_initializer_info_str;
bool m_original_initialization_has_been_noted = false;
std::string m_original_initialization_expr_str;
};
class CDDeclConversionStateMap : public std::map<const clang::DeclaratorDecl*, CDDeclConversionState> {
public:
std::pair<iterator, bool> insert(const clang::DeclaratorDecl& ddecl) {
value_type item(&ddecl, CDDeclConversionState(ddecl));
return std::map<const clang::DeclaratorDecl*, CDDeclConversionState>::insert(item);
}
};
class CState1 {
public:
/* This container holds (potential) actions that are meant to be executed if/when
* their corresponding item is determined to be a dynamic array. */
CDynamicArray2ReplacementActionMap m_dynamic_array2_contingent_replacement_map;
/* This container holds (potential) actions that are meant to be executed if/when
* their corresponding item is determined to be an array (dynamic or otherwise). */
CArray2ReplacementActionMap m_array2_contingent_replacement_map;
/* This container holds information about each item's original type and which
* type it might be converted to. */
CDDeclConversionStateMap m_ddecl_conversion_state_map;
};
class CDeclarationReplacementCodeItem {
public:
std::string m_replacement_code;
std::string m_action_species;
};
static CDeclarationReplacementCodeItem generate_declaration_replacement_code(const DeclaratorDecl* DD, Rewriter &Rewrite, CDDeclConversionStateMap& ddecl_conversion_state_map, std::string options_str = "") {
CDeclarationReplacementCodeItem retval;
auto res1 = ddecl_conversion_state_map.insert(*DD);
auto ddcs_map_iter = res1.first;
auto& ddcs_ref = (*ddcs_map_iter).second;
QualType QT = DD->getType();
const clang::Type* TP = QT.getTypePtr();
auto qtype_str = QT.getAsString();
auto direct_qtype_str = clang::QualType::getAsString(ddcs_ref.m_direct_qtype.split());
if ("_Bool" == direct_qtype_str) {
direct_qtype_str = "bool";
} else if ("const _Bool" == direct_qtype_str) {
direct_qtype_str = "const bool";
}
clang::StorageDuration storage_duration = clang::StorageDuration::SD_Automatic;
bool has_dynamic_storage_duration = false;
bool is_a_temporary = false;
bool is_static = false;
bool is_a_function_parameter = false;
bool is_member = false;
bool is_vardecl = false;
std::string initialization_expr_str;
auto VD = dynamic_cast<const clang::VarDecl *>(DD);
if (VD) {
is_vardecl = true;
storage_duration = VD->getStorageDuration();
has_dynamic_storage_duration = (clang::StorageDuration::SD_Dynamic == storage_duration);
is_a_temporary = (clang::StorageDuration::SD_FullExpression == storage_duration);
is_static = (clang::StorageDuration::SD_Static == storage_duration);
is_a_function_parameter = (VD->isLocalVarDeclOrParm() && (!VD->isLocalVarDecl()));
if (ddcs_ref.m_original_initialization_has_been_noted) {
initialization_expr_str = ddcs_ref.m_original_initialization_expr_str;
} else {
auto pInitExpr = VD->getInit();
if (VD->hasInit() && pInitExpr) {
auto init_expr_source_range = nice_source_range(pInitExpr->getSourceRange(), Rewrite);
initialization_expr_str = Rewrite.getRewrittenText(init_expr_source_range);
ddcs_ref.m_original_initialization_expr_str = initialization_expr_str;
}
ddcs_ref.m_original_initialization_has_been_noted = true;
}
} else {
auto FD = dynamic_cast<const clang::FieldDecl*>(DD);
if (FD) {
is_member = true;
if (ddcs_ref.m_original_initialization_has_been_noted) {
initialization_expr_str = ddcs_ref.m_original_initialization_expr_str;
} else {
auto pInitExpr = FD->getInClassInitializer();
if (FD->hasInClassInitializer() && pInitExpr) {
auto init_expr_source_range = nice_source_range(pInitExpr->getSourceRange(), Rewrite);
initialization_expr_str = Rewrite.getRewrittenText(init_expr_source_range);
ddcs_ref.m_original_initialization_expr_str = initialization_expr_str;
}
ddcs_ref.m_original_initialization_has_been_noted = true;
}
}
}
ddcs_ref.m_original_initialization_has_been_noted = true;
std::string variable_name = DD->getNameAsString();
std::string identifier_name_str;
auto pIdentifier = DD->getIdentifier();
if (pIdentifier) {
identifier_name_str = pIdentifier->getName();
}
if ("" == variable_name) {
int q = 7;
}
std::string replacement_code;
std::string prefix_str;
std::string suffix_str;
for (size_t i = 0; i < ddcs_ref.m_indirection_state_stack.size(); i += 1) {
bool is_char_star = false;
bool is_last_indirection = (ddcs_ref.m_indirection_state_stack.size() == (i+1));
if (is_last_indirection && (("char" == direct_qtype_str) || ("const char" == direct_qtype_str))) {
is_char_star = true;
}
if ("inferred array" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (is_char_star) {
/* We're assuming this is a null terminated string. We'll just leave it as a
* char* for now. At some point we'll replace it with an mse::string or whatever. */
//prefix_str = prefix_str + "";
suffix_str = "* " + suffix_str;
retval.m_action_species = "char*";
} else {
prefix_str = prefix_str + "mse::TNullableAnyRandomAccessIterator<";
suffix_str = "> " + suffix_str;
retval.m_action_species = "native pointer to TNullableAnyRandomAccessIterator";
}
} else if ("dynamic array" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (is_char_star) {
/* We're assuming this is a null terminated string. We'll just leave it as a
* char* for now. At some point we'll replace it with an mse::string or whatever. */
//prefix_str = prefix_str + "";
suffix_str = "* " + suffix_str;
retval.m_action_species = "char*";
} else {
prefix_str = prefix_str + "mse::TIPointerWithBundledVector<";
if (is_a_function_parameter) {
suffix_str = "> " + suffix_str;
retval.m_action_species = "native pointer parameter to TIPointerWithBundledVector";
} else {
suffix_str = "> " + suffix_str;
retval.m_action_species = "native pointer to TIPointerWithBundledVector";
}
}
} else if ("native array" == ddcs_ref.m_indirection_state_stack[i].m_current) {
std::string size_text;
if (TP->isVariableArrayType()) {
auto VATP = llvm::cast<const clang::VariableArrayType>(TP);
if (!VATP) {
assert(false);
} else {
auto size_expr = VATP->getSizeExpr();
auto SR = nice_source_range(size_expr->getSourceRange(), Rewrite);
size_text = Rewrite.getRewrittenText(SR);
}
} else if (TP->isConstantArrayType()) {
auto CATP = llvm::cast<const clang::ConstantArrayType>(TP);
if (!CATP) {
assert(false);
} else {
auto array_size = CATP->getSize();
size_text = array_size.toString(10, false);/*check this*/
if (false) {
auto DDSR = nice_source_range(DD->getSourceRange(), Rewrite);
std::string array_size_expression_text;
std::string source_text;
if (DDSR.isValid()) {
source_text = Rewrite.getRewrittenText(DDSR);
auto left_bracket_pos = source_text.find('[');
auto right_bracket_pos = source_text.find(']');
if ((std::string::npos != left_bracket_pos) && (std::string::npos != right_bracket_pos)
&& (left_bracket_pos + 1 < right_bracket_pos)) {
auto array_size_expression_text = source_text.substr(left_bracket_pos + 1, right_bracket_pos - (left_bracket_pos + 1));
int q = 3;
} else {
int q = 7;
}
} else {
int q = 5;
}
}
}
}
if (is_char_star) {
/* We're assuming this is a null terminated string. We'll just leave it as a
* char[] for now. At some point we'll replace it with an mse::string or whatever. */
//prefix_str = prefix_str + "";
suffix_str = "[" + size_text + "]" + suffix_str;
} else {
if (is_a_function_parameter) {
prefix_str = prefix_str + "mse::TNullableAnyRandomAccessIterator<";
suffix_str = ", " + size_text + "> " + suffix_str;
retval.m_action_species = "native array parameter to TNullableAnyRandomAccessIterator";
} else {
prefix_str = prefix_str + "mse::TIteratorWithBundledArray<";
suffix_str = ", " + size_text + "> " + suffix_str;
retval.m_action_species = "native array to TIteratorWithBundledArray";
}
}
} else if ("native pointer" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (is_char_star) {
/* We're assuming this is a null terminated string. We'll just leave it as a
* char* for now. At some point we'll replace it with an mse::string or whatever. */
//prefix_str = prefix_str + "";
suffix_str = "* " + suffix_str;
retval.m_action_species = "char*";
} else {
if (false/*for now*/) {
prefix_str = prefix_str + "mse::TAnyPointer<";
suffix_str = "> " + suffix_str;
retval.m_action_species = "native pointer to TAnyPointer";
} else {
//prefix_str = prefix_str + "";
suffix_str = "* " + suffix_str;
retval.m_action_species = "native pointer";
}
}
} else if ("malloc target" == ddcs_ref.m_indirection_state_stack[i].m_current) {
/* We'll just leaving it as a native pointer for now. Ultimately, this won't be the case. */
//prefix_str = prefix_str + "";
suffix_str = "* " + suffix_str;
retval.m_action_species = "malloc target";
}
}
if (is_static) {
replacement_code += "static ";
}
replacement_code += prefix_str + direct_qtype_str + suffix_str;
replacement_code += " ";
replacement_code += variable_name;
if (std::string::npos == options_str.find("[no-initializer]")) {
std::string initializer_append_str = ddcs_ref.m_initializer_info_str;
if (("" == initializer_append_str) && ("" != initialization_expr_str)) {
initializer_append_str = " = " + initialization_expr_str;
}
replacement_code += initializer_append_str;
}
retval.m_replacement_code = replacement_code;
return retval;
}
static void update_declaration(const DeclaratorDecl& ddecl, Rewriter &Rewrite, CState1& state1, std::string options_str = "") {
const DeclaratorDecl* DD = &ddecl;
auto SR = nice_source_range(DD->getSourceRange(), Rewrite);
QualType QT = DD->getType();
const clang::Type* TP = QT.getTypePtr();
auto qtype_str = QT.getAsString();
std::string source_text;
if (SR.isValid()) {
source_text = Rewrite.getRewrittenText(SR);
if ("" == source_text) {
return;
}
} else {
return;
}
std::string variable_name = DD->getNameAsString();
if (("" == variable_name) || (!TP)) {
return;
}
if ((TP->isFunctionType()) || (false)) {
/* We don't handle function declarations yet. */
return;
}
/* There may be multiple declarations in the same declaration statement. Replacing
* one of them requires replacing all of them together. */
auto ddecls = IndividualDeclaratorDecls(DD, Rewrite);
if ((1 <= ddecls.size())/* && (ddecls.back() == DD)*/) {
if (2 <= ddecls.size()) {
int q = 5;
}
std::vector<std::string> action_species_list;
std::string replacement_code;
for (const auto& ddecl_cref : ddecls) {
auto res = generate_declaration_replacement_code(ddecl_cref, Rewrite, state1.m_ddecl_conversion_state_map, options_str);
action_species_list.push_back(res.m_action_species);
replacement_code += res.m_replacement_code;
replacement_code += "; \n";
}
if (replacement_code.size() >= 3) {
replacement_code = replacement_code.substr(0, replacement_code.size() - 3);
}
/* (Only) the source range of the last individual declaration in the declaration statement
* should encompass the whole statement. */
auto last_ddecl = ddecls.back();
auto last_decl_source_range = nice_source_range(last_ddecl->getSourceRange(), Rewrite);
std::string last_decl_source_text;
if (last_decl_source_range.isValid()) {
last_decl_source_text = Rewrite.getRewrittenText(last_decl_source_range);
if ("" == last_decl_source_text) {
return;
}
} else {
return;
}
if (ConvertToSCPP && last_decl_source_range.isValid() && (3 <= replacement_code.size())) {
auto res = Rewrite.ReplaceText(last_decl_source_range, replacement_code);
} else {
int q = 7;
}
} else {
int q = 7;
}
}
void CSetArrayPointerToNull2ReplacementAction::do_replacement(CState1& state1) const {
Rewriter &Rewrite = m_Rewrite;
const MatchFinder::MatchResult &MR = m_MR;
const BinaryOperator* BO = m_BO;
const DeclaratorDecl* DD = m_DD;
if ((BO != nullptr) && (DD != nullptr))
{
auto BOSR = nice_source_range(BO->getSourceRange(), Rewrite);
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
if (ConvertToSCPP && decl_source_range.isValid() && (BOSR.isValid())) {
update_declaration(*DD, Rewrite, state1);
//state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, (*this).ddecl_indirection_cref());
//state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, (*this).ddecl_indirection_cref());
auto res2 = Rewrite.ReplaceText(BOSR, m_bo_replacement_code);
int q = 3;
} else {
int q = 7;
}
}
}
void CFreeDynamicArray2ReplacementAction::do_replacement(CState1& state1) const {
Rewriter &Rewrite = m_Rewrite;
const MatchFinder::MatchResult &MR = m_MR;
const CallExpr* CE = m_CE;
const DeclaratorDecl* DD = m_DD;
if ((CE != nullptr) && (DD != nullptr))
{
auto CESR = nice_source_range(CE->getSourceRange(), Rewrite);
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
if (ConvertToSCPP && decl_source_range.isValid() && (CESR.isValid())) {
update_declaration(*DD, Rewrite, state1);
//state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, (*this).ddecl_indirection_cref());
//state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, (*this).ddecl_indirection_cref());
auto res2 = Rewrite.ReplaceText(CESR, m_ce_replacement_code);
int q = 3;
} else {
int q = 7;
}
}
}
void CMallocArray2ReplacementAction::do_replacement(CState1& state1) const {
Rewriter &Rewrite = m_Rewrite;
const MatchFinder::MatchResult &MR = m_MR;
const BinaryOperator* BO = m_BO;
const DeclaratorDecl* DD = m_DD;
if ((BO != nullptr) && (DD != nullptr))
{
auto BOSR = nice_source_range(BO->getSourceRange(), Rewrite);
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
if (ConvertToSCPP && decl_source_range.isValid() && (BOSR.isValid())) {
update_declaration(*DD, Rewrite, state1);
//state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, (*this).ddecl_indirection_cref());
//state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, (*this).ddecl_indirection_cref());
auto res2 = Rewrite.ReplaceText(BOSR, m_bo_replacement_code);
int q = 3;
} else {
int q = 7;
}
}
}
void CMallocInitializerArray2ReplacementAction::do_replacement(CState1& state1) const {
Rewriter &Rewrite = m_Rewrite;
const MatchFinder::MatchResult &MR = m_MR;
const DeclStmt* DS = m_DS;
const DeclaratorDecl* DD = m_DD;
if ((DS != nullptr) && (DD != nullptr))
{
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
auto res1 = state1.m_ddecl_conversion_state_map.insert(*DD);
auto ddcs_map_iter = res1.first;
auto& ddcs_ref = (*ddcs_map_iter).second;
ddcs_ref.m_initializer_info_str = m_initializer_info_str;
if (ConvertToSCPP && decl_source_range.isValid()) {
update_declaration(*DD, Rewrite, state1);
//state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, (*this).ddecl_indirection_cref());
//state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, (*this).ddecl_indirection_cref());
int q = 3;
} else {
int q = 7;
}
}
}
/**********************************************************************************************************************/
class MCSSSArrayToPointerDecay : public MatchFinder::MatchCallback
{
public:
MCSSSArrayToPointerDecay (Rewriter &Rewrite, CState1& state1)
: Rewrite(Rewrite), m_state1(state1) {}
virtual void run(const MatchFinder::MatchResult &MR)
{
if (/*SafeSubset && */(MR.Nodes.getNodeAs<clang::CastExpr>("mcsssarraytopointerdecay") != nullptr))
{
const CastExpr* CE = MR.Nodes.getNodeAs<clang::CastExpr>("mcsssarraytopointerdecay");
auto SR = nice_source_range(CE->getSourceRange(), Rewrite);
SourceLocation SL = SR.getBegin();
SourceLocation SLE = SR.getEnd();
ASTContext *const ASTC = MR.Context;
FullSourceLoc FSL = ASTC->getFullLoc(SL);
auto source_location_str = SL.printToString(*MR.SourceManager);
std::string source_text;
if (SL.isValid() && SLE.isValid()) {
source_text = Rewrite.getRewrittenText(SourceRange(SL, SLE));
} else {
return;
}
if (filtered_out_by_location(MR, SL))
{
/*intentionally left blank*/
}
else
{
{
if (false) {
std::cout << "sss1.2:" << "array to pointer decay:";
std::cout << SL.printToString(*MR.SourceManager) << ":" << std::endl;
//XMLDocOut.XMLAddNode(MR.Context, SL, "sss1.2", "array to pointer decay: ");
//JSONDocOUT.JSONAddElement(MR.Context, SL, "sss1.2", "array to pointer decay: ");
}
}
}
}
}
private:
Rewriter &Rewrite;
CState1& m_state1;
};
/**********************************************************************************************************************/
class MCSSSNativePointer : public MatchFinder::MatchCallback
{
public:
MCSSSNativePointer (Rewriter &Rewrite) : Rewrite(Rewrite) {}
virtual void run(const MatchFinder::MatchResult &MR)
{
if (SafeSubset && (MR.Nodes.getNodeAs<clang::VarDecl>("mcsssnativepointer") != nullptr))
{
const VarDecl *VD = MR.Nodes.getNodeAs<clang::VarDecl>("mcsssnativepointer");
auto SR = nice_source_range(VD->getSourceRange(), Rewrite);
SourceLocation SL = SR.getBegin();
SourceLocation SLE = SR.getEnd();
ASTContext* const ASTC = MR.Context;
FullSourceLoc FSL = ASTC->getFullLoc(SL);
auto source_location_str = SL.printToString(*MR.SourceManager);
std::string source_text;
if (SL.isValid() && SLE.isValid()) {
source_text = Rewrite.getRewrittenText(SourceRange(SL, SLE));
} else {
return;
}
if (filtered_out_by_location(MR, SL))
{
/*intentionally left blank*/
}
else
{
{
if (false && SafeSubset) {
std::cout << "sss1.1:" << "native pointer:";
std::cout << SL.printToString(*MR.SourceManager) << ":" << std::endl;
//XMLDocOut.XMLAddNode(MR.Context, SL, "sss1.1", "native pointer: ");
//JSONDocOUT.JSONAddElement(MR.Context, SL, "sss1.1", "native pointer: ");
}
}
}
}
}
virtual void onEndOfTranslationUnit()
{
}
private:
Rewriter &Rewrite;
};
/**********************************************************************************************************************/
class MCSSSVarDecl2 : public MatchFinder::MatchCallback
{
public:
MCSSSVarDecl2 (Rewriter &Rewrite, CState1& state1) :
Rewrite(Rewrite), m_state1(state1) {}
virtual void run(const MatchFinder::MatchResult &MR)
{
const DeclaratorDecl* DD = MR.Nodes.getNodeAs<clang::DeclaratorDecl>("mcsssvardecl");
if ((DD != nullptr))
{
auto SR = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_range = SR;
SourceLocation SL = SR.getBegin();
SourceLocation SLE = SR.getEnd();
QualType QT = DD->getType();
const clang::Type* TP = QT.getTypePtr();
auto qtype_str = QT.getAsString();
ASTContext *const ASTC = MR.Context;
FullSourceLoc FSL = ASTC->getFullLoc(SL);
SourceManager &SM = ASTC->getSourceManager();
auto source_location_str = SL.printToString(*MR.SourceManager);
std::string source_text;
if (SR.isValid()) {
source_text = Rewrite.getRewrittenText(SR);
} else {
return;
}
if (filtered_out_by_location(MR, SL)) {
return void();
}
std::string variable_name = DD->getNameAsString();
auto qualified_name = DD->getQualifiedNameAsString();
static const std::string mse_namespace_str1 = "mse::";
static const std::string mse_namespace_str2 = "::mse::";
if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1))
|| (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) {
int q = 5;
//return;
}
auto res1 = (*this).m_state1.m_ddecl_conversion_state_map.insert(*DD);
auto ddcs_map_iter = res1.first;
auto& ddcs_ref = (*ddcs_map_iter).second;
//bool update_declaration_flag = res1.second;
for (size_t i = 0; (i < ddcs_ref.m_indirection_state_stack.size()); i += 1) {
if ("native array" == ddcs_ref.m_indirection_state_stack[i].m_current) {
m_state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
}
}
update_declaration(*DD, Rewrite, m_state1);
}
}
virtual void onEndOfTranslationUnit()
{
}
private:
Rewriter &Rewrite;
CState1& m_state1;
};
/**********************************************************************************************************************/
class MCSSSPointerArithmetic2 : public MatchFinder::MatchCallback
{
public:
MCSSSPointerArithmetic2 (Rewriter &Rewrite, CState1& state1)
: Rewrite(Rewrite), m_state1(state1) {}
virtual void run(const MatchFinder::MatchResult &MR)
{
const DeclRefExpr* DRE = MR.Nodes.getNodeAs<clang::DeclRefExpr>("mcssspointerarithmetic");
const MemberExpr* ME = MR.Nodes.getNodeAs<clang::MemberExpr>("mcssspointerarithmetic2");
const Expr* E = MR.Nodes.getNodeAs<clang::Expr>("mcssspointerarithmetic3");
if ((DRE != nullptr) && (E != nullptr))
{
const DeclRefExpr* DRE = MR.Nodes.getNodeAs<clang::DeclRefExpr>("mcssspointerarithmetic");
auto SR = nice_source_range(DRE->getSourceRange(), Rewrite);
SourceLocation SL = SR.getBegin();
SourceLocation SLE = SR.getEnd();
QualType QT = DRE->getType();
const clang::Type* TP = QT.getTypePtr();
ASTContext *const ASTC = MR.Context;
FullSourceLoc FSL = ASTC->getFullLoc(SL);
SourceManager &SM = ASTC->getSourceManager();
auto source_location_str = SL.printToString(*MR.SourceManager);
std::string source_text;
if (SL.isValid() && SLE.isValid()) {
source_text = Rewrite.getRewrittenText(SourceRange(SL, SLE));
} else {
return;
}
if (filtered_out_by_location(MR, SL)) {
return void();
}
auto decl = DRE->getDecl();
auto DD = dynamic_cast<const DeclaratorDecl*>(decl);
const clang::FieldDecl* FD = nullptr;
if (nullptr != ME) {
auto member_decl = ME->getMemberDecl();
FD = dynamic_cast<const clang::FieldDecl*>(ME->getMemberDecl());
}
if (nullptr != FD) {
DD = FD;
}
if (!DD) {
return;
} else {
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
QT = DD->getType();
std::string variable_name = DD->getNameAsString();
auto qualified_name = DD->getQualifiedNameAsString();
static const std::string mse_namespace_str1 = "mse::";
static const std::string mse_namespace_str2 = "::mse::";
if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1))
|| (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) {
return;
}
auto res1 = (*this).m_state1.m_ddecl_conversion_state_map.insert(*DD);
auto ddcs_map_iter = res1.first;
auto& ddcs_ref = (*ddcs_map_iter).second;
bool update_declaration_flag = res1.second;
const clang::Type* TP = QT.getTypePtr();
auto type_str = QT.getAsString();
auto expr_SR = nice_source_range(E->getSourceRange(), Rewrite);
std::string expr_source_location_str;
std::string expr_source_text;
if (expr_SR.isValid()) {
expr_source_location_str = expr_SR.getBegin().printToString(*MR.SourceManager);
expr_source_text = Rewrite.getRewrittenText(expr_SR);
} else {
int q = 3;
}
std::vector<std::string> stmt_indirection_stack;
const clang::Expr* expr2 = populateStmtIndirectionStack(stmt_indirection_stack, *E);
std::reverse(stmt_indirection_stack.begin(), stmt_indirection_stack.end());
stmt_indirection_stack.push_back("pointer arithmetic");
if (expr2) {
std::string expr2_stmt_class_name;
expr2_stmt_class_name = expr2->getStmtClassName();
const DeclaratorDecl* expr2_DD = nullptr;
if (clang::Stmt::StmtClass::DeclRefExprClass == expr2->getStmtClass()) {
auto expr2_DRE = llvm::cast<const clang::DeclRefExpr>(expr2);
if (expr2_DRE) {
auto expr2_decl = expr2_DRE->getDecl();
expr2_DD = dynamic_cast<const DeclaratorDecl*>(expr2_decl);
} else { assert(false); }
} else if (clang::Stmt::StmtClass::MemberExprClass == expr2->getStmtClass()) {
auto expr2_ME = llvm::cast<const clang::MemberExpr>(expr2);
if (expr2_ME) {
auto expr2_FD = dynamic_cast<const clang::FieldDecl*>(expr2_ME->getMemberDecl());
if (expr2_FD) {
expr2_DD = expr2_FD;
} else { assert(false); }
} else { assert(false); }
}
if (expr2_DD) {
auto expr2_QT = expr2_DD->getType();
const clang::Type* expr2_TP = expr2_QT.getTypePtr();
auto expr2_type_str = clang::QualType::getAsString(expr2_QT.split());
std::string expr2_variable_name = expr2_DD->getNameAsString();
if ((expr2_QT == QT) && (expr2_variable_name == variable_name)) {
for (size_t i = 0; ((i < ddcs_ref.m_indirection_state_stack.size())
&& (i < stmt_indirection_stack.size())); i += 1) {
if ("native pointer" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (("ArraySubscriptExpr" == stmt_indirection_stack[i])
|| ("pointer arithmetic" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "inferred array";
update_declaration_flag = true;
m_state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
}
} else if ("malloc target" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (("ArraySubscriptExpr" == stmt_indirection_stack[i])
|| ("pointer arithmetic" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "dynamic array";
update_declaration_flag = true;
m_state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
m_state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
}
}
}
} else {
int q = 5;
}
}
int q = 5;
} else {
int q = 5;
}
if (update_declaration_flag) {
update_declaration(*DD, Rewrite, m_state1);
}
}
}
}
private:
Rewriter &Rewrite;
CState1& m_state1;
};
/**********************************************************************************************************************/
class MCSSSMalloc2 : public MatchFinder::MatchCallback
{
public:
MCSSSMalloc2 (Rewriter &Rewrite, CState1& state1)
: Rewrite(Rewrite), m_state1(state1) {}
virtual void run(const MatchFinder::MatchResult &MR)
{
const BinaryOperator* BO = MR.Nodes.getNodeAs<clang::BinaryOperator>("mcsssmalloc1");
const Expr* LHS = nullptr;
if (BO != nullptr) {
LHS = BO->getLHS();
}
const CallExpr* CE = MR.Nodes.getNodeAs<clang::CallExpr>("mcsssmalloc2");
const DeclRefExpr* DRE = MR.Nodes.getNodeAs<clang::DeclRefExpr>("mcsssmalloc3");
const MemberExpr* ME = MR.Nodes.getNodeAs<clang::MemberExpr>("mcsssmalloc4");
if ((BO != nullptr) && (LHS != nullptr) && (CE != nullptr) && (DRE != nullptr))
{
auto BOSR = nice_source_range(BO->getSourceRange(), Rewrite);
SourceLocation BOSL = BOSR.getBegin();
SourceLocation BOSLE = BOSR.getEnd();
ASTContext *const ASTC = MR.Context;
FullSourceLoc FBOSL = ASTC->getFullLoc(BOSL);
SourceManager &SM = ASTC->getSourceManager();
auto source_location_str = BOSL.printToString(*MR.SourceManager);
std::string source_text;
if (BOSL.isValid() && BOSLE.isValid()) {
source_text = Rewrite.getRewrittenText(SourceRange(BOSL, BOSLE));
} else {
return;
}
if (std::string::npos != source_location_str.find("526")) {
int q = 5;
}
if (filtered_out_by_location(MR, BOSL)) {
return void();
}
auto function_decl = CE->getDirectCallee();
auto num_args = CE->getNumArgs();
if (function_decl && ((1 == num_args) || (2 == num_args))) {
std::string function_name = function_decl->getNameAsString();
static const std::string alloc_str = "alloc";
static const std::string realloc_str = "realloc";
auto lc_function_name = tolowerstr(function_name);
bool ends_with_alloc = ((lc_function_name.size() >= alloc_str.size())
&& (0 == lc_function_name.compare(lc_function_name.size() - alloc_str.size(), alloc_str.size(), alloc_str)));
bool ends_with_realloc = (ends_with_alloc && (lc_function_name.size() >= realloc_str.size())
&& (0 == lc_function_name.compare(lc_function_name.size() - realloc_str.size(), realloc_str.size(), realloc_str)));
bool still_potentially_valid1 = (ends_with_alloc && (1 == num_args)) || (ends_with_realloc && (2 == num_args));
if (still_potentially_valid1) {
auto iter = CE->arg_begin();
if (ends_with_realloc) {
iter++;
}
bool argIsIntegerType = false;
if (*iter) {
argIsIntegerType = (*iter)->getType().split().asPair().first->isIntegerType();
}
if (argIsIntegerType) {
auto arg_source_range = nice_source_range((*iter)->getSourceRange(), Rewrite);
std::string arg_source_text;
if (arg_source_range.isValid()) {
arg_source_text = Rewrite.getRewrittenText(arg_source_range);
//auto arg_source_text_sans_ws = with_whitespace_removed(arg_source_text);
bool asterisk_found = false;
auto sizeof_start_index = arg_source_text.find("sizeof(");
if (std::string::npos != sizeof_start_index) {
auto sizeof_end_index = arg_source_text.find(")", sizeof_start_index);
if (std::string::npos != sizeof_end_index) {
assert(sizeof_end_index > sizeof_start_index);
std::string before_str = arg_source_text.substr(0, sizeof_start_index);
std::string after_str;
if (sizeof_end_index + 1 < arg_source_text.size()) {
after_str = arg_source_text.substr(sizeof_end_index + 1);
}
auto index = before_str.size() - 1;
while (0 <= index) {
if ('*' == before_str[index]) {
asterisk_found = true;
}
if (!std::isspace(before_str[index])) {
break;
}
index -= 1;
}
if (asterisk_found) {
before_str = before_str.substr(0, index);
} else {
size_t index2 = 0;
while (after_str.size() > index2) {
if ('*' == after_str[index2]) {
asterisk_found = true;
}
if (!std::isspace(after_str[index2])) {
break;
}
index2 += 1;
}
if (asterisk_found) {
after_str = after_str.substr(index2 + 1);
}
}
}
}
if (true || asterisk_found) {
/* The argument is in the form "something * sizeof(something_else)" or
* "sizeof(something) * something_else". So we're just going to assume that
* this is an instance of an array being allocated. */
std::string num_elements_text/* = before_str + after_str*/;
QualType QT;
std::string element_type_str;
clang::SourceRange decl_source_range;
std::string variable_name;
std::string bo_replacement_code;
const clang::DeclaratorDecl* DD = nullptr;
auto lhs_QT = LHS->getType();
auto decl = DRE->getDecl();
DD = dynamic_cast<const DeclaratorDecl*>(decl);
auto VD = dynamic_cast<const VarDecl*>(decl);
const clang::FieldDecl* FD = nullptr;
if (nullptr != ME) {
auto member_decl = ME->getMemberDecl();
FD = dynamic_cast<const clang::FieldDecl*>(ME->getMemberDecl());
}
if (nullptr != FD) {
DD = FD;
} else if (nullptr != VD) {
DD = VD;
} else {
int q = 7;
}
if (nullptr != DD) {
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
QT = DD->getType();
variable_name = DD->getNameAsString();
auto qualified_name = DD->getQualifiedNameAsString();
static const std::string mse_namespace_str1 = "mse::";
static const std::string mse_namespace_str2 = "::mse::";
if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1))
|| (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) {
return;
}
auto res1 = (*this).m_state1.m_ddecl_conversion_state_map.insert(*DD);
auto ddcs_map_iter = res1.first;
auto& ddcs_ref = (*ddcs_map_iter).second;
bool update_declaration_flag = res1.second;
const clang::Type* TP = QT.getTypePtr();
auto type_str = QT.getAsString();
auto expr_SR = nice_source_range(LHS->getSourceRange(), Rewrite);
std::string expr_source_location_str;
std::string expr_source_text;
if (expr_SR.isValid()) {
expr_source_location_str = expr_SR.getBegin().printToString(*MR.SourceManager);
expr_source_text = Rewrite.getRewrittenText(expr_SR);
} else {
int q = 3;
}
std::vector<std::string> stmt_indirection_stack;
const clang::Expr* expr2 = populateStmtIndirectionStack(stmt_indirection_stack, *LHS);
std::reverse(stmt_indirection_stack.begin(), stmt_indirection_stack.end());
stmt_indirection_stack.push_back("malloc target");
bool lhs_has_been_determined_to_be_an_array = false;
size_t indirection_level = 0;
if (expr2) {
std::string expr2_stmt_class_name;
expr2_stmt_class_name = expr2->getStmtClassName();
const DeclaratorDecl* expr2_DD = nullptr;
if (clang::Stmt::StmtClass::DeclRefExprClass == expr2->getStmtClass()) {
auto expr2_DRE = llvm::cast<const clang::DeclRefExpr>(expr2);
if (expr2_DRE) {
auto expr2_decl = expr2_DRE->getDecl();
expr2_DD = dynamic_cast<const DeclaratorDecl*>(expr2_decl);
} else { assert(false); }
} else if (clang::Stmt::StmtClass::MemberExprClass == expr2->getStmtClass()) {
auto expr2_ME = llvm::cast<const clang::MemberExpr>(expr2);
if (expr2_ME) {
auto expr2_FD = dynamic_cast<const clang::FieldDecl*>(expr2_ME->getMemberDecl());
if (expr2_FD) {
expr2_DD = expr2_FD;
} else { assert(false); }
} else { assert(false); }
}
if (expr2_DD) {
auto expr2_QT = expr2_DD->getType();
const clang::Type* expr2_TP = expr2_QT.getTypePtr();
auto expr2_type_str = clang::QualType::getAsString(expr2_QT.split());
std::string expr2_variable_name = expr2_DD->getNameAsString();
if ((expr2_QT == QT) && (expr2_variable_name == variable_name)) {
for (size_t i = 0; ((i < ddcs_ref.m_indirection_state_stack.size())
&& (i < stmt_indirection_stack.size())); i += 1) {
if ("native pointer" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (("ArraySubscriptExpr" == stmt_indirection_stack[i])
|| ("pointer arithmetic" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "inferred array";
update_declaration_flag = true;
m_state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
} else if (("malloc target" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "malloc target";
indirection_level = i;
}
} else if ("inferred array" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (("malloc target" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "dynamic array";
update_declaration_flag = true;
lhs_has_been_determined_to_be_an_array = true;
indirection_level = i;
m_state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
}
} else {
assert(!(("native array" == ddcs_ref.m_indirection_state_stack[i].m_current)
&& (("malloc target" == stmt_indirection_stack[i]))));
}
}
} else {
int q = 5;
}
}
int q = 5;
} else {
int q = 5;
}
if (update_declaration_flag) {
update_declaration(*DD, Rewrite, m_state1);
}
const clang::Type* lhs_TP = lhs_QT.getTypePtr();
auto lhs_type_str = clang::QualType::getAsString(lhs_QT.split());
std::string lhs_element_type_str;
if (lhs_TP->isArrayType()) {
auto ATP = llvm::cast<const clang::ArrayType>(lhs_TP);
assert(nullptr != ATP);
auto element_type = ATP->getElementType();
auto elementSplitQualType = element_type.split();
auto type_str = clang::QualType::getAsString(elementSplitQualType);
if (("char" != type_str) && ("const char" != type_str)) {
lhs_element_type_str = type_str;
}
} else if (lhs_TP->isPointerType()) {
auto TPP = llvm::cast<const clang::PointerType>(lhs_TP);
assert(nullptr != TPP);
auto target_type = TPP->getPointeeType();
auto splitQualType = target_type.split();
auto type_str = clang::QualType::getAsString(splitQualType);
if (("char" != type_str) && ("const char" != type_str)) {
lhs_element_type_str = type_str;
}
}
if ("" != lhs_element_type_str) {
num_elements_text = "(";
num_elements_text += arg_source_text;
num_elements_text += ") / sizeof(";
num_elements_text += lhs_element_type_str;
num_elements_text += ")";
auto lhs_source_range = nice_source_range(LHS->getSourceRange(), Rewrite);
auto lhs_source_text = Rewrite.getRewrittenText(lhs_source_range);
bo_replacement_code += "(" + lhs_source_text + ")";
bo_replacement_code += ".resize(";
bo_replacement_code += num_elements_text;
bo_replacement_code += ")";
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
auto BOSR = clang::SourceRange(BOSL, BOSLE);
if (ConvertToSCPP && decl_source_range.isValid() && (BOSR.isValid())) {
auto cr_shptr = std::make_shared<CMallocArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*DD, indirection_level), BO, bo_replacement_code);
if (lhs_has_been_determined_to_be_an_array) {
(*cr_shptr).do_replacement(m_state1);
} else {
m_state1.m_dynamic_array2_contingent_replacement_map.insert(cr_shptr);
}
} else {
int q = 7;
}
}
}
int q = 5;
}
} else {
int q = 5;
}
int q = 5;
}
}
}
}
}
private:
Rewriter &Rewrite;
CState1& m_state1;
};
class MCSSSMallocInitializer2 : public MatchFinder::MatchCallback
{
public:
MCSSSMallocInitializer2 (Rewriter &Rewrite, CState1& state1) :
Rewrite(Rewrite), m_state1(state1) {}
virtual void run(const MatchFinder::MatchResult &MR)
{
const DeclStmt* DS = MR.Nodes.getNodeAs<clang::DeclStmt>("mcsssmallocinitializer1");
const CallExpr* CE = MR.Nodes.getNodeAs<clang::CallExpr>("mcsssmallocinitializer2");
const DeclaratorDecl* DD = MR.Nodes.getNodeAs<clang::DeclaratorDecl>("mcsssmallocinitializer3");
if ((DS != nullptr) && (CE != nullptr) && (DD != nullptr))
{
auto DSSR = nice_source_range(DS->getSourceRange(), Rewrite);
SourceLocation DSSL = DSSR.getBegin();
SourceLocation DSSLE = DSSR.getEnd();
ASTContext *const ASTC = MR.Context;
FullSourceLoc FDSSL = ASTC->getFullLoc(DSSL);
SourceManager &SM = ASTC->getSourceManager();
auto source_location_str = DSSL.printToString(*MR.SourceManager);
std::string source_text;
if (DSSL.isValid() && DSSLE.isValid()) {
source_text = Rewrite.getRewrittenText(SourceRange(DSSL, DSSLE));
} else {
return;
}
if (filtered_out_by_location(MR, DSSL)) {
return void();
}
auto function_decl = CE->getDirectCallee();
auto num_args = CE->getNumArgs();
if (function_decl && ((1 == num_args) || (2 == num_args))) {
std::string function_name = function_decl->getNameAsString();
static const std::string alloc_str = "alloc";
static const std::string realloc_str = "realloc";
auto lc_function_name = tolowerstr(function_name);
bool ends_with_alloc = ((lc_function_name.size() >= alloc_str.size())
&& (0 == lc_function_name.compare(lc_function_name.size() - alloc_str.size(), alloc_str.size(), alloc_str)));
bool ends_with_realloc = (ends_with_alloc && (lc_function_name.size() >= realloc_str.size())
&& (0 == lc_function_name.compare(lc_function_name.size() - realloc_str.size(), realloc_str.size(), realloc_str)));
bool still_potentially_valid1 = (ends_with_alloc && (1 == num_args)) || (ends_with_realloc && (2 == num_args));
if (still_potentially_valid1) {
auto iter = CE->arg_begin();
if (ends_with_realloc) {
iter++;
}
{
auto arg_source_range = nice_source_range((*iter)->getSourceRange(), Rewrite);
std::string arg_source_text;
if (arg_source_range.isValid()) {
arg_source_text = Rewrite.getRewrittenText(arg_source_range);
//auto arg_source_text_sans_ws = with_whitespace_removed(arg_source_text);
bool asterisk_found = false;
auto sizeof_start_index = arg_source_text.find("sizeof(");
if (std::string::npos != sizeof_start_index) {
auto sizeof_end_index = arg_source_text.find(")", sizeof_start_index);
if (std::string::npos != sizeof_end_index) {
assert(sizeof_end_index > sizeof_start_index);
std::string before_str = arg_source_text.substr(0, sizeof_start_index);
std::string after_str;
if (sizeof_end_index + 1 < arg_source_text.size()) {
after_str = arg_source_text.substr(sizeof_end_index + 1);
}
auto index = before_str.size() - 1;
while (0 <= index) {
if ('*' == before_str[index]) {
asterisk_found = true;
}
if (!std::isspace(before_str[index])) {
break;
}
index -= 1;
}
if (asterisk_found) {
before_str = before_str.substr(0, index);
} else {
size_t index2 = 0;
while (after_str.size() > index2) {
if ('*' == after_str[index2]) {
asterisk_found = true;
}
if (!std::isspace(after_str[index2])) {
break;
}
index2 += 1;
}
if (asterisk_found) {
after_str = after_str.substr(index2 + 1);
}
}
}
}
if (true || asterisk_found) {
/* The argument is in the form "something * sizeof(something_else)" or
* "sizeof(something) * something_else". So we're just going to assume that
* this is an instance of an array being allocated. */
std::string num_elements_text/* = before_str + after_str*/;
QualType QT;
std::string element_type_str;
clang::SourceRange decl_source_range;
std::string variable_name;
std::string declaration_replacement_code;
if (nullptr != DD) {
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
QT = DD->getType();
variable_name = DD->getNameAsString();
auto qualified_name = DD->getQualifiedNameAsString();
static const std::string mse_namespace_str1 = "mse::";
static const std::string mse_namespace_str2 = "::mse::";
if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1))
|| (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) {
return;
}
auto res1 = (*this).m_state1.m_ddecl_conversion_state_map.insert(*DD);
auto ddcs_map_iter = res1.first;
auto& ddcs_ref = (*ddcs_map_iter).second;
bool update_declaration_flag = res1.second;
bool lhs_has_been_determined_to_be_an_array = false;
if ("native pointer" == ddcs_ref.m_indirection_state_stack[0].m_current) {
ddcs_ref.m_indirection_state_stack[0].m_current = "malloc target";
} else if ("inferred array" == ddcs_ref.m_indirection_state_stack[0].m_current) {
ddcs_ref.m_indirection_state_stack[0].m_current = "dynamic array";
lhs_has_been_determined_to_be_an_array = true;
//update_declaration_flag = true;
m_state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, 0));
} else {
assert("native array" != ddcs_ref.m_indirection_state_stack[0].m_current);
}
const clang::Type* TP = QT.getTypePtr();
auto lhs_type_str = QT.getAsString();
if (TP->isArrayType()) {
auto ATP = llvm::cast<const clang::ArrayType>(TP);
assert(nullptr != ATP);
auto element_type = ATP->getElementType();
auto elementSplitQualType = element_type.split();
element_type_str = clang::QualType::getAsString(elementSplitQualType);
} else if (TP->isPointerType()) {
auto TPP = llvm::cast<const clang::PointerType>(TP);
assert(nullptr != TPP);
auto target_type = TPP->getPointeeType();
auto splitQualType = target_type.split();
auto type_str = clang::QualType::getAsString(splitQualType);
if (("char" != type_str) && ("const char" != type_str)) {
element_type_str = type_str;
}
}
if ("" != element_type_str) {
num_elements_text = "(";
num_elements_text += arg_source_text;
num_elements_text += ") / sizeof(";
num_elements_text += element_type_str;
num_elements_text += ")";
std::string initializer_info_str = "(" + num_elements_text + ")";
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
auto DSSR = clang::SourceRange(DSSL, DSSLE);
if (ConvertToSCPP && decl_source_range.isValid() && (DSSR.isValid())) {
auto cr_shptr = std::make_shared<CMallocInitializerArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*DD, 0/*indirection_level*/), DS, initializer_info_str);
if (lhs_has_been_determined_to_be_an_array) {
(*cr_shptr).do_replacement(m_state1);
} else {
m_state1.m_dynamic_array2_contingent_replacement_map.insert(cr_shptr);
}
int q = 3;
} else {
int q = 7;
}
}
}
int q = 5;
}
} else {
int q = 5;
}
int q = 5;
}
}
}
}
}
private:
Rewriter &Rewrite;
CState1& m_state1;
};
class MCSSSFree2 : public MatchFinder::MatchCallback
{
public:
MCSSSFree2 (Rewriter &Rewrite, CState1& state1)
: Rewrite(Rewrite), m_state1(state1) {}
virtual void run(const MatchFinder::MatchResult &MR)
{
const CallExpr* CE = MR.Nodes.getNodeAs<clang::CallExpr>("mcsssfree1");
const DeclRefExpr* DRE = MR.Nodes.getNodeAs<clang::DeclRefExpr>("mcsssfree2");
const MemberExpr* ME = MR.Nodes.getNodeAs<clang::MemberExpr>("mcsssfree3");
if ((CE != nullptr) && (DRE != nullptr))
{
auto CESR = nice_source_range(CE->getSourceRange(), Rewrite);
SourceLocation CESL = CESR.getBegin();
SourceLocation CESLE = CESR.getEnd();
ASTContext *const ASTC = MR.Context;
FullSourceLoc FCESL = ASTC->getFullLoc(CESL);
SourceManager &SM = ASTC->getSourceManager();
auto source_location_str = CESL.printToString(*MR.SourceManager);
std::string source_text;
if (CESL.isValid() && CESLE.isValid()) {
source_text = Rewrite.getRewrittenText(SourceRange(CESL, CESLE));
} else {
return;
}
if (filtered_out_by_location(MR, CESL)) {
return void();
}
auto function_decl = CE->getDirectCallee();
auto num_args = CE->getNumArgs();
if (function_decl && (1 == num_args)) {
{
std::string function_name = function_decl->getNameAsString();
static const std::string free_str = "free";
auto lc_function_name = tolowerstr(function_name);
bool ends_with_free = ((lc_function_name.size() >= free_str.size())
&& (0 == lc_function_name.compare(lc_function_name.size() - free_str.size(), free_str.size(), free_str)));
if (ends_with_free) {
auto iter = CE->arg_begin();
assert((*iter)->getType().getTypePtrOrNull());
auto arg_source_range = nice_source_range((*iter)->getSourceRange(), Rewrite);
std::string arg_source_text;
if (arg_source_range.isValid()) {
arg_source_text = Rewrite.getRewrittenText(arg_source_range);
//auto arg_source_text_sans_ws = with_whitespace_removed(arg_source_text);
QualType QT;
std::string element_type_str;
clang::SourceRange decl_source_range;
std::string variable_name;
std::string ce_replacement_code;
const clang::DeclaratorDecl* DD = nullptr;
auto decl = DRE->getDecl();
DD = dynamic_cast<const DeclaratorDecl*>(decl);
auto VD = dynamic_cast<const VarDecl*>(decl);
const clang::FieldDecl* FD = nullptr;
if (nullptr != ME) {
auto member_decl = ME->getMemberDecl();
FD = dynamic_cast<const clang::FieldDecl*>(ME->getMemberDecl());
}
if (nullptr != FD) {
DD = FD;
} else if (nullptr != VD) {
DD = VD;
} else {
int q = 7;
}
if (nullptr != DD) {
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
QT = DD->getType();
variable_name = DD->getNameAsString();
auto qualified_name = DD->getQualifiedNameAsString();
static const std::string mse_namespace_str1 = "mse::";
static const std::string mse_namespace_str2 = "::mse::";
if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1))
|| (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) {
return;
}
auto res1 = (*this).m_state1.m_ddecl_conversion_state_map.insert(*DD);
auto ddcs_map_iter = res1.first;
auto& ddcs_ref = (*ddcs_map_iter).second;
bool update_declaration_flag = res1.second;
const clang::Type* TP = QT.getTypePtr();
auto type_str = QT.getAsString();
auto expr_SR = nice_source_range(CE->getSourceRange(), Rewrite);
std::string expr_source_location_str;
std::string expr_source_text;
if (expr_SR.isValid()) {
expr_source_location_str = expr_SR.getBegin().printToString(*MR.SourceManager);
expr_source_text = Rewrite.getRewrittenText(expr_SR);
} else {
int q = 3;
}
std::vector<std::string> stmt_indirection_stack;
const clang::Expr* expr2 = populateStmtIndirectionStack(stmt_indirection_stack, *CE);
std::reverse(stmt_indirection_stack.begin(), stmt_indirection_stack.end());
stmt_indirection_stack.push_back("malloc target");
bool lhs_has_been_determined_to_be_an_array = false;
size_t indirection_level = 0;
if (expr2) {
std::string expr2_stmt_class_name;
expr2_stmt_class_name = expr2->getStmtClassName();
const DeclaratorDecl* expr2_DD = nullptr;
if (clang::Stmt::StmtClass::DeclRefExprClass == expr2->getStmtClass()) {
auto expr2_DRE = llvm::cast<const clang::DeclRefExpr>(expr2);
if (expr2_DRE) {
auto expr2_decl = expr2_DRE->getDecl();
expr2_DD = dynamic_cast<const DeclaratorDecl*>(expr2_decl);
} else { assert(false); }
} else if (clang::Stmt::StmtClass::MemberExprClass == expr2->getStmtClass()) {
auto expr2_ME = llvm::cast<const clang::MemberExpr>(expr2);
if (expr2_ME) {
auto expr2_FD = dynamic_cast<const clang::FieldDecl*>(expr2_ME->getMemberDecl());
if (expr2_FD) {
expr2_DD = expr2_FD;
} else { assert(false); }
} else { assert(false); }
}
if (expr2_DD) {
auto expr2_QT = expr2_DD->getType();
const clang::Type* expr2_TP = expr2_QT.getTypePtr();
auto expr2_type_str = clang::QualType::getAsString(expr2_QT.split());
std::string expr2_variable_name = expr2_DD->getNameAsString();
if ((expr2_QT == QT) && (expr2_variable_name == variable_name)) {
for (size_t i = 0; ((i < ddcs_ref.m_indirection_state_stack.size())
&& (i < stmt_indirection_stack.size())); i += 1) {
if ("native pointer" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (("ArraySubscriptExpr" == stmt_indirection_stack[i])
|| ("pointer arithmetic" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "inferred array";
update_declaration_flag = true;
m_state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
} else if (("malloc target" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "malloc target";
indirection_level = i;
}
} else if ("inferred array" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (("malloc target" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "dynamic array";
update_declaration_flag = true;
lhs_has_been_determined_to_be_an_array = true;
indirection_level = i;
m_state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
}
} else {
assert(!(("native array" == ddcs_ref.m_indirection_state_stack[i].m_current)
&& (("malloc target" == stmt_indirection_stack[i]))));
}
}
} else {
int q = 5;
}
}
int q = 5;
} else {
int q = 5;
}
if (update_declaration_flag) {
update_declaration(*DD, Rewrite, m_state1);
}
ce_replacement_code = "(" + arg_source_text + ")";
ce_replacement_code += ".resize(0)";
if (ConvertToSCPP && decl_source_range.isValid() && (CESR.isValid())) {
auto cr_shptr = std::make_shared<CFreeDynamicArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*DD, indirection_level), CE, ce_replacement_code);
if (lhs_has_been_determined_to_be_an_array) {
(*cr_shptr).do_replacement(m_state1);
} else {
m_state1.m_dynamic_array2_contingent_replacement_map.insert(cr_shptr);
}
} else {
int q = 7;
}
}
int q = 5;
} else {
int q = 5;
}
int q = 5;
}
}
}
}
}
private:
Rewriter &Rewrite;
CState1& m_state1;
};
class MCSSSSetToNull2 : public MatchFinder::MatchCallback
{
public:
MCSSSSetToNull2 (Rewriter &Rewrite, CState1& state1)
: Rewrite(Rewrite), m_state1(state1) {}
virtual void run(const MatchFinder::MatchResult &MR)
{
const BinaryOperator* BO = MR.Nodes.getNodeAs<clang::BinaryOperator>("mcssssettonull1");
const Expr* RHS = nullptr;
const Expr* LHS = nullptr;
if (BO != nullptr) {
RHS = BO->getRHS();
LHS = BO->getLHS();
}
const DeclRefExpr* DRE = MR.Nodes.getNodeAs<clang::DeclRefExpr>("mcssssettonull3");
const MemberExpr* ME = MR.Nodes.getNodeAs<clang::MemberExpr>("mcssssettonull4");
if ((BO != nullptr) && (RHS != nullptr) && (LHS != nullptr) && (DRE != nullptr))
{
auto BOSR = nice_source_range(BO->getSourceRange(), Rewrite);
SourceLocation BOSL = BOSR.getBegin();
SourceLocation BOSLE = BOSR.getEnd();
ASTContext *const ASTC = MR.Context;
FullSourceLoc FBOSL = ASTC->getFullLoc(BOSL);
SourceManager &SM = ASTC->getSourceManager();
auto source_location_str = BOSL.printToString(*MR.SourceManager);
std::string source_text;
if (BOSL.isValid() && BOSLE.isValid()) {
source_text = Rewrite.getRewrittenText(SourceRange(BOSL, BOSLE));
} else {
return;
}
if (filtered_out_by_location(MR, BOSL)) {
return void();
}
Expr::NullPointerConstantKind kind = RHS->isNullPointerConstant(*ASTC, Expr::NullPointerConstantValueDependence());
if (clang::Expr::NPCK_NotNull != kind) {
auto lhs_source_range = nice_source_range(LHS->getSourceRange(), Rewrite);
std::string lhs_source_text;
if (lhs_source_range.isValid()) {
lhs_source_text = Rewrite.getRewrittenText(lhs_source_range);
//auto lhs_source_text_sans_ws = with_whitespace_removed(lhs_source_text);
QualType QT;
std::string element_type_str;
clang::SourceRange decl_source_range;
std::string variable_name;
std::string bo_replacement_code;
const clang::DeclaratorDecl* DD = nullptr;
auto decl = DRE->getDecl();
DD = dynamic_cast<const DeclaratorDecl*>(decl);
auto VD = dynamic_cast<const VarDecl*>(decl);
const clang::FieldDecl* FD = nullptr;
if (nullptr != ME) {
auto member_decl = ME->getMemberDecl();
FD = dynamic_cast<const clang::FieldDecl*>(ME->getMemberDecl());
}
if (nullptr != FD) {
DD = FD;
} else if (nullptr != VD) {
DD = VD;
} else {
int q = 7;
}
if (nullptr != DD) {
auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite);
auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager);
std::string decl_source_text;
if (decl_source_range.isValid()) {
decl_source_text = Rewrite.getRewrittenText(decl_source_range);
} else {
return;
}
QT = DD->getType();
variable_name = DD->getNameAsString();
auto qualified_name = DD->getQualifiedNameAsString();
static const std::string mse_namespace_str1 = "mse::";
static const std::string mse_namespace_str2 = "::mse::";
if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1))
|| (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) {
return;
}
auto res1 = (*this).m_state1.m_ddecl_conversion_state_map.insert(*DD);
auto ddcs_map_iter = res1.first;
auto& ddcs_ref = (*ddcs_map_iter).second;
bool update_declaration_flag = res1.second;
const clang::Type* TP = QT.getTypePtr();
auto type_str = QT.getAsString();
auto expr_SR = nice_source_range(LHS->getSourceRange(), Rewrite);
std::string expr_source_location_str;
std::string expr_source_text;
if (expr_SR.isValid()) {
expr_source_location_str = expr_SR.getBegin().printToString(*MR.SourceManager);
expr_source_text = Rewrite.getRewrittenText(expr_SR);
} else {
int q = 3;
}
std::vector<std::string> stmt_indirection_stack;
const clang::Expr* expr2 = populateStmtIndirectionStack(stmt_indirection_stack, *LHS);
std::reverse(stmt_indirection_stack.begin(), stmt_indirection_stack.end());
stmt_indirection_stack.push_back("malloc target");
bool lhs_has_been_determined_to_be_an_array = false;
size_t indirection_level = 0;
if (expr2) {
std::string expr2_stmt_class_name;
expr2_stmt_class_name = expr2->getStmtClassName();
const DeclaratorDecl* expr2_DD = nullptr;
if (clang::Stmt::StmtClass::DeclRefExprClass == expr2->getStmtClass()) {
auto expr2_DRE = llvm::cast<const clang::DeclRefExpr>(expr2);
if (expr2_DRE) {
auto expr2_decl = expr2_DRE->getDecl();
expr2_DD = dynamic_cast<const DeclaratorDecl*>(expr2_decl);
} else { assert(false); }
} else if (clang::Stmt::StmtClass::MemberExprClass == expr2->getStmtClass()) {
auto expr2_ME = llvm::cast<const clang::MemberExpr>(expr2);
if (expr2_ME) {
auto expr2_FD = dynamic_cast<const clang::FieldDecl*>(expr2_ME->getMemberDecl());
if (expr2_FD) {
expr2_DD = expr2_FD;
} else { assert(false); }
} else { assert(false); }
}
if (expr2_DD) {
auto expr2_QT = expr2_DD->getType();
const clang::Type* expr2_TP = expr2_QT.getTypePtr();
auto expr2_type_str = clang::QualType::getAsString(expr2_QT.split());
std::string expr2_variable_name = expr2_DD->getNameAsString();
if ((expr2_QT == QT) && (expr2_variable_name == variable_name)) {
for (size_t i = 0; ((i < ddcs_ref.m_indirection_state_stack.size())
&& (i < stmt_indirection_stack.size())); i += 1) {
if ("native pointer" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (("ArraySubscriptExpr" == stmt_indirection_stack[i])
|| ("pointer arithmetic" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "inferred array";
update_declaration_flag = true;
m_state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
} else if (("malloc target" == stmt_indirection_stack[i])) {
//ddcs_ref.m_indirection_state_stack[i].m_current = "malloc target";
indirection_level = i;
}
} else if ("inferred array" == ddcs_ref.m_indirection_state_stack[i].m_current) {
if (("malloc target" == stmt_indirection_stack[i])) {
ddcs_ref.m_indirection_state_stack[i].m_current = "dynamic array";
update_declaration_flag = true;
lhs_has_been_determined_to_be_an_array = true;
indirection_level = i;
m_state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(m_state1, CDDeclIndirection(*DD, i));
}
} else {
assert(!(("native array" == ddcs_ref.m_indirection_state_stack[i].m_current)
&& (("malloc target" == stmt_indirection_stack[i]))));
}
}
} else {
int q = 5;
}
}
int q = 5;
} else {
int q = 5;
}
if (update_declaration_flag) {
update_declaration(*DD, Rewrite, m_state1);
}
auto lhs_source_range = nice_source_range(LHS->getSourceRange(), Rewrite);
auto lhs_source_text = Rewrite.getRewrittenText(lhs_source_range);
bo_replacement_code += "(" + lhs_source_text + ")";
bo_replacement_code += ".resize(0)";
if (ConvertToSCPP && decl_source_range.isValid() && (BOSR.isValid())) {
auto cr_shptr = std::make_shared<CSetArrayPointerToNull2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*DD, indirection_level), BO, bo_replacement_code);
if (lhs_has_been_determined_to_be_an_array) {
(*cr_shptr).do_replacement(m_state1);
} else {
m_state1.m_dynamic_array2_contingent_replacement_map.insert(cr_shptr);
}
} else {
int q = 7;
}
}
int q = 5;
} else {
int q = 5;
}
int q = 5;
}
}
}
private:
Rewriter &Rewrite;
CState1& m_state1;
};
/**********************************************************************************************************************/
class MyASTConsumer : public ASTConsumer {
public:
MyASTConsumer(Rewriter &R) : HandlerForSSSNativePointer(R), HandlerForSSSArrayToPointerDecay(R, m_state1),
HandlerForSSSVarDecl2(R, m_state1), HandlerForSSSPointerArithmetic2(R, m_state1), HandlerForSSSMalloc2(R, m_state1),
HandlerForSSSMallocInitializer2(R, m_state1), HandlerForSSSFree2(R, m_state1), HandlerForSSSSetToNull2(R, m_state1)
{
Matcher.addMatcher(varDecl(hasType(pointerType())).bind("mcsssnativepointer"), &HandlerForSSSNativePointer);
Matcher.addMatcher(castExpr(allOf(hasCastKind(CK_ArrayToPointerDecay), unless(hasParent(arraySubscriptExpr())))).bind("mcsssarraytopointerdecay"), &HandlerForSSSArrayToPointerDecay);
Matcher.addMatcher(clang::ast_matchers::declaratorDecl().bind("mcsssvardecl"), &HandlerForSSSVarDecl2);
Matcher.addMatcher(expr(allOf(
hasParent(expr(anyOf( \
unaryOperator(hasOperatorName("++")), unaryOperator(hasOperatorName("--")), \
binaryOperator(hasOperatorName("+=")), binaryOperator(hasOperatorName("-=")),
castExpr(hasParent(expr(anyOf(
binaryOperator(hasOperatorName("+")), binaryOperator(hasOperatorName("+=")),
binaryOperator(hasOperatorName("-")), binaryOperator(hasOperatorName("-=")),
binaryOperator(hasOperatorName("<=")), binaryOperator(hasOperatorName("<")),
binaryOperator(hasOperatorName(">=")), binaryOperator(hasOperatorName(">")),
arraySubscriptExpr()/*, clang::ast_matchers::castExpr(hasParent(arraySubscriptExpr()))*/
))))))),
hasType(pointerType()),
anyOf(
memberExpr(expr(hasDescendant(declRefExpr().bind("mcssspointerarithmetic")))).bind("mcssspointerarithmetic2"),
declRefExpr().bind("mcssspointerarithmetic"),
hasDescendant(memberExpr(expr(hasDescendant(declRefExpr().bind("mcssspointerarithmetic")))).bind("mcssspointerarithmetic2")),
hasDescendant(declRefExpr().bind("mcssspointerarithmetic"))
)
)).bind("mcssspointerarithmetic3"), &HandlerForSSSPointerArithmetic2);
Matcher.addMatcher(binaryOperator(allOf(
hasOperatorName("="),
hasRHS(
anyOf(
cStyleCastExpr(has(callExpr().bind("mcsssmalloc2"))),
callExpr().bind("mcsssmalloc2")
)
),
hasLHS(anyOf(
memberExpr(expr(hasDescendant(declRefExpr().bind("mcsssmalloc3")))).bind("mcsssmalloc4"),
declRefExpr().bind("mcsssmalloc3"),
hasDescendant(memberExpr(expr(hasDescendant(declRefExpr().bind("mcsssmalloc3")))).bind("mcsssmalloc4")),
hasDescendant(declRefExpr().bind("mcsssmalloc3"))
)),
hasLHS(expr(hasType(pointerType())))
)).bind("mcsssmalloc1"), &HandlerForSSSMalloc2);
Matcher.addMatcher(declStmt(hasDescendant(
varDecl(hasInitializer(ignoringImpCasts(
anyOf(
cStyleCastExpr(has(callExpr().bind("mcsssmallocinitializer2"))),
callExpr().bind("mcsssmallocinitializer2")
)
))).bind("mcsssmallocinitializer3")
)).bind("mcsssmallocinitializer1"), &HandlerForSSSMallocInitializer2);
Matcher.addMatcher(
callExpr(allOf(
hasAnyArgument(
expr(anyOf(
memberExpr(expr(hasDescendant(declRefExpr().bind("mcsssfree2")))).bind("mcsssfree3"),
hasDescendant(memberExpr(expr(hasDescendant(declRefExpr().bind("mcsssfree2")))).bind("mcsssfree3")),
hasDescendant(declRefExpr().bind("mcsssfree2"))
))),
argumentCountIs(1),
hasAnyArgument(hasType(pointerType()))
)).bind("mcsssfree1"), &HandlerForSSSFree2);
Matcher.addMatcher(binaryOperator(allOf(
hasOperatorName("="),
hasLHS(anyOf(
memberExpr(expr(hasDescendant(declRefExpr().bind("mcssssettonull3")))).bind("mcssssettonull4"),
hasDescendant(memberExpr(expr(hasDescendant(declRefExpr().bind("mcssssettonull3")))).bind("mcssssettonull4")),
hasDescendant(declRefExpr().bind("mcssssettonull3"))
)),
hasLHS(expr(hasType(pointerType())))
)).bind("mcssssettonull1"), &HandlerForSSSSetToNull2);
}
void HandleTranslationUnit(ASTContext &Context) override
{
Matcher.matchAST(Context);
}
private:
CState1 m_state1;
MCSSSNativePointer HandlerForSSSNativePointer;
MCSSSArrayToPointerDecay HandlerForSSSArrayToPointerDecay;
MCSSSVarDecl2 HandlerForSSSVarDecl2;
MCSSSPointerArithmetic2 HandlerForSSSPointerArithmetic2;
MCSSSMalloc2 HandlerForSSSMalloc2;
MCSSSMallocInitializer2 HandlerForSSSMallocInitializer2;
MCSSSFree2 HandlerForSSSFree2;
MCSSSSetToNull2 HandlerForSSSSetToNull2;
MatchFinder Matcher;
};
/**********************************************************************************************************************/
class MyFrontendAction : public ASTFrontendAction
{
public:
MyFrontendAction() {}
~MyFrontendAction() {
if (ConvertToSCPP) {
auto res = overwriteChangedFiles();
int q = 5;
}
}
void EndSourceFileAction() override {
TheRewriter.getEditBuffer(TheRewriter.getSourceMgr().getMainFileID()).write(llvm::outs());
}
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) override {
TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
return llvm::make_unique<MyASTConsumer>(TheRewriter);
}
bool overwriteChangedFiles() {
return TheRewriter.overwriteChangedFiles();
}
private:
Rewriter TheRewriter;
};
/**********************************************************************************************************************/
/*Main*/
int main(int argc, const char **argv)
{
CommonOptionsParser op(argc, argv, MatcherSampleCategory);
ClangTool Tool(op.getCompilations(), op.getSourcePathList());
return Tool.run(newFrontendActionFactory<MyFrontendAction>().get());
}
/*last line intentionally left blank*/