diff options
-rw-r--r-- | safercpp/safercpp-arr.cpp | 1369 |
1 files changed, 1024 insertions, 345 deletions
diff --git a/safercpp/safercpp-arr.cpp b/safercpp/safercpp-arr.cpp index 28419a1..05f6f27 100644 --- a/safercpp/safercpp-arr.cpp +++ b/safercpp/safercpp-arr.cpp @@ -214,14 +214,6 @@ static std::vector<std::string> f_declared_object_strings(const std::string& dec 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) { @@ -230,6 +222,11 @@ std::string tolowerstr(const std::string& a) { return retval; } +bool string_begins_with(const std::string& s1, const std::string& prefix) { + return (0 == s1.compare(0, prefix.length(), prefix)); +} + + /* 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) { @@ -295,197 +292,6 @@ public: 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 CMemsetArray2ReplacementAction : public CArray2ReplacementAction { -public: - CMemsetArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection, - const CallExpr* CE, const std::string& ce_replacement_code) : - CArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_CE(CE), m_DD(ddecl_indirection.m_ddecl_cptr), - m_ce_replacement_code(ce_replacement_code) {} - virtual ~CMemsetArray2ReplacementAction() {} - - 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 CMemcpyArray2ReplacementAction : public CArray2ReplacementAction { -public: - CMemcpyArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection, - const CallExpr* CE, const std::string& ce_replacement_code) : - CArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_CE(CE), m_DD(ddecl_indirection.m_ddecl_cptr), - m_ce_replacement_code(ce_replacement_code) {} - virtual ~CMemcpyArray2ReplacementAction() {} - - 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 CAssignedFromArray2ReplacementAction : public CArray2ReplacementAction { -public: - CAssignedFromArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection, - const CDDeclIndirection& ddecl_indirection2) : - CArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_ddecl_indirection2(ddecl_indirection2) {} - virtual ~CAssignedFromArray2ReplacementAction() {} - - virtual void do_replacement(CState1& state1) const; - - const CDDeclIndirection m_ddecl_indirection2; -}; - -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) { - /* The base class map may be modified during loop iterations. Maybe. */ - auto iter = base_class::find(ddecl_indirection); - while (base_class::end() != iter) { - (*((*iter).second)).do_replacement(state1); - base_class::erase(iter); - - iter = base_class::find(ddecl_indirection); - } - } -}; - -class CDynamicArray2ReplacementAction : public CArray2ReplacementAction { -public: - using CArray2ReplacementAction::CArray2ReplacementAction; - virtual ~CDynamicArray2ReplacementAction() {} -}; - -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 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 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 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) @@ -734,12 +540,15 @@ public: m_direct_qtype = populateQTypeIndirectionStack(m_indirection_state_stack, QT); //std::reverse(m_indirection_state_stack.begin(), m_indirection_state_stack.end()); } + bool is_an_indirect_type(size_t indirection_level = 0) const { return (indirection_level < m_indirection_state_stack.size()); } 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; + bool m_original_source_text_has_been_noted = false; + std::string m_original_source_text_str; }; class CDDeclConversionStateMap : public std::map<const clang::DeclaratorDecl*, CDDeclConversionState> { @@ -750,6 +559,402 @@ public: } }; +bool is_an_indirect_type(const CDDeclIndirection& ddecl_indirection) { + return CDDeclConversionState(*(ddecl_indirection.m_ddecl_cptr)).is_an_indirect_type(ddecl_indirection.m_indirection_level); +} +bool is_an_indirect_type(const clang::DeclaratorDecl& ddecl) { + return CDDeclConversionState(ddecl).is_an_indirect_type(); +} + +bool is_an_indirect_type(const QualType& QT, size_t indirection_level = 0) { + CIndirectionStateStack m_indirection_state_stack; + auto m_direct_qtype = populateQTypeIndirectionStack(m_indirection_state_stack, QT); + return (indirection_level < m_indirection_state_stack.size()); +} + +class CExprTextModifier { +public: + virtual ~CExprTextModifier() {} + virtual std::string modified_copy(const std::string& input_text, const clang::Expr* expr_ptr = nullptr) const { + return input_text; + } + virtual std::string species_str() const { + return "no op"; + } +}; + +class CWrapExprTextModifier : public CExprTextModifier { +public: + CWrapExprTextModifier(const std::string& prefix, const std::string& suffix) : + m_prefix(prefix), m_suffix(suffix) {} + virtual ~CWrapExprTextModifier() {} + virtual std::string modified_copy(const std::string& input_text, const clang::Expr* expr_ptr = nullptr) const { + return m_prefix + input_text + m_suffix; + } + virtual std::string species_str() const { + return "wrap"; + } + std::string m_prefix; + std::string m_suffix; +}; + +class CNullableAnyRandomAccessIterCastExprTextModifier : public CWrapExprTextModifier { +public: + CNullableAnyRandomAccessIterCastExprTextModifier(const clang::QualType& qtype) : + CWrapExprTextModifier("mse::TNullableAnyRandomAccessIterator<" + qtype.getAsString() + " >(", ")"), + m_qtype(qtype) {} + virtual ~CNullableAnyRandomAccessIterCastExprTextModifier() {} + virtual std::string species_str() const { + return "nullable any random access iter cast"; + } + clang::QualType m_qtype; +}; + +class CExprTextModifierStack : public std::vector<std::shared_ptr<CExprTextModifier>> { +public: +}; + +class CExprConversionState { +public: + CExprConversionState(const clang::Expr& expr, Rewriter &Rewrite) : m_expr_cptr(&expr), Rewrite(Rewrite) { + m_original_source_text_str = Rewrite.getRewrittenText(nice_source_range()); + m_current_text_str = m_original_source_text_str; + } + virtual ~CExprConversionState() {} + virtual void update_current_text() { + m_current_text_str = modified_copy(m_original_source_text_str); + } + + clang::SourceRange source_range() const { + clang::SourceRange retval; + return m_expr_cptr->getSourceRange(); + } + clang::SourceRange nice_source_range() const { + return ::nice_source_range(source_range(), Rewrite); + } + void set_parent_shptr(const std::shared_ptr<CExprConversionState>& parent_shptr) { + m_parent_shptr = parent_shptr; + } + void set_childrens_parent_shptr(const std::shared_ptr<CExprConversionState>& parent_shptr) { + for (auto& child_shptr : m_children_shptrs) { + child_shptr->set_parent_shptr(parent_shptr); + } + } + + std::string modified_copy(const std::string& input_text) const { + std::string retval = input_text; + for (const auto& modifier_shptr_cref : m_expr_text_modifier_stack) { + retval = (*modifier_shptr_cref).modified_copy(retval, m_expr_cptr); + } + return retval; + } + + CExprTextModifierStack m_expr_text_modifier_stack; + + std::shared_ptr<CExprConversionState> m_parent_shptr; + std::vector<std::shared_ptr<CExprConversionState>> m_children_shptrs; + + const Expr* m_expr_cptr = nullptr; + std::string m_original_source_text_str; + std::string m_current_text_str; + Rewriter &Rewrite; +}; + +class CConditionalOperatorExprConversionState : public CExprConversionState { +public: + CConditionalOperatorExprConversionState(const clang::ConditionalOperator& co_cref, Rewriter &Rewrite) : CExprConversionState(co_cref, Rewrite) { + auto cond_ptr = co_cref.getCond(); + auto lhs_ptr = co_cref.getLHS(); + auto rhs_ptr = co_cref.getRHS(); + if (cond_ptr && lhs_ptr && rhs_ptr) { + m_cond_shptr = std::make_shared<CExprConversionState>(*cond_ptr, Rewrite); + m_children_shptrs.push_back(m_cond_shptr); + + m_lhs_shptr = std::make_shared<CExprConversionState>(*lhs_ptr, Rewrite); + m_children_shptrs.push_back(m_lhs_shptr); + + m_rhs_shptr = std::make_shared<CExprConversionState>(*rhs_ptr, Rewrite); + m_children_shptrs.push_back(m_rhs_shptr); + } else { + assert(false); + throw(""); + } + } + const clang::ConditionalOperator& co_cref() const { + return (*(static_cast<const clang::ConditionalOperator *>(m_expr_cptr))); + } + virtual void update_current_text() { + if (false) { + /* Do we need to update the kids first? */ + m_cond_shptr->update_current_text(); + m_lhs_shptr->update_current_text(); + m_rhs_shptr->update_current_text(); + } + std::string updated_text = m_cond_shptr->m_current_text_str + " ? " + + m_lhs_shptr->m_current_text_str + " : " + m_rhs_shptr->m_current_text_str; + updated_text = modified_copy(updated_text); + m_current_text_str = updated_text; + } + + std::shared_ptr<CExprConversionState> m_cond_shptr; + std::shared_ptr<CExprConversionState> m_lhs_shptr; + std::shared_ptr<CExprConversionState> m_rhs_shptr; +}; + +template<class X, class... Args> +std::shared_ptr<X> make_expr_conversion_state_shared_ptr(Args&&... args) { + std::shared_ptr<X> retval = std::make_shared<X>(std::forward<Args>(args)...); + retval->set_childrens_parent_shptr(retval); + return retval; +} + +class CExprConversionStateMap : public std::map<const clang::Expr*, std::shared_ptr<CExprConversionState>> { +public: + typedef std::map<const clang::Expr*, std::shared_ptr<CExprConversionState>> base_class; + iterator insert( const std::shared_ptr<CExprConversionState>& cr_shptr ) { + iterator retval(end()); + if (!cr_shptr) { assert(false); } else { + value_type val((*cr_shptr).m_expr_cptr, cr_shptr); + auto res1 = base_class::insert(val); + retval = res1.first; + for (auto& child_shptr_ref : (*cr_shptr).m_children_shptrs) { + value_type val((*child_shptr_ref).m_expr_cptr, child_shptr_ref); + auto res1 = base_class::insert(val); + } + } + return retval; + } +}; + + +class CState1; + +class CReplacementAction { +public: + virtual ~CReplacementAction() {} + virtual void do_replacement(CState1& state1) const = 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 CMemsetArray2ReplacementAction : public CArray2ReplacementAction { +public: + CMemsetArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection, + const CallExpr* CE, const std::string& ce_replacement_code) : + CArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_CE(CE), m_DD(ddecl_indirection.m_ddecl_cptr), + m_ce_replacement_code(ce_replacement_code) {} + virtual ~CMemsetArray2ReplacementAction() {} + + 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 CMemcpyArray2ReplacementAction : public CArray2ReplacementAction { +public: + CMemcpyArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection, + const CallExpr* CE, const std::string& ce_replacement_code) : + CArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_CE(CE), m_DD(ddecl_indirection.m_ddecl_cptr), + m_ce_replacement_code(ce_replacement_code) {} + virtual ~CMemcpyArray2ReplacementAction() {} + + 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 CAssignmentTargetConstrainsSourceArray2ReplacementAction : public CArray2ReplacementAction { +public: + CAssignmentTargetConstrainsSourceArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection, + const CDDeclIndirection& ddecl_indirection2) : + CArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_ddecl_indirection2(ddecl_indirection2) {} + virtual ~CAssignmentTargetConstrainsSourceArray2ReplacementAction() {} + + virtual void do_replacement(CState1& state1) const; + + const CDDeclIndirection m_ddecl_indirection2; +}; + +class CAssignmentSourceConstrainsTargetArray2ReplacementAction : public CArray2ReplacementAction { +public: + CAssignmentSourceConstrainsTargetArray2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection, + const CDDeclIndirection& ddecl_indirection2) : + CArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_ddecl_indirection2(ddecl_indirection2) {} + virtual ~CAssignmentSourceConstrainsTargetArray2ReplacementAction() {} + + virtual void do_replacement(CState1& state1) const; + + const CDDeclIndirection m_ddecl_indirection2; +}; + +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) { + /* The base class map may be modified during loop iterations. Maybe. */ + auto iter = base_class::find(ddecl_indirection); + while (base_class::end() != iter) { + (*((*iter).second)).do_replacement(state1); + base_class::erase(iter); + + iter = base_class::find(ddecl_indirection); + } + } +}; + +class CDynamicArray2ReplacementAction : public CArray2ReplacementAction { +public: + using CArray2ReplacementAction::CArray2ReplacementAction; + virtual ~CDynamicArray2ReplacementAction() {} +}; + +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 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 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; +}; + +/* This class represents and "enforces" the constraint that the lhs and rhs + * values of a conditional operator must be the same type. */ +class CConditionalOperatorReconciliation2ReplacementAction : public CDynamicArray2ReplacementAction { +public: + CConditionalOperatorReconciliation2ReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const CDDeclIndirection& ddecl_indirection, + const clang::ConditionalOperator* CO, const DeclaratorDecl* lhs_DD, const DeclaratorDecl* rhs_DD, const DeclaratorDecl* var_DD = nullptr) : + CDynamicArray2ReplacementAction(Rewrite, MR, ddecl_indirection), m_CO(CO), m_lhs_DD(lhs_DD), m_rhs_DD(rhs_DD), m_var_DD(var_DD) {} + virtual ~CConditionalOperatorReconciliation2ReplacementAction() {} + + virtual void do_replacement(CState1& state1) const; + + const clang::ConditionalOperator* m_CO = nullptr; + const DeclaratorDecl* m_lhs_DD = nullptr; + const DeclaratorDecl* m_rhs_DD = nullptr; + const DeclaratorDecl* m_var_DD = nullptr; +}; + +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 CState1 { public: /* This container holds (potential) actions that are meant to be executed if/when @@ -763,6 +968,10 @@ public: /* This container holds information about each item's original type and which * type it might be converted to. */ CDDeclConversionStateMap m_ddecl_conversion_state_map; + + /* This container holds information about selected expressions' original text and + * any modifications we might have made. */ + CExprConversionStateMap m_expr_conversion_state_map; }; class CDeclarationReplacementCodeItem { @@ -773,6 +982,14 @@ public: static CDeclarationReplacementCodeItem generate_declaration_replacement_code(const DeclaratorDecl* DD, Rewriter &Rewrite, CDDeclConversionStateMap& ddecl_conversion_state_map, std::string options_str = "") { CDeclarationReplacementCodeItem retval; + if (!DD) { + return retval; + } + auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite); + if (!(decl_source_range.isValid())) { + return retval; + } + auto res1 = ddecl_conversion_state_map.insert(*DD); auto ddcs_map_iter = res1.first; auto& ddcs_ref = (*ddcs_map_iter).second; @@ -780,12 +997,26 @@ static CDeclarationReplacementCodeItem generate_declaration_replacement_code(con 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()); + auto direct_qtype_str = ddcs_ref.m_direct_qtype.getAsString(); if ("_Bool" == direct_qtype_str) { direct_qtype_str = "bool"; } else if ("const _Bool" == direct_qtype_str) { direct_qtype_str = "const bool"; } + QT.isConstQualified(); + + auto non_const_direct_qtype = ddcs_ref.m_direct_qtype; + non_const_direct_qtype.removeLocalConst(); + auto non_const_direct_qtype_str = non_const_direct_qtype.getAsString(); + if ("_Bool" == non_const_direct_qtype_str) { + non_const_direct_qtype_str = "bool"; + } + + auto direct_TP = ddcs_ref.m_direct_qtype.getTypePtr(); + if (!direct_TP) { + return retval; + } + bool direct_type_is_function_type = direct_TP->isFunctionType(); std::string variable_name = DD->getNameAsString(); std::string identifier_name_str; @@ -797,6 +1028,13 @@ static CDeclarationReplacementCodeItem generate_declaration_replacement_code(con int q = 7; } + if (!(ddcs_ref.m_original_source_text_has_been_noted)) { + ddcs_ref.m_original_source_text_str = Rewrite.getRewrittenText(decl_source_range); + ddcs_ref.m_original_source_text_has_been_noted = true; + } + + clang::StorageClass storage_class = clang::StorageClass::SC_None; + bool is_extern = false; clang::StorageDuration storage_duration = clang::StorageDuration::SD_Automatic; bool has_dynamic_storage_duration = false; bool is_a_temporary = false; @@ -805,14 +1043,21 @@ static CDeclarationReplacementCodeItem generate_declaration_replacement_code(con bool is_member = false; bool is_vardecl = false; std::string initialization_expr_str; + bool is_function = DD->isFunctionOrFunctionTemplate(); auto VD = dynamic_cast<const clang::VarDecl *>(DD); if (VD) { is_vardecl = true; + storage_class = VD->getStorageClass(); + is_extern = (clang::StorageClass::SC_Extern == storage_class); 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_static = (clang::StorageDuration::SD_Static == storage_duration); + is_static = (clang::StorageClass::SC_Static == storage_class); + if ((clang::StorageDuration::SD_Static == storage_duration) && (!is_static)) { + int q = 5; + } is_a_function_parameter = (VD->isLocalVarDeclOrParm() && (!VD->isLocalVarDecl())); if (ddcs_ref.m_original_initialization_has_been_noted) { @@ -880,142 +1125,180 @@ static CDeclarationReplacementCodeItem generate_declaration_replacement_code(con } ddcs_ref.m_original_initialization_has_been_noted = true; + bool changed_from_original = false; 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"; + if (true) { + for (size_t i = 0; i < ddcs_ref.m_indirection_state_stack.size(); i += 1) { + bool is_char_star = false; + bool is_function_pointer = 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; + } else if (is_last_indirection && direct_type_is_function_type) { + is_function_pointer = true; + } + if ("inferred array" == ddcs_ref.m_indirection_state_stack[i].m_current) { + direct_qtype_str = non_const_direct_qtype_str; + 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 TIPointerWithBundledVector"; + retval.m_action_species = "native pointer to TNullableAnyRandomAccessIterator"; } - } - } 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 if ("dynamic array" == ddcs_ref.m_indirection_state_stack[i].m_current) { + direct_qtype_str = non_const_direct_qtype_str; + 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 { - auto size_expr = VATP->getSizeExpr(); - auto SR = nice_source_range(size_expr->getSourceRange(), Rewrite); - size_text = Rewrite.getRewrittenText(SR); + 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 (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 if ("native array" == ddcs_ref.m_indirection_state_stack[i].m_current) { + direct_qtype_str = non_const_direct_qtype_str; + 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 = 7; + int q = 5; } - } 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"; + 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 { - prefix_str = prefix_str + "mse::TIteratorWithBundledArray<"; - suffix_str = ", " + size_text + "> " + suffix_str; - retval.m_action_species = "native array to TIteratorWithBundledArray"; + 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 { + } 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 = "native pointer"; + retval.m_action_species = "char*"; + } else if (is_function_pointer) { + prefix_str = prefix_str + "std::function<"; + suffix_str = "> " + suffix_str; + retval.m_action_species = "function pointer to std::function"; + } 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"; } - } 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; + bool discard_initializer_option_flag = (std::string::npos != options_str.find("[discard-initializer]")); + std::string initializer_append_str; + if (!discard_initializer_option_flag) { + initializer_append_str = ddcs_ref.m_initializer_info_str; if (("" == initializer_append_str) && ("" != initialization_expr_str)) { initializer_append_str = " = " + initialization_expr_str; } + } + + if (("" != prefix_str) || ("" != suffix_str)) { + changed_from_original = true; + } else if (("" != ddcs_ref.m_initializer_info_str) || + (discard_initializer_option_flag)) { + changed_from_original = true; + } else if (2 <= IndividualDeclaratorDecls(DD, Rewrite).size()) { + /* There is more than one declaration in the declaration statement. We split + * them so that each has their own separate declaration statement. This counts + * as a change from the original source code. */ + changed_from_original = true; + } + + if (changed_from_original) { + if (is_extern) { + if ("" == ddcs_ref.m_original_initialization_expr_str) { + replacement_code += "extern "; + } + } else if (is_static) { + replacement_code += "static "; + } + replacement_code += prefix_str + direct_qtype_str + suffix_str; + replacement_code += " "; + replacement_code += variable_name; + replacement_code += initializer_append_str; + } else { + replacement_code = ddcs_ref.m_original_source_text_str; } + retval.m_replacement_code = replacement_code; return retval; } @@ -1285,7 +1568,7 @@ void CMemcpyArray2ReplacementAction::do_replacement(CState1& state1) const { } } -void CAssignedFromArray2ReplacementAction::do_replacement(CState1& state1) const { +void CAssignmentTargetConstrainsSourceArray2ReplacementAction::do_replacement(CState1& state1) const { Rewriter &Rewrite = m_Rewrite; const MatchFinder::MatchResult &MR = m_MR; @@ -1294,16 +1577,21 @@ void CAssignedFromArray2ReplacementAction::do_replacement(CState1& state1) const auto& ddcs_ref = (*ddcs_map_iter).second; bool update_declaration_flag = res1.second; - if ("native pointer" == ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current) { - ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current = "inferred array"; - update_declaration_flag = true; - state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, m_ddecl_indirection2); - } else if ("malloc target" == ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current) { - ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current = "dynamic array"; - update_declaration_flag = true; - state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, m_ddecl_indirection2); + if (ddcs_ref.m_indirection_state_stack.size() >= m_ddecl_indirection2.m_indirection_level) { + if ("native pointer" == ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current) { + ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current = "inferred array"; + update_declaration_flag = true; + state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, m_ddecl_indirection2); + } else if ("malloc target" == ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current) { + ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current = "dynamic array"; + update_declaration_flag = true; + state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, m_ddecl_indirection2); + state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, m_ddecl_indirection2); + } else { + int q = 3; + } } else { - int q = 3; + int q = 7; } if (update_declaration_flag) { @@ -1311,11 +1599,205 @@ void CAssignedFromArray2ReplacementAction::do_replacement(CState1& state1) const } } +void CAssignmentSourceConstrainsTargetArray2ReplacementAction::do_replacement(CState1& state1) const { + Rewriter &Rewrite = m_Rewrite; + const MatchFinder::MatchResult &MR = m_MR; + + auto res1 = state1.m_ddecl_conversion_state_map.insert(*(m_ddecl_indirection2.m_ddecl_cptr)); + auto ddcs_map_iter = res1.first; + auto& ddcs_ref = (*ddcs_map_iter).second; + bool update_declaration_flag = res1.second; + + if (ddcs_ref.m_indirection_state_stack.size() >= m_ddecl_indirection2.m_indirection_level) { + if ("native pointer" == ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current) { + ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current = "inferred array"; + update_declaration_flag = true; + state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, m_ddecl_indirection2); + } else if ("malloc target" == ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current) { + ddcs_ref.m_indirection_state_stack[m_ddecl_indirection2.m_indirection_level].m_current = "dynamic array"; + update_declaration_flag = true; + state1.m_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, m_ddecl_indirection2); + state1.m_dynamic_array2_contingent_replacement_map.do_and_dispose_matching_replacements(state1, m_ddecl_indirection2); + } else { + int q = 3; + } + } else { + int q = 7; + } + + if (update_declaration_flag) { + update_declaration(*(m_ddecl_indirection2.m_ddecl_cptr), Rewrite, state1); + } +} + +void CConditionalOperatorReconciliation2ReplacementAction::do_replacement(CState1& state1) const { + const clang::ConditionalOperator* CO = m_CO; + const Expr* COND = nullptr; + const Expr* LHS = nullptr; + const Expr* RHS = nullptr; + if (CO) { + COND = CO->getCond(); + LHS = CO->getLHS(); + RHS = CO->getRHS(); + } + const DeclaratorDecl* lhs_DD = m_lhs_DD; + const DeclaratorDecl* rhs_DD = m_rhs_DD; + if ((COND != nullptr) && (LHS != nullptr) && (RHS != nullptr) && (lhs_DD != nullptr) && (rhs_DD != nullptr)) { + bool lhs_is_array = false; + bool lhs_is_dynamic_array = false; + bool lhs_is_native_array = false; + + auto COSR = nice_source_range(CO->getSourceRange(), (*this).m_Rewrite); + auto cond_SR = nice_source_range(COND->getSourceRange(), (*this).m_Rewrite); + auto lhs_SR = nice_source_range(LHS->getSourceRange(), (*this).m_Rewrite); + auto rhs_SR = nice_source_range(RHS->getSourceRange(), (*this).m_Rewrite); + if ((COSR.isValid()) && (cond_SR.isValid()) && (lhs_SR.isValid()) && (rhs_SR.isValid())) { + auto res1 = state1.m_ddecl_conversion_state_map.insert(*lhs_DD); + auto ddcs_map_iter = res1.first; + auto& ddcs_ref = (*ddcs_map_iter).second; + /* At the moment we only support the case where the value option expressions are + * just declared variables. */ + if (1 <= ddcs_ref.m_indirection_state_stack.size()) { + if ("dynamic array" == ddcs_ref.m_indirection_state_stack[0].m_current) { + lhs_is_dynamic_array = true; + lhs_is_array = true; + } else if ("native array" == ddcs_ref.m_indirection_state_stack[0].m_current) { + lhs_is_native_array = true; + lhs_is_array = true; + } else if ("inferred array" == ddcs_ref.m_indirection_state_stack[0].m_current) { + lhs_is_array = true; + } + } else { + int q = 3; + } + } + + bool rhs_is_array = false; + bool rhs_is_dynamic_array = false; + bool rhs_is_native_array = false; + { + auto res1 = state1.m_ddecl_conversion_state_map.insert(*rhs_DD); + auto ddcs_map_iter = res1.first; + auto& ddcs_ref = (*ddcs_map_iter).second; + if (1 <= ddcs_ref.m_indirection_state_stack.size()) { + if ("dynamic array" == ddcs_ref.m_indirection_state_stack[0].m_current) { + rhs_is_dynamic_array = true; + rhs_is_array = true; + } else if ("native array" == ddcs_ref.m_indirection_state_stack[0].m_current) { + rhs_is_native_array = true; + rhs_is_array = true; + } else if ("inferred array" == ddcs_ref.m_indirection_state_stack[0].m_current) { + rhs_is_array = true; + } + } else { + int q = 3; + } + } + if (lhs_is_array && rhs_is_array) { + if (m_var_DD) { + update_declaration(*m_var_DD, (*this).m_Rewrite, state1); + } + + std::string CO_prior_text = (*this).m_Rewrite.getRewrittenText(COSR); + std::string CO_replacement_text; + + std::string cond_prior_text = (*this).m_Rewrite.getRewrittenText(cond_SR); + std::string cond_replacement_text = cond_prior_text; + + std::string lhs_prior_text = (*this).m_Rewrite.getRewrittenText(lhs_SR); + std::string lhs_replacement_text = lhs_prior_text; + + std::string rhs_prior_text = (*this).m_Rewrite.getRewrittenText(rhs_SR); + std::string rhs_replacement_text = rhs_prior_text; + static const std::string ara_iter_prefix = "mse::TNullableAnyRandomAccessIterator<"; + + bool lhs_needs_to_be_wrapped = false; + if ((lhs_is_dynamic_array && (!rhs_is_dynamic_array)) || (lhs_is_native_array && (!rhs_is_native_array))) { + lhs_needs_to_be_wrapped = true; + } + bool rhs_needs_to_be_wrapped = false; + if ((rhs_is_dynamic_array && (!lhs_is_dynamic_array)) || (rhs_is_native_array && (!lhs_is_native_array))) { + rhs_needs_to_be_wrapped = true; + } + auto cocs_iter = state1.m_expr_conversion_state_map.end(); + if (lhs_needs_to_be_wrapped || rhs_needs_to_be_wrapped) { + cocs_iter = state1.m_expr_conversion_state_map.find(CO); + if (state1.m_expr_conversion_state_map.end() == cocs_iter) { + auto shptr1 = make_expr_conversion_state_shared_ptr<CConditionalOperatorExprConversionState>(*CO, m_Rewrite); + cocs_iter = state1.m_expr_conversion_state_map.insert(shptr1); + } + } + + if (lhs_needs_to_be_wrapped) { + assert(state1.m_expr_conversion_state_map.end() != cocs_iter); + auto lhscs_iter = state1.m_expr_conversion_state_map.find(LHS); + if (state1.m_expr_conversion_state_map.end() != lhscs_iter) { + auto& lhscs_shptr_ref = (*lhscs_iter).second; + bool already_wrapped_flag = false; + if (1 <= (*lhscs_shptr_ref).m_expr_text_modifier_stack.size()) { + auto& last_modifier_ref = (*(*lhscs_shptr_ref).m_expr_text_modifier_stack.back()); + if ("nullable any random access iter cast" == last_modifier_ref.species_str()) { + already_wrapped_flag = true; + } + } + if (ConvertToSCPP && (!already_wrapped_flag)) { + auto shptr1 = std::make_shared<CNullableAnyRandomAccessIterCastExprTextModifier>(LHS->getType()->getPointeeType()); + (*lhscs_shptr_ref).m_expr_text_modifier_stack.push_back(shptr1); + (*lhscs_shptr_ref).update_current_text(); + } + } + } + if (rhs_needs_to_be_wrapped) { + assert(state1.m_expr_conversion_state_map.end() != cocs_iter); + auto rhscs_iter = state1.m_expr_conversion_state_map.find(RHS); + if (state1.m_expr_conversion_state_map.end() != rhscs_iter) { + auto& rhscs_shptr_ref = (*rhscs_iter).second; + bool already_wrapped_flag = false; + if (1 <= (*rhscs_shptr_ref).m_expr_text_modifier_stack.size()) { + auto& last_modifier_ref = (*(*rhscs_shptr_ref).m_expr_text_modifier_stack.back()); + if ("nullable any random access iter cast" == last_modifier_ref.species_str()) { + already_wrapped_flag = true; + } + } + if (ConvertToSCPP && (!already_wrapped_flag)) { + auto shptr1 = std::make_shared<CNullableAnyRandomAccessIterCastExprTextModifier>(RHS->getType()->getPointeeType()); + (*rhscs_shptr_ref).m_expr_text_modifier_stack.push_back(shptr1); + (*rhscs_shptr_ref).update_current_text(); + } + } + } + + if (m_var_DD && (true)) { + assert(state1.m_expr_conversion_state_map.end() != cocs_iter); + auto& cocs_shptr_ref = (*(*cocs_iter).second); + cocs_shptr_ref.update_current_text(); + + auto res1 = state1.m_ddecl_conversion_state_map.insert(*m_var_DD); + auto ddcs_map_iter = res1.first; + auto& ddcs_ref = (*ddcs_map_iter).second; + + ddcs_ref.m_initializer_info_str = " = " + cocs_shptr_ref.m_current_text_str; + } + + } + } +} + + struct CArrayInferenceInfo { + bool is_an_indirect_type() const { + if (nullptr != ddecl_conversion_state_ptr) { + return (1 <= ddecl_conversion_state_ptr->m_indirection_state_stack.size()); + } else { + return false; + } + } bool update_declaration_flag = false; bool has_been_determined_to_be_an_array = false; size_t indirection_level = 0; const DeclaratorDecl* ddecl_cptr = nullptr; + CDDeclConversionState* ddecl_conversion_state_ptr = nullptr; + bool ddecl_needs_update_flag = false; const clang::Expr* declaration_expr_cptr = nullptr; }; @@ -1326,7 +1808,11 @@ CArrayInferenceInfo infer_array_type_info_from_stmt_indirection_stack(CDDeclConv if (!DD) { assert(false); return retval; } 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 (("" == stmt_indirection_stack[i])) { + /* We're using the empty string as a generic state for the "terminal level of indirection" + * when we don't want to bother specifying a specific state. */ + retval.indirection_level = i; + } else 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"; @@ -1424,6 +1910,9 @@ CArrayInferenceInfo infer_array_type_info_from_stmt(const clang::Stmt& stmt_cref if ((expr2_QT == QT) && (expr2_variable_name == variable_name)) { retval = infer_array_type_info_from_stmt_indirection_stack(ddcs_ref, stmt_indirection_stack, state1_ref); } + + retval.ddecl_conversion_state_ptr = &ddcs_ref; + retval.ddecl_needs_update_flag = update_declaration_flag; } retval.ddecl_cptr = expr2_DD; } @@ -2780,6 +3269,7 @@ private: CState1& m_state1; }; +/* This class addresses the initialized declarations in the form "type var = cond ? lhs : rhs;". */ class MCSSSConditionalInitializer : public MatchFinder::MatchCallback { public: @@ -2821,11 +3311,6 @@ public: return void(); } - if (std::string::npos != source_location_str.find("73")) { - walkTheAST1(*LHS); - int q = 5; - } - 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; @@ -2845,52 +3330,163 @@ public: 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; + std::string var_current_state_str; + { + auto res1 = m_state1.m_ddecl_conversion_state_map.insert(*DD); + auto ddcs_map_iter = res1.first; + auto& ddcs_ref = (*ddcs_map_iter).second; + if (1 <= ddcs_ref.m_indirection_state_stack.size()) { + var_current_state_str = ddcs_ref.m_indirection_state_stack[0].m_current; + } else { + int q = 7; + } + } + bool var_has_been_determined_to_be_an_array = false; + if (("inferred array" == var_current_state_str) || + ("dynamic array" == var_current_state_str) || + ("native array" == var_current_state_str)) { + if ("native array" == var_current_state_str) { + assert(false); /* right? */ + } + var_has_been_determined_to_be_an_array = true; + } + + auto lhs_res2 = infer_array_type_info_from_stmt(*LHS, "", (*this).m_state1); + auto rhs_res2 = infer_array_type_info_from_stmt(*RHS, "", (*this).m_state1); + bool lhs_qualifies = false; + bool rhs_qualifies = false; { - auto res2 = infer_array_type_info_from_stmt(*LHS, "", (*this).m_state1); + auto& res2 = lhs_res2; if (res2.ddecl_cptr && res2.declaration_expr_cptr) { std::string variable_name = res2.ddecl_cptr->getNameAsString(); auto QT = res2.ddecl_cptr->getType(); auto LHS_QT = LHS->getType(); - if (QT == LHS_QT) { - - if (ConvertToSCPP && decl_source_range.isValid()) { - auto cr_shptr = std::make_shared<CAssignedFromArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*DD, 0), CDDeclIndirection(*(res2.ddecl_cptr) , res2.indirection_level)); + /* Currently we only support the case where the value expressions are direct + * references to declared variables. */ + if ((QT == LHS_QT)/* && (1 == res2.indirection_level)*/) { + lhs_qualifies = true; + if (ConvertToSCPP) { + { + /* Here we're establishing and "enforcing" the constraint that the lhs value must + * be of an (array) type that can be assigned to the target variable. */ + auto cr_shptr = std::make_shared<CAssignmentTargetConstrainsSourceArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*DD, 0), CDDeclIndirection(*(res2.ddecl_cptr) , res2.indirection_level)); + + if (var_has_been_determined_to_be_an_array) { + (*cr_shptr).do_replacement(m_state1); + } else { + m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); + } + } + { + /* Here we're establishing the constraint in the opposite direction as well. */ + auto cr_shptr = std::make_shared<CAssignmentSourceConstrainsTargetArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*(res2.ddecl_cptr) , res2.indirection_level), CDDeclIndirection(*DD, 0)); - if (true || res2.has_been_determined_to_be_an_array) { - (*cr_shptr).do_replacement(m_state1); - } else { - m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); + if (res2.has_been_determined_to_be_an_array) { + (*cr_shptr).do_replacement(m_state1); + } else { + m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); + } } - } else { - int q = 7; } } } } { - auto res2 = infer_array_type_info_from_stmt(*RHS, "", (*this).m_state1); + auto& res2 = rhs_res2; if (res2.ddecl_cptr && res2.declaration_expr_cptr) { std::string variable_name = res2.ddecl_cptr->getNameAsString(); auto QT = res2.ddecl_cptr->getType(); auto RHS_QT = RHS->getType(); + /* Currently we only support the case where the value expressions are direct + * references to declared variables. */ if (QT == RHS_QT) { + rhs_qualifies = true; + if (ConvertToSCPP) { + { + /* Here we're establishing and "enforcing" the constraint that the rhs value must + * be of an (array) type that can be assigned to the target variable. */ + auto cr_shptr = std::make_shared<CAssignmentTargetConstrainsSourceArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*DD, 0), CDDeclIndirection(*(res2.ddecl_cptr) , res2.indirection_level)); + + if (var_has_been_determined_to_be_an_array) { + (*cr_shptr).do_replacement(m_state1); + } else { + m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); + } + } + { + /* Here we're establishing the constraint in the opposite direction as well. */ + auto cr_shptr = std::make_shared<CAssignmentSourceConstrainsTargetArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*(res2.ddecl_cptr) , res2.indirection_level), CDDeclIndirection(*DD, 0)); + + if (res2.has_been_determined_to_be_an_array) { + (*cr_shptr).do_replacement(m_state1); + } else { + m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); + } + } + } + } + } + } + + if (lhs_qualifies && rhs_qualifies) { + std::string lhs_current_state_str; + { + auto res1 = m_state1.m_ddecl_conversion_state_map.insert(*(lhs_res2.ddecl_cptr)); + auto ddcs_map_iter = res1.first; + auto& ddcs_ref = (*ddcs_map_iter).second; + if (1 <= ddcs_ref.m_indirection_state_stack.size()) { + lhs_current_state_str = ddcs_ref.m_indirection_state_stack[0].m_current; + } else { + int q = 7; + } + } + std::string rhs_current_state_str; + { + auto res1 = m_state1.m_ddecl_conversion_state_map.insert(*(rhs_res2.ddecl_cptr)); + auto ddcs_map_iter = res1.first; + auto& ddcs_ref = (*ddcs_map_iter).second; + if (1 <= ddcs_ref.m_indirection_state_stack.size()) { + rhs_current_state_str = ddcs_ref.m_indirection_state_stack[0].m_current; + } else { + int q = 7; + } + } - if (ConvertToSCPP && decl_source_range.isValid()) { - auto cr_shptr = std::make_shared<CAssignedFromArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*DD, 0), CDDeclIndirection(*(res2.ddecl_cptr) , res2.indirection_level)); + if (ConvertToSCPP) { + /* Here we're establishing and "enforcing" the constraint that the lhs and rhs + * values of the conditional operator must be the same type. */ + { + auto cr_shptr = std::make_shared<CConditionalOperatorReconciliation2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*lhs_res2.ddecl_cptr, 0), CO, lhs_res2.ddecl_cptr, rhs_res2.ddecl_cptr, DD); - if (true || res2.has_been_determined_to_be_an_array) { + if ("dynamic array" == lhs_current_state_str) { + (*cr_shptr).do_replacement(m_state1); + } else if ("native array" == lhs_current_state_str) { + (*cr_shptr).do_replacement(m_state1); + } else { + m_state1.m_dynamic_array2_contingent_replacement_map.insert(cr_shptr); + if ("inferred array" == lhs_current_state_str) { (*cr_shptr).do_replacement(m_state1); } else { m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); } + } + } + { + auto cr_shptr = std::make_shared<CConditionalOperatorReconciliation2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*rhs_res2.ddecl_cptr, 0), CO, lhs_res2.ddecl_cptr, rhs_res2.ddecl_cptr, DD); + + if ("dynamic array" == rhs_current_state_str) { + (*cr_shptr).do_replacement(m_state1); + } else if ("native array" == rhs_current_state_str) { + (*cr_shptr).do_replacement(m_state1); } else { - int q = 7; + m_state1.m_dynamic_array2_contingent_replacement_map.insert(cr_shptr); + if ("inferred array" == rhs_current_state_str) { + (*cr_shptr).do_replacement(m_state1); + } else { + m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); + } } } } @@ -2903,6 +3499,81 @@ private: CState1& m_state1; }; +class MCSSSAssignment : public MatchFinder::MatchCallback +{ +public: + MCSSSAssignment (Rewriter &Rewrite, CState1& state1) : + Rewrite(Rewrite), m_state1(state1) {} + + virtual void run(const MatchFinder::MatchResult &MR) + { + const clang::BinaryOperator* BO = MR.Nodes.getNodeAs<clang::BinaryOperator>("mcsssassignment1"); + const Expr* LHS = nullptr; + const Expr* RHS = nullptr; + if (BO) { + LHS = BO->getLHS(); + RHS = BO->getRHS(); + } + const DeclRefExpr* DRE = MR.Nodes.getNodeAs<clang::DeclRefExpr>("mcsssassignment2"); + + if ((BO != nullptr) && (LHS != nullptr) && (RHS != 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(); + } + + auto lhs_res2 = infer_array_type_info_from_stmt(*LHS, "", (*this).m_state1); + auto rhs_res2 = infer_array_type_info_from_stmt(*RHS, "", (*this).m_state1); + if (ConvertToSCPP && (lhs_res2.ddecl_cptr) && (rhs_res2.ddecl_cptr) + && (is_an_indirect_type(LHS->getType()))) { + { + /* Here we're establishing and "enforcing" the constraint that the rhs value must + * be of an (array) type that can be assigned to the lhs. */ + auto cr_shptr = std::make_shared<CAssignmentTargetConstrainsSourceArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*(lhs_res2.ddecl_cptr), lhs_res2.indirection_level), CDDeclIndirection(*(rhs_res2.ddecl_cptr), rhs_res2.indirection_level)); + + if (lhs_res2.has_been_determined_to_be_an_array) { + (*cr_shptr).do_replacement(m_state1); + } else { + m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); + } + } + { + /* Here we're establishing the constraint in the opposite direction as well. */ + auto cr_shptr = std::make_shared<CAssignmentSourceConstrainsTargetArray2ReplacementAction>(Rewrite, MR, CDDeclIndirection(*(rhs_res2.ddecl_cptr), rhs_res2.indirection_level), CDDeclIndirection(*(lhs_res2.ddecl_cptr), lhs_res2.indirection_level)); + + if (rhs_res2.has_been_determined_to_be_an_array) { + (*cr_shptr).do_replacement(m_state1); + } else { + m_state1.m_array2_contingent_replacement_map.insert(cr_shptr); + } + } + } + + } + } + +private: + Rewriter &Rewrite; + CState1& m_state1; +}; + /**********************************************************************************************************************/ class MyASTConsumer : public ASTConsumer { @@ -2910,7 +3581,8 @@ 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), - HandlerForSSSMemset(R, m_state1), HandlerForSSSMemcpy(R, m_state1), HandlerForSSSConditionalInitializer(R, m_state1) + HandlerForSSSMemset(R, m_state1), HandlerForSSSMemcpy(R, m_state1), HandlerForSSSConditionalInitializer(R, m_state1), + HandlerForSSSAssignment(R, m_state1) { Matcher.addMatcher(varDecl(hasType(pointerType())).bind("mcsssnativepointer"), &HandlerForSSSNativePointer); @@ -3021,6 +3693,12 @@ public: ))).bind("mcsssconditionalinitializer3") )).bind("mcsssconditionalinitializer1"), &HandlerForSSSConditionalInitializer); + Matcher.addMatcher(binaryOperator(allOf( + hasOperatorName("="), + hasLHS(hasDescendant(declRefExpr().bind("mcsssassignment2"))), + hasRHS(hasDescendant(declRefExpr().bind("mcsssassignment3"))) + )).bind("mcsssassignment1"), &HandlerForSSSAssignment); + } void HandleTranslationUnit(ASTContext &Context) override @@ -3043,6 +3721,7 @@ private: MCSSSMemset HandlerForSSSMemset; MCSSSMemcpy HandlerForSSSMemcpy; MCSSSConditionalInitializer HandlerForSSSConditionalInitializer; + MCSSSAssignment HandlerForSSSAssignment; MatchFinder Matcher; }; |