我想重写代码中的所有消息,
我只需要替换选择器,但是我需要能够替换嵌套表达式
F。 e。 :

[super foo:[someInstance someMessage:@""] foo2:[someInstance someMessage2]];

我尝试用clang::Rewriter replaceText做到这一点,只是生成新的字符串,
但是有一个问题:如果更改选择器的长度,它将不起作用,因为我用这些旧位置替换了嵌套消息。

所以,我假设我需要使用clang::Rewriter ReplaceStmt(originalStatement, newStatement);
我正在使用RecursiveASTVisitor来访问所有消息,并且我想复制这些消息对象并替换选择器:

我怎样才能做到这一点?

我尝试使用ObjCMessageExpr::Create,但是参数太小了,我不知道如何从原始消息中获取ASTContext &Context and ArrayRef<SourceLocation> SeLocsExpr *Receiver参数。

使用clang工具(clang工具界面)替换嵌套消息中的选择器的正确方法是什么?

更新:

我应该使用ReplaceStmtWithStmt回调和ASTMatchFinder吗?

更新:

我正在使用以下功能来重写文件中的文本:
void ReplaceText(SourceLocation start, unsigned originalLength, StringRef string) {
    m_rewriter.ReplaceText(start, originalLength, string);
    m_rewriter.overwriteChangedFiles();
}

我想用新的选择器f替换代码中的所有messageExpr:
它怎么样:
[object someMessage:[object2 someMessage:obj3 calculate:obj4]];

应该如何:
[object newSelector:[object2 newSelector:obj3 newSelector:obj4]];

我正在使用ReqoursiveASTVisitor:
bool VisitStmt(Stmt *statement) {
    if (ObjCMessageExpr *messageExpr = dyn_cast<ObjCMessageExpr>(statement)) {
         ReplaceMessage(*messageExpr)
    }
    return true;
}

我创建了用于生成新消息expr字符串的方法:
string StringFromObjCMessageExpr(ObjCMessageExpr& messageExpression) {
    std::ostringstream stringStream;
    const string selectorString = messageExpression.getSelector().getAsString();
    cout << selectorString << endl;
    vector<string> methodParts;
    split(selectorString, ParametersDelimiter, methodParts);
    stringStream << "[" ;
    const string receiver = GetStringFromLocations(m_compiler, messageExpression.getReceiverRange().getBegin(), messageExpression.getSelectorStartLoc());
    stringStream << receiver;
    clang::ObjCMessageExpr::arg_iterator argIterator = messageExpression.arg_begin();
    for (vector<string>::const_iterator partsIterator = methodParts.begin();
         partsIterator != methodParts.end();
         ++partsIterator) {
        stringStream << "newSelector";
        if (messageExpression.getNumArgs() != 0) {
            const clang::Stmt *argument = *argIterator;
            stringStream << ":" << GetStatementString(*argument) << " ";
            ++argIterator;
        }
    }
    stringStream << "]";
    return stringStream.str();
}

void ReplaceMessage(ObjCMessageExpr& messageExpression) {
    SourceLocation locStart = messageExpression.getLocStart();
    SourceLocation locEnd = messageExpression.getLocEnd();
    string newExpr = StringFromObjCMessageExpr(messageExpression);
    const int exprStringLegth = m_rewriter.getRangeSize(SourceRange(locStart, locEnd));
    ReplaceText(locStart, exprStringLegth, newExpr);
}

当我尝试替换嵌套消息时,会发生此问题:
[simpleClass doSomeActionWithString:string3 andAnotherString:string4];
[simpleClass doSomeActionWithString:str andAnotherString:str2];
[simpleClass doSomeActionWithString:@"" andAnotherString:@"asdasdsad"];
[simpleClass setSimpleClassZAZAZAZAZAZAZAZA:[simpleClass getSimpleClassZAZAZAZAZAZAZAZA]];

结果是:
[simpleClass newSelector:string3 newSelector:string4 ];
[simpleClass newSelector:str newSelector:str2 ];
[simpleClass newSelector:@"" newSelector:@"asdasdsad" ];
[simpleClass newSelector:[simpleClass getSimp[simpleClass newSelector]];

因为messageExpression具有getLocStart();getLocEnd();的“旧”值,我该如何解决?

最佳答案

您可以通过仅替换选择器名称的连续部分来重写选择器名称。例如,仅更换带下划线的零件

[object someMessage:[object2 someMessage:obj3 calculate:obj4]];
        ^~~~~~~~~~~          ^~~~~~~~~~~      ^~~~~~~~~

为此,您只需要
  • 选择器部件的数量-ObjCMessageExpr::getNumSelectorLocs()
  • 他们的位置-ObjCMessageExpr::getSelectorLoc(index)
  • 的长度-ObjCMessageExpr::getSelector().getNameForSlot(index).size()

  • 总体而言,您可以使用以下RecursiveASTVisitor重写ObjCMessageExpr:
    #include "clang/AST/ASTConsumer.h"
    #include "clang/AST/ASTContext.h"
    #include "clang/AST/RecursiveASTVisitor.h"
    #include "clang/Rewrite/Core/Rewriter.h"
    
    namespace clang_tooling
    {
    
    using clang::SourceLocation;
    
    class RewritingVisitor : public clang::ASTConsumer,
                             public clang::RecursiveASTVisitor<RewritingVisitor>
    {
    public:
        // You can obtain SourceManager and LangOptions from CompilerInstance when
        // you are creating visitor (which is also ASTConsumer) in
        // clang::ASTFrontendAction::CreateASTConsumer.
        RewritingVisitor(clang::SourceManager &sourceManager,
                         const clang::LangOptions &langOptions)
            : _sourceManager(sourceManager), _rewriter(sourceManager, langOptions)
        {}
    
        virtual void HandleTranslationUnit(clang::ASTContext &context)
        {
            TraverseDecl(context.getTranslationUnitDecl());
            _rewriter.overwriteChangedFiles();
        }
    
        bool VisitObjCMessageExpr(clang::ObjCMessageExpr *messageExpr)
        {
            if (_sourceManager.isInMainFile(messageExpr->getLocStart()))
            {
                clang::Selector selector = messageExpr->getSelector();
                for (unsigned i = 0, end = messageExpr->getNumSelectorLocs();
                     i < end; ++i)
                {
                    SourceLocation selectorLoc = messageExpr->getSelectorLoc(i);
                    _rewriter.ReplaceText(selectorLoc,
                                          selector.getNameForSlot(i).size(),
                                          "newSelector");
                }
            }
            return Base::VisitObjCMessageExpr(messageExpr);
        }
    
    private:
        typedef clang::RecursiveASTVisitor<RewritingVisitor> Base;
    
        clang::SourceManager &_sourceManager;
        clang::Rewriter _rewriter;
    };
    
    } // end namespace clang_tooling
    

    10-08 11:56