<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Hey everyone</p>
    <p>the two major limitations are resolved now:</p>
    <p>- The macro argument issue<br>
      - Support for replacing Decls using
      clang::ast_type_traits::DynTypedNode<br>
    </p>
    <p>The macro issue vanished by itself once I figured a little
      unintuitive detail out: The SourceLocations from the original AST
      and the ones from the new Preprocessor Lexer did not compare equal
      even though they refer to the exact same location.</p>
    <p>I believe this is because expansion SrcLocs have a kind of
      pointer identity representation and equality just compares raw
      representations, such that even when they point to the same
      locations, they don't compare equal. What worked for me was a kind
      of "deep" comparison:<br>
    </p>
    <p>bool clutil::DeepSrcLocEqual(clang::SourceLocation lhs,
      clang::SourceLocation rhs, const clang::SourceManager &SM)<br>
      {<br>
          if (lhs == rhs)<br>
              return true;<br>
      <br>
          if (SM.getExpansionLoc(lhs) != SM.getExpansionLoc(rhs))<br>
              return false;<br>
          if (SM.getSpellingLoc(lhs) != SM.getSpellingLoc(rhs))<br>
              return false;<br>
      <br>
          clang::SourceLocation lhsMacro, rhsMacro;<br>
          if (SM.isMacroArgExpansion(lhs, &lhsMacro))<br>
          {<br>
              if (!SM.isMacroArgExpansion(rhs, &rhsMacro))<br>
                  return false;<br>
              if (!DeepSrcLocEqual(lhsMacro, rhsMacro, SM))<br>
                  return false;<br>
          }<br>
      <br>
          return true;<br>
      }</p>
    <p>Attached is the cleaned up rewriter that I ended up with now.
      Still, if there is any interest, I'd be happy to contribute this
      back to clangs libraries, but I would require some feedback how
      this fits into existing facilities.<br>
    </p>
    <p>Best regards<br>
      Rafael<br>
    </p>
    <div class="moz-cite-prefix">On 17.07.18 16:19, Jonas Toth wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:88511a7d-d662-70be-675e-0665bbfa949c@jonas-toth.eu">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <p>Hi Rafael,</p>
      <p>I did read into clang-refactor a while ago but unfortunatly
        could not follow that up. If I recall correctly its about
        source-to-source transformation (as you said) and aims at
        implementing the primitive refactorings that exist (e.g.
        extract-method, extract-variable, ....).</p>
      <p>Rewriting itself should happen with the normal tooling
        framework.<br>
      </p>
      (<a class="moz-txt-link-freetext"
        href="https://clang.llvm.org/docs/RefactoringEngine.html"
        moz-do-not-send="true">https://clang.llvm.org/docs/RefactoringEngine.html</a>)<br>
      <br>
      Maybe the implementers of the existing code can give better
      comments on you proposal (and might have considered a similar
      solution to yours already). <br>
      <br>
      +Alex Lorenz<br>
      <br>
      All the best, Jonas<br>
      <br>
      <br>
      <div class="moz-cite-prefix">Am 17.07.2018 um 14:46 schrieb
        Rafael·Stahl:<br>
      </div>
      <blockquote type="cite"
        cite="mid:f94cfa5f-233e-7cad-bd6e-09ce07a549bc@tum.de">
        <p>Hi Jonas</p>
        <p>Thanks for introducing me to this, I have seen the
          "Replacement" before, but not clang-refactor.</p>
        <p>However it seems to only provide management facilities around
          rewrite operations and not aid with the rewriting itself. Am I
          missing something here?</p>
        <p>The two core problems for me:</p>
        <p>- nesting replacements: When implementing replacements with
          clang-refactor, I still have to provide replacements that are
          closed in themselves. I cannot make them depend on others,
          right?<br>
          - macros: clang-refactor only seems to work with spelling
          locations.</p>
        <p>Maybe an even simpler example: Replace all additions with
          "add(lhs, rhs)". This in itself is very difficult with clang
          as soon as the Stmts are nested or macros are involved.<br>
        </p>
        <p>Best regards<br>
          Rafael<br>
        </p>
        <br>
        <div class="moz-cite-prefix">On 16.07.2018 19:06, Jonas Toth via
          cfe-dev wrote:<br>
        </div>
        <blockquote type="cite"
          cite="mid:cef03437-19d3-fba7-82d9-2a7983011ddc@jonas-toth.eu">
          <p>Hi Rafael,</p>
          <p>wouldn't your usecase be a task for clang-refactor?</p>
          <p>Best,  Jonas<br>
          </p>
          <br>
          <div class="moz-cite-prefix">Am 16.07.2018 um 17:08 schrieb
            Rafael·Stahl via cfe-dev:<br>
          </div>
          <blockquote type="cite"
            cite="mid:78dd3056-9faa-4dae-5bf8-9d10f3a3219d@tum.de">Hey
            everyone <br>
            <br>
            The rewriting API of Clang operates on the source code in
            textual form. The user can use AST nodes to figure out what
            to replace, but in the end he has to remove and insert
            snippets in a linear piece of text. <br>
            <br>
            This is very inconvenient when it is required to restructure
            and nest replacements. The involvement of macros makes a
            manual process even more difficult. See some recent threads
            expressing difficulty with the API [1][2]. <br>
            <br>
            What do I mean by "nested replacements"? For example in the
            following: <br>
            <br>
                int i = x + s->a; <br>
            <br>
            I would want to replace the BinaryOperator with a function
            call and the MemberExpr with some constant: <br>
            <br>
                int i = Addition(x, 7); <br>
            <br>
            When keeping the two replacement rules independent of each
            other, achieving this with the current API is extremely
            difficult. More so when macros are involved. <br>
            <br>
            I am proposing some kind of helper that aims to solve these
            issues by providing an interface that offers to directly
            replace AST nodes and a mechanism to nest AST node
            replacements - without having to worry about macros. <br>
            <br>
            Potential usage: <br>
            <br>
            - Develop a class that derives from StmtToRewrite to define
            how replacements should happen: <br>
            <br>
                class RewriteAdds : public cu::StmtToRewrite <br>
                { <br>
                public: <br>
                    std::string makeReplaceStr() const override <br>
                    { <br>
                        auto binOp =
            dyn_cast<BinaryOperator>(replaceS); <br>
                        return "Addition(" +
            getMgr()->getReplaced(binOp->getLHS()).strToInsert +
            ", " + <br>
            getMgr()->getReplaced(binOp->getRHS()).strToInsert +
            ")"; <br>
                    } <br>
                }; <br>
            <br>
                class RewriteMembs : public cu::StmtToRewrite <br>
                { <br>
                public: <br>
                    std::string makeReplaceStr() const override <br>
                    { <br>
                        return "7"; <br>
                    } <br>
                }; <br>
            <br>
            - Construct a RewriteManager: <br>
            <br>
                cu::RewriteManager mgr(ACtx, PP); <br>
            <br>
            - Add rewriting operations to the manager: <br>
            <br>
                // std::vector<const Stmt *> AddStmts = /* matched
            from binaryOperator() with plus */ <br>
                // std::vector<const Stmt *> MembStmts = /*
            matched from memberExpr() */ <br>
                for (const auto &S : AddStmts)
            mgr.registerStmt<RewriteAdds>(S); <br>
                for (const auto &S : MembStmts)
            mgr.registerStmt<RewriteMembs>(S); <br>
            <br>
            - Retrieve and apply the results: <br>
            <br>
                clang::Rewriter rewriter(SM, LangOpts); <br>
                for (const auto &r : mgr.getReplacements()) { <br>
                    rewriter.RemoveText(r.rangeToRemove); <br>
                    rewriter.InsertText(r.rangeToRemove.getBegin(),
            r.strToInsert); <br>
                } <br>
            <br>
            <br>
            At the end of this mail is my low quality code that kind-of
            implements this. TLDR: <br>
            <br>
            - Build a hierarchy of stmts to replace and keep track of
            which replacements must be combined <br>
            - Move further up in the AST if these replacements are
            inside a macro <br>
            - Recursively lex the file and look for replacements
            outside-in by spelling locations. Expand any macros that are
            encountered during this. The re-lexing idea is based on the
            hint in [3]. <br>
            <br>
            The code has the following shortcomings: <br>
            <br>
            - I do not know how to distinguish macro argument expansions
            within macros. For example in "#define FOO(a) a + a" the two
            "a"s expand to different AST nodes that could be replaced
            with different rules. This is an important issue, because it
            can lead to completely broken code with nesting. <br>
            - Limited to Stmts, when Decls should be supported too. <br>
            - Very un-optimized with lexing the entire source file many
            times. Easy to solve, but didn't want to raise the
            complexity further for now. <br>
            - Could keep written code more clean by only expanding
            macros if required. For example not required if just a macro
            arg is replaced and all expansions would be the same. <br>
            <br>
            <br>
            I am very interested in your general thoughts. I'm not very
            experienced with clang, but this was my vision how I would
            want to do replacements. Are you interested in getting this
            into clang? I would need help with ironing out the remaining
            issues. <br>
            <br>
            -Rafael <br>
            <br>
            <br>
            [1] <a class="moz-txt-link-freetext"
              href="http://lists.llvm.org/pipermail/cfe-dev/2018-July/058430.html"
              moz-do-not-send="true">http://lists.llvm.org/pipermail/cfe-dev/2018-July/058430.html</a>
            <br>
            [2] <a class="moz-txt-link-freetext"
              href="http://lists.llvm.org/pipermail/cfe-dev/2018-June/058213.html"
              moz-do-not-send="true">http://lists.llvm.org/pipermail/cfe-dev/2018-June/058213.html</a>
            <br>
            [3] <a class="moz-txt-link-freetext"
              href="http://lists.llvm.org/pipermail/cfe-dev/2017-August/055079.html"
              moz-do-not-send="true">http://lists.llvm.org/pipermail/cfe-dev/2017-August/055079.html</a>
            <br>
            <br>
            <br>
            <br>
            ---------------------------------------- <br>
            <br>
            RewriteManager.h <br>
            <br>
            ---------------------------------------- <br>
            <br>
            #ifndef CLANGUTIL_REWRITEMANAGER_H <br>
            #define CLANGUTIL_REWRITEMANAGER_H <br>
            <br>
            #include "ClangUtil/SourceRangeLess.h" <br>
            #include "make_unique.h" <br>
            #include "clang/AST/AST.h" <br>
            #include <vector> <br>
            #include <map> <br>
            <br>
            <br>
            // TODO extend to decls <br>
            <br>
            <br>
            namespace cu <br>
            { <br>
            // Represents a statement in the original AST that should be
            rewritten. To implement recursive replacements, call <br>
            // getMgr()->getReplaced() on any AST node within the
            makeReplaceStr callback. <br>
            class StmtToRewrite <br>
            { <br>
                friend class RewriteManager; <br>
            <br>
            public: <br>
                // Returns the enclosing RewriteManager. <br>
                class RewriteManager *getMgr() const; <br>
                // Override this to build a replacement string.
            Implement recursive replacements with
            RewriteManager::getReplaced. <br>
                virtual std::string makeReplaceStr() const = 0; <br>
            <br>
                // The statement to replace. <br>
                const clang::Stmt *replaceS = nullptr; <br>
            <br>
            private: <br>
                RewriteManager *m_mgr; <br>
            }; <br>
            <br>
            struct RewriteOperation <br>
            { <br>
                clang::SourceRange rangeToRemove; <br>
                std::string strToInsert; <br>
            }; <br>
            <br>
            // A class for managing replacements of AST nodes. It allows
            to specifically target AST nodes instead of raw source <br>
            // locations to enable easy replacements involving macros
            and nested replacements. <br>
            // For extended documentation see: doc/rewriting.md <br>
            class RewriteManager <br>
            { <br>
            public: <br>
                RewriteManager(clang::ASTContext &ACtx,
            clang::Preprocessor &PP); <br>
            <br>
                clang::ASTContext &getACtx() const { return ACtx; }
            <br>
            <br>
                // Registers a StmtToRewrite for use with
            getReplacements. Call this on all <br>
                // statements that should be rewritten before calling
            any rewriting functions. <br>
                void registerStmt(std::unique_ptr<StmtToRewrite>
            S); <br>
            <br>
                // Helper for constructing the custom type from a Stmt.
            <br>
                template <typename T, typename... Args> <br>
                void registerStmt(const clang::Stmt *S, Args... args) <br>
                { <br>
                    auto p =
            std::make_unique<T>(std::forward<Args>(args)...);
            <br>
                    p->replaceS = S; <br>
                    registerStmt(std::move(p)); <br>
                } <br>
            <br>
                // Get the full replacement of an AST node. Note that
            this function removes any replaced statements from the work
            <br>
                // list, so calling it twice will only replace the first
            time. <br>
                RewriteOperation getReplaced(const clang::Stmt *S); <br>
                // Get all replacements. These may be fewer than the
            requested ones because of nesting. <br>
                std::vector<RewriteOperation> getReplacements(); <br>
            <br>
            private: <br>
                std::string getExpandedCode(const clang::Stmt
            *toReplaceS); <br>
            <br>
            private: <br>
                clang::ASTContext &ACtx; <br>
                const clang::LangOptions &LangOpts; <br>
                clang::SourceManager &SM; <br>
                clang::Preprocessor &PP; <br>
            <br>
                // Manages the pending replacements. <br>
                class WorkList <br>
                { <br>
                public: <br>
                    typedef std::map<clang::SourceRange,
            std::vector<const StmtToRewrite *>> RangeToRepMap;
            <br>
            <br>
                    WorkList(clang::ASTContext &ACtx,
            clang::SourceManager &SM); <br>
            <br>
                    bool isStmtPending(const clang::Stmt *S) const; <br>
                    void addStmt(std::unique_ptr<StmtToRewrite>
            S); <br>
                    const RangeToRepMap &getRangeToReplacementsMap()
            const; <br>
                    std::vector<const StmtToRewrite *>
            getSortedReplacements() const; <br>
                    void markDone(const StmtToRewrite *S); <br>
                    void cleanup(); <br>
            <br>
                private: <br>
                    clang::ASTContext &ACtx; <br>
                    clang::SourceManager &SM; <br>
                   
            std::vector<std::unique_ptr<StmtToRewrite>>
            m_pending; <br>
                   
            std::vector<std::unique_ptr<StmtToRewrite>>
            m_done; <br>
                    RangeToRepMap m_rangeToReplacements; <br>
                }; <br>
            <br>
                WorkList m_workList; <br>
            }; <br>
            <br>
            } // namespace cu <br>
            <br>
            #endif <br>
            <br>
            <br>
            <br>
            ---------------------------------------- <br>
            <br>
            RewriteManager.cpp <br>
            <br>
            ---------------------------------------- <br>
            <br>
            #include "ClangUtil/RewriteManager.h" <br>
            #include "ClangUtil/ASTUtil.h" <br>
            #include "clang/Lex/Lexer.h" <br>
            #include "clang/Lex/Preprocessor.h" <br>
            #include "clang/Lex/PreprocessorOptions.h" <br>
            #include "clang/Lex/TokenConcatenation.h" <br>
            #include "clang/Lex/MacroArgs.h" <br>
            <br>
            <br>
            using namespace cu; <br>
            <br>
            <br>
            // Returns a Stmt that is the first parent of startS whose
            expansion range is within the given range. <br>
            static const clang::Stmt
            *GetFullMacroStmt(clang::SourceRange range, const
            clang::Stmt *startS, clang::ASTContext &ACtx) <br>
            { <br>
                auto &SM = ACtx.getSourceManager(); <br>
            <br>
                // Walk the tree upwards until ST does no longer expand
            to within range. <br>
                const clang::Stmt *ST = startS; <br>
                while (true) <br>
                { <br>
                    const auto &parents = ACtx.getParents(*ST); <br>
                    if (parents.empty()) <br>
                    { <br>
                        break; <br>
                    } <br>
                    auto childS = ST; <br>
                    ST = parents[0].get<clang::Stmt>(); <br>
                    if (!ST) <br>
                    { <br>
                        if (auto D =
            parents[0].get<clang::Decl>()) <br>
                        { <br>
                            const auto &parentsD =
            ACtx.getParents(*D); <br>
                            if (parentsD.empty()) <br>
                            { <br>
                                break; <br>
                            } <br>
                            ST = parentsD[0].get<clang::Stmt>(); <br>
                            if (!ST) <br>
                            { <br>
                                break; <br>
                            } <br>
                        } <br>
                        else <br>
                        { <br>
                            break; <br>
                        } <br>
                    } <br>
            <br>
                    auto exLocS =
            SM.getExpansionLoc(ST->getLocStart()); <br>
                    auto exLocE =
            SM.getExpansionLoc(ST->getLocEnd()); <br>
                    if (SM.isBeforeInTranslationUnit(exLocS,
            range.getBegin()) || <br>
                        SM.isBeforeInTranslationUnit(range.getEnd(),
            exLocE)) <br>
                    { <br>
                        return childS; <br>
                    } <br>
                } <br>
            <br>
                return nullptr; <br>
            } <br>
            <br>
            <br>
            RewriteManager *StmtToRewrite::getMgr() const <br>
            { <br>
                return m_mgr; <br>
            } <br>
            <br>
            <br>
            RewriteManager::WorkList::WorkList(clang::ASTContext
            &ACtx, clang::SourceManager &SM) : ACtx(ACtx),
            SM(SM) {} <br>
            bool RewriteManager::WorkList::isStmtPending(const
            clang::Stmt *S) const <br>
            { <br>
                for (const auto &r : m_pending) <br>
                { <br>
                    if (r->replaceS == S) <br>
                    { <br>
                        return true; <br>
                    } <br>
                } <br>
                return false; <br>
            } <br>
            void
            RewriteManager::WorkList::addStmt(std::unique_ptr<StmtToRewrite>
            S) <br>
            { <br>
                // Use the expansion range for maximal replacement
            flexibility in macros. <br>
                auto replaceRange =
            SM.getExpansionRange(S->replaceS->getSourceRange()); <br>
            <br>
                // TODO not quite correct. <br>
                /*auto sortRanges = [&](std::vector<const
            StmtToRewrite *> &vec) { <br>
                    std::sort(vec.begin(), vec.end(), [&](const
            StmtToRewrite *lhs, const StmtToRewrite *rhs) { <br>
                        auto lhsRange =
            SM.getExpansionRange(lhs->replaceS->getSourceRange());
            <br>
                        auto rhsRange =
            SM.getExpansionRange(rhs->replaceS->getSourceRange());
            <br>
                        return IsContained(rhsRange, lhsRange, SM); <br>
                    }); <br>
                };*/ <br>
            <br>
                // Establish hierarchical relation between all ranges. <br>
                bool found = false; <br>
                // First, check if this range is within one we already
            have. <br>
                for (auto &r : m_rangeToReplacements) <br>
                { <br>
                    if (IsContained(replaceRange, r.first, SM)) <br>
                    { <br>
                        // Insert in a sorted order. <br>
                        for (auto it = r.second.begin(); it !=
            r.second.end(); ++it) <br>
                        { <br>
                            //auto testRange =
            SM.getExpansionRange((*it)->replaceS->getSourceRange());
            <br>
                            // if (IsContained(testRange, replaceRange,
            SM)) <br>
                            if (IsParent(S->replaceS,
            (*it)->replaceS, ACtx)) <br>
                            { <br>
                                r.second.insert(it, S.get()); <br>
                                found = true; <br>
                                break; <br>
                            } <br>
                        } <br>
                        if (!found) <br>
                        { <br>
                            r.second.push_back(S.get()); <br>
                            found = true; <br>
                        } <br>
                        break; <br>
                    } <br>
                } <br>
                // Not within existing range, add as new top-level
            range. <br>
                if (!found) <br>
                { <br>
                    // Check if any existing ranges are contained within
            the new one. <br>
                    std::vector<const StmtToRewrite *> moveThese;
            <br>
                    auto it = m_rangeToReplacements.begin(); <br>
                    while (it != m_rangeToReplacements.end()) <br>
                    { <br>
                        if (IsContained(it->first, replaceRange, SM))
            <br>
                        { <br>
                            moveThese.insert(moveThese.end(),
            it->second.begin(), it->second.end()); <br>
                            it = m_rangeToReplacements.erase(it); <br>
                        } <br>
                        else <br>
                        { <br>
                            ++it; <br>
                        } <br>
                    } <br>
                    auto &accesses =
            m_rangeToReplacements[replaceRange]; <br>
                    // The order is important here. We want the first
            element to be the one that spans the full range. <br>
                    accesses.push_back(S.get()); <br>
                    // TODO sort "moveThese". <br>
                    accesses.insert(accesses.end(), moveThese.begin(),
            moveThese.end()); <br>
                } <br>
            <br>
                int count = 0; <br>
                for (const auto &r : m_rangeToReplacements) <br>
                { <br>
                    printf("range %i\n", count++); <br>
                    for (const auto &a : r.second) <br>
                    { <br>
                        printf("replacement:\n"); <br>
                        a->replaceS->dump(); <br>
                    } <br>
                } <br>
            <br>
                m_pending.push_back(std::move(S)); <br>
            } <br>
            const RewriteManager::WorkList::RangeToRepMap
            &RewriteManager::WorkList::getRangeToReplacementsMap()
            const <br>
            { <br>
                return m_rangeToReplacements; <br>
            } <br>
            std::vector<const StmtToRewrite *>
            RewriteManager::WorkList::getSortedReplacements() const <br>
            { <br>
                std::vector<const StmtToRewrite *> result; <br>
                for (auto &r : m_rangeToReplacements) <br>
                { <br>
                    result.insert(result.end(), r.second.begin(),
            r.second.end()); <br>
                } <br>
                return result; <br>
            } <br>
            void RewriteManager::WorkList::markDone(const StmtToRewrite
            *S) <br>
            { <br>
                // Remove from hierarchy. <br>
                for (auto &r : m_rangeToReplacements) <br>
                { <br>
                    r.second.erase(std::remove(r.second.begin(),
            r.second.end(), S), r.second.end()); <br>
                } <br>
            <br>
                // Move from pending to done list. <br>
                auto it = std::find_if(m_pending.begin(),
            m_pending.end(), <br>
                                       [&](const
            std::unique_ptr<StmtToRewrite> &rep) { return
            rep.get() == S; }); <br>
                if (it == m_pending.end()) <br>
                { <br>
                    throw std::runtime_error("Did not find replacement
            to mark as done"); <br>
                } <br>
                m_done.push_back(std::move(*it)); <br>
                m_pending.erase(it); <br>
            } <br>
            void RewriteManager::WorkList::cleanup() <br>
            { <br>
                m_done.clear(); <br>
            } <br>
            <br>
            <br>
            RewriteManager::RewriteManager(clang::ASTContext &ACtx,
            clang::Preprocessor &PP) <br>
                : ACtx(ACtx), LangOpts(ACtx.getLangOpts()),
            SM(ACtx.getSourceManager()), PP(PP), m_workList(ACtx, SM) <br>
            { <br>
            } <br>
            <br>
            void
            RewriteManager::registerStmt(std::unique_ptr<StmtToRewrite>
            S) <br>
            { <br>
                if (!S->replaceS) <br>
                { <br>
                    throw std::runtime_error("Must set replaceS"); <br>
                } <br>
            <br>
                if (m_workList.isStmtPending(S->replaceS)) <br>
                { <br>
                    throw std::runtime_error("This Stmt will already be
            replaced"); <br>
                } <br>
            <br>
                S->m_mgr = this; <br>
                m_workList.addStmt(std::move(S)); <br>
            } <br>
            <br>
            RewriteOperation RewriteManager::getReplaced(const
            clang::Stmt *S) <br>
            { <br>
                auto range =
            SM.getExpansionRange(S->getSourceRange()); <br>
                return { range, getExpandedCode(S) }; <br>
            } <br>
            <br>
            std::vector<RewriteOperation>
            RewriteManager::getReplacements() <br>
            { <br>
                std::vector<RewriteOperation> results; <br>
            <br>
                for (auto &rangeAndAccesses :
            m_workList.getRangeToReplacementsMap()) <br>
                { <br>
                    auto &range = rangeAndAccesses.first; <br>
                    auto &accesses = rangeAndAccesses.second; <br>
            <br>
                    // Cannot replace something inside a macro because
            it would replace all expansions instead of just the selected
            <br>
                    // AST node. So in a first step, get an enclosing
            statement that is no longer inside a macro. <br>
                    // TODO we could keep the original code more clean
            by not expanding macro args if the whole expansion does not
            <br>
                    // contain the macro arg more than once. <br>
                    auto macroS = GetFullMacroStmt(range,
            accesses[0]->replaceS, ACtx); <br>
            <br>
                    results.push_back(getReplaced(macroS)); <br>
            <br>
                    // TODO we could run clang-format on the
            replacements. this would especially benefit long macro
            expansions. <br>
                } <br>
            <br>
                m_workList.cleanup(); <br>
            <br>
                return results; <br>
            } <br>
            <br>
            std::string RewriteManager::getExpandedCode(const
            clang::Stmt *toReplaceS) <br>
            { <br>
                // TODO performance optimization. this is parsing way
            more than required. <br>
            <br>
                using namespace clang; <br>
            <br>
                printf("getExpandedCode:\n"); <br>
                toReplaceS->dump(); <br>
            <br>
                std::string out; <br>
            <br>
                auto toReplaceExpStart =
            SM.getExpansionLoc(toReplaceS->getLocStart()); <br>
                auto toReplaceExpEnd =
            SM.getExpansionLoc(toReplaceS->getLocEnd()); <br>
                auto toReplaceSpellStart =
            SM.getSpellingLoc(toReplaceS->getLocStart()); <br>
                auto toReplaceSpellEnd =
            SM.getSpellingLoc(toReplaceS->getLocEnd()); <br>
            <br>
                auto FID =
            SM.getFileID(SM.getExpansionLoc(toReplaceS->getLocStart()));
            <br>
            <br>
                // The following is inspired by:
            clang/Rewrite/HTMLRewrite.cpp:HighlightMacros <br>
            <br>
                // Re-lex the raw token stream into a token buffer. <br>
                std::vector<Token> TokenStream; <br>
            <br>
                const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
            <br>
                Lexer L(FID, FromFile, SM, PP.getLangOpts()); <br>
            <br>
                // Lex all the tokens in raw mode, to avoid entering
            #includes or expanding <br>
                // macros. <br>
                while (1) <br>
                { <br>
                    Token Tok; <br>
                    L.LexFromRawLexer(Tok); <br>
            <br>
                    // If this is a # at the start of a line, discard it
            from the token stream. <br>
                    // We don't want the re-preprocess step to see
            #defines, #includes or other <br>
                    // preprocessor directives. <br>
                    if (Tok.is(tok::hash) &&
            Tok.isAtStartOfLine()) <br>
                        continue; <br>
            <br>
                    // If this is a ## token, change its kind to unknown
            so that repreprocessing <br>
                    // it will not produce an error. <br>
                    if (Tok.is(tok::hashhash)) <br>
                        Tok.setKind(tok::unknown); <br>
            <br>
                    // If this raw token is an identifier, the raw lexer
            won't have looked up <br>
                    // the corresponding identifier info for it.  Do
            this now so that it will be <br>
                    // macro expanded when we re-preprocess it. <br>
                    if (Tok.is(tok::raw_identifier)) <br>
                        PP.LookUpIdentifierInfo(Tok); <br>
            <br>
                    TokenStream.push_back(Tok); <br>
            <br>
                    for (auto &rep :
            m_workList.getSortedReplacements()) <br>
                    { <br>
                        auto repS = rep->replaceS; <br>
                        auto spellLoc =
            SM.getSpellingLoc(repS->getLocStart()); <br>
                        if (SM.getSpellingLoc(Tok.getLocation()) ==
            spellLoc) <br>
                        { <br>
                            // <br>
                        } <br>
                    } <br>
            <br>
                    if (Tok.is(tok::eof)) <br>
                        break; <br>
                } <br>
            <br>
                // Temporarily change the diagnostics object so that we
            ignore any generated <br>
                // diagnostics from this pass. <br>
                DiagnosticsEngine
            TmpDiags(PP.getDiagnostics().getDiagnosticIDs(),
            &PP.getDiagnostics().getDiagnosticOptions(), <br>
                                           new IgnoringDiagConsumer); <br>
            <br>
                // Copy the preprocessor and all of its state. <br>
                auto PPOpts =
            std::make_shared<PreprocessorOptions>(PP.getPreprocessorOpts());
            <br>
                LangOptions LO = PP.getLangOpts(); <br>
                Preprocessor TmpPP(PPOpts, TmpDiags, LO, SM,
            PP.getPCMCache(), PP.getHeaderSearchInfo(),
            PP.getModuleLoader(), <br>
            PP.getIdentifierTable().getExternalIdentifierLookup()); <br>
                TmpPP.Initialize(PP.getTargetInfo(),
            PP.getAuxTargetInfo()); <br>
                TmpPP.setExternalSource(PP.getExternalSource()); <br>
                TmpPP.setPreprocessedOutput(true); <br>
            <br>
                std::map<const clang::IdentifierInfo *, bool>
            MacroPreviouslyEnabled; <br>
                for (const auto &m : PP.macros()) <br>
                { <br>
                    // printf("PREDEF MACRO: %s\n",
            m.first->getName().str().c_str()); <br>
                    TmpPP.getMacroDefinition(m.first); <br>
            <br>
                    for (const auto &tmpm : TmpPP.macros()) <br>
                    { <br>
                        if (tmpm.first == m.first) <br>
                        { <br>
                            auto MD = m.second.getLatest(); <br>
                            auto MI = MD->getMacroInfo(); <br>
                            // If this is a recursive call we might be
            in a macro expansion and the macro might be disabled. We
            need <br>
                            // to enable it for now so that all
            expansions work. Restore it later. <br>
                            MacroPreviouslyEnabled[tmpm.first] =
            MI->isEnabled(); <br>
                            if (!MI->isEnabled()) <br>
                            { <br>
                                MD->getMacroInfo()->EnableMacro();
            <br>
                            } <br>
            <br>
                            // This should not change anything since we
            just copy data over. <br>
                            auto &mutableState =
            const_cast<std::remove_const<decltype(tmpm.second)>::type
            &>(tmpm.second); <br>
                            mutableState.setLatest(MD); <br>
                            break; <br>
                        } <br>
                    } <br>
                } <br>
            <br>
                class MacroArgCollector : public clang::PPCallbacks <br>
                { <br>
                public: <br>
                    MacroArgCollector(Preprocessor &TmpPP) :
            TmpPP(TmpPP) {} <br>
            <br>
                    void MacroExpands(const Token &Tok, const
            MacroDefinition &MD, SourceRange Range, const MacroArgs
            *Args) override <br>
                    { <br>
                        if (!Args) <br>
                        { <br>
                            return; <br>
                        } <br>
                        printf("GOT MACRO ARGS EXPANSION CALLBACK\n"); <br>
                        for (int i = 0; i <
            (int)Args->getNumMacroArguments(); i++) <br>
                        { <br>
                            auto TokUnex = Args->getUnexpArgument(i);
            <br>
                            // Thats just non-const for a cache, so
            should be fine. <br>
                            auto TokPreExp = const_cast<MacroArgs
            *>(Args)->getPreExpArgument(i, TmpPP); <br>
                            printf("unexp: %s\n",
            TmpPP.getSpelling(*TokUnex).c_str()); <br>
                            for (const auto &T : TokPreExp) <br>
                            { <br>
                                printf("preexp: %s\n",
            TmpPP.getSpelling(T).c_str()); <br>
                            } <br>
                        } <br>
                    } <br>
            <br>
                    Preprocessor &TmpPP; <br>
                }; <br>
TmpPP.addPPCallbacks(std::make_unique<MacroArgCollector>(TmpPP));
            <br>
                // Instead: collect the macro arg info in the law lexing
            step above. or do another pass that uses the PP but without
            expansions. <br>
            <br>
                /*printf("DUMP MACRO INFO\n"); <br>
                for (const auto &m : PP.macros()) <br>
                    PP.dumpMacroInfo(m.first); <br>
                printf("---\n"); <br>
                for (const auto &m : TmpPP.macros()) <br>
                    TmpPP.dumpMacroInfo(m.first); <br>
                printf("DUMP MACRO INFO END\n");*/ <br>
            <br>
                DiagnosticsEngine *OldDiags =
            &TmpPP.getDiagnostics(); <br>
            <br>
                // Inform the preprocessor that we don't want comments.
            <br>
                TmpPP.SetCommentRetentionState(false, false); <br>
            <br>
                // We don't want pragmas either. Although we filtered
            out #pragma, removing <br>
                // _Pragma and __pragma is much harder. <br>
                bool PragmasPreviouslyEnabled =
            TmpPP.getPragmasEnabled(); <br>
                TmpPP.setPragmasEnabled(false); <br>
            <br>
                // Enter the tokens we just lexed.  This will cause them
            to be macro expanded <br>
                // but won't enter sub-files (because we removed #'s). <br>
                TmpPP.EnterTokenStream(TokenStream, false); <br>
            <br>
                TokenConcatenation ConcatInfo(TmpPP); <br>
            <br>
                // Lex all the tokens. <br>
                Token Tok; <br>
                TmpPP.Lex(Tok); <br>
            <br>
                std::map<SourceLocation, int> slocIdx; <br>
            <br>
                auto checkReplacement = [&]() { <br>
                    for (auto &rep :
            m_workList.getSortedReplacements()) <br>
                    { <br>
                        // auto rep = r.second.get(); <br>
                        auto repS = rep->replaceS; <br>
                        auto spellLoc =
            SM.getSpellingLoc(repS->getLocStart()); <br>
                        // TODO we need to check here if the repS spans
            the full range (or largest?) <br>
                        if (SM.getSpellingLoc(Tok.getLocation()) ==
            spellLoc) <br>
                        { <br>
                            if (slocIdx[spellLoc] == 7) <br>
                            { <br>
                                // replace <br>
                            } <br>
                            slocIdx[spellLoc]++; <br>
            <br>
                            // Done replacing that one, but have to keep
            it alive until we're done with it. <br>
                            m_workList.markDone(rep); <br>
            <br>
                            printf("[[[\n"); <br>
                            auto repStr = rep->makeReplaceStr(); <br>
                            printf("REPLACED: %s ]]]\n",
            repStr.c_str()); <br>
                            out += repStr; <br>
            <br>
                            // Skip ahead until after the whole
            replacement. <br>
                            auto repEnd =
            SM.getSpellingLoc(repS->getLocEnd()); <br>
                            while (repEnd !=
            SM.getSpellingLoc(Tok.getLocation())) <br>
                            { <br>
                                TmpPP.Lex(Tok); <br>
                                assert(!Tok.is(tok::eof) && "End
            not found"); <br>
                            } <br>
            <br>
                            // Eat one more since we stopped at the end
            token and we want to continue after it. <br>
                            TmpPP.Lex(Tok); <br>
            <br>
                            return true; <br>
                        } <br>
                    } <br>
                    return false; <br>
                }; <br>
            <br>
                while (Tok.isNot(tok::eof)) <br>
                { <br>
                    printf("TOKEN: %s\n",
            TmpPP.getSpelling(Tok).c_str()); <br>
            <br>
                    auto TokLoc = Tok.getLocation(); <br>
                    auto TokExp = SM.getExpansionLoc(TokLoc); <br>
                    if (SM.isBeforeInTranslationUnit(toReplaceExpEnd,
            TokExp)) <br>
                    { <br>
                        // Anything after the Stmt we want to replace is
            not interesting. <br>
                        break; <br>
                    } <br>
            <br>
                    // Skip ahead until we are at the expansion start of
            the Stmt we want to replace. <br>
                    if (!SM.isBeforeInTranslationUnit(TokLoc,
            toReplaceExpStart)) <br>
                    { <br>
                        if (TokLoc.isMacroID()) <br>
                        { <br>
                            // This is the first token of a macro
            expansion. <br>
                            auto LLoc = SM.getExpansionRange(TokLoc); <br>
            <br>
                            // Ignore tokens whose instantiation
            location was not the main file. <br>
                            if (SM.getFileID(LLoc.first) != FID) <br>
                            { <br>
                                TmpPP.Lex(Tok); <br>
                                continue; <br>
                            } <br>
            <br>
                            assert(SM.getFileID(LLoc.second) == FID
            && <br>
                                   "Start and end of expansion must be
            in the same ultimate file!"); <br>
            <br>
                            bool stopOutputOnNextToken = false; <br>
                            bool toReplaceStartsInMacro =
            toReplaceExpStart == TokExp; <br>
                            bool toReplaceEndsInMacro = toReplaceExpEnd
            == TokExp; <br>
                            bool startedOutput = false; <br>
            <br>
                            Token PrevPrevTok; <br>
                            Token PrevTok = Tok; <br>
            <br>
                            while (!Tok.is(tok::eof) &&
            SM.getExpansionLoc(Tok.getLocation()) == LLoc.first) <br>
                            { <br>
                                printf("TOKEN (in macro): %s\n",
            TmpPP.getSpelling(Tok).c_str()); <br>
            <br>
                                auto TokSpell =
            SM.getSpellingLoc(Tok.getLocation()); <br>
                                if (stopOutputOnNextToken) <br>
                                { <br>
                                    break; <br>
                                } <br>
                                if (toReplaceEndsInMacro &&
            TokSpell == toReplaceSpellEnd) <br>
                                { <br>
                                    stopOutputOnNextToken = true; <br>
                                } <br>
            <br>
                                if (toReplaceStartsInMacro &&
            !startedOutput) <br>
                                { <br>
                                    if (TokSpell == toReplaceSpellStart)
            <br>
                                    { <br>
                                        startedOutput = true; <br>
                                    } <br>
                                    else <br>
                                    { <br>
                                        TmpPP.Lex(Tok); <br>
                                        continue; <br>
                                    } <br>
                                } <br>
            <br>
                                // If the tokens were already space
            separated, or if they must be to avoid <br>
                                // them being implicitly pasted, add a
            space between them. <br>
                                if (Tok.hasLeadingSpace() ||
            ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok)) <br>
                                    out += ' '; <br>
            <br>
                                if (checkReplacement()) <br>
                                { <br>
                                    continue; <br>
                                } <br>
            <br>
                                out += TmpPP.getSpelling(Tok); <br>
                                TmpPP.Lex(Tok); <br>
                            } <br>
                            if (stopOutputOnNextToken) <br>
                            { <br>
                                break; <br>
                            } <br>
                        } <br>
                        else <br>
                        { <br>
                            if (checkReplacement()) <br>
                            { <br>
                                continue; <br>
                            } <br>
            <br>
                            // Output original code because we are
            outside of a replacement. <br>
                            out += TmpPP.getSpelling(Tok); <br>
                            TmpPP.Lex(Tok); <br>
                        } <br>
                    } <br>
                    else <br>
                    { <br>
                        TmpPP.Lex(Tok); <br>
                    } <br>
                } <br>
            <br>
                // Restore the preprocessor's old state. <br>
                TmpPP.setDiagnostics(*OldDiags); <br>
                TmpPP.setPragmasEnabled(PragmasPreviouslyEnabled); <br>
            <br>
                for (const auto &tmpm : TmpPP.macros()) <br>
                { <br>
                    auto it = MacroPreviouslyEnabled.find(tmpm.first); <br>
                    if (it != MacroPreviouslyEnabled.end()) <br>
                    { <br>
                        auto MD = tmpm.second.getLatest(); <br>
                        auto MI = MD->getMacroInfo(); <br>
                        if (MI->isEnabled() &&
            !it->second) <br>
                        { <br>
                            MI->DisableMacro(); <br>
                        } <br>
                        else if (!MI->isEnabled() &&
            it->second) <br>
                        { <br>
                            MI->EnableMacro(); <br>
                        } <br>
                    } <br>
                } <br>
            <br>
                return out; <br>
            } <br>
            <br>
            <br>
            <fieldset class="mimeAttachmentHeader"></fieldset>
            <br>
            <pre wrap="">_______________________________________________
cfe-dev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:cfe-dev@lists.llvm.org" moz-do-not-send="true">cfe-dev@lists.llvm.org</a>
<a class="moz-txt-link-freetext" href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" moz-do-not-send="true">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a>
</pre>
          </blockquote>
          <br>
          <br>
          <fieldset class="mimeAttachmentHeader"></fieldset>
          <br>
          <pre wrap="">_______________________________________________
cfe-dev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:cfe-dev@lists.llvm.org" moz-do-not-send="true">cfe-dev@lists.llvm.org</a>
<a class="moz-txt-link-freetext" href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" moz-do-not-send="true">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a>
</pre>
        </blockquote>
        <br>
      </blockquote>
      <br>
    </blockquote>
  </body>
</html>