c++ objective-c selector clang llvm-c++-api

c++ - Herramienta de Clang: reescribir ObjCMessageExpr



objective-c selector (1)

Quiero reescribir todos los mensajes en mi código, necesito reemplazar solo los selectores, pero necesito poder reemplazar las expresiones anidadas fe:

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

Intenté hacerlo con clang::Rewriter replaceText y solo generar una nueva cadena, pero hay un problema: no funcionaría si cambio la longitud de los selectores, porque sustituyo los mensajes anidados con esas posiciones antiguas.

Entonces, asumí que necesito usar clang::Rewriter ReplaceStmt(originalStatement, newStatement);

Estoy usando RecursiveASTVisitor para visitar todos los mensajes, y quiero copiar esos objetos de mensajes y reemplazar los selectores:

¿Cómo puedo hacer eso?

Intenté usar ObjCMessageExpr::Create pero hay tantos argumentos, no sé cómo obtener los ASTContext &Context and ArrayRef<SourceLocation> SeLocs y Expr *Receiver ASTContext &Context and ArrayRef<SourceLocation> SeLocs del mensaje original.

¿Cuál es la forma correcta de reemplazar los selectores en los mensajes anidados usando la herramienta de Clang (interfaz de herramientas de Clang)?

Actualizar:

¿Debo usar la ReplaceStmtWithStmt llamada ASTMatchFinder y ASTMatchFinder ?

Actualizar:

Estoy usando la siguiente función para reescribir el texto en el archivo:

void ReplaceText(SourceLocation start, unsigned originalLength, StringRef string) { m_rewriter.ReplaceText(start, originalLength, string); m_rewriter.overwriteChangedFiles(); }

Y quiero reemplazar todos los mensajes EXPR en código con el nuevo selector fe: cómo fue:

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

como debería ser:

[object newSelector:[object2 newSelector:obj3 newSelector:obj4]];

Estoy usando ReqoursiveASTVisitor:

bool VisitStmt(Stmt *statement) { if (ObjCMessageExpr *messageExpr = dyn_cast<ObjCMessageExpr>(statement)) { ReplaceMessage(*messageExpr) } return true; }

Creé un método para generar un nuevo mensaje de cadena 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); }

El problema ocurre cuando trato de reemplazar los mensajes anidados, de esa manera:

[simpleClass doSomeActionWithString:string3 andAnotherString:string4]; [simpleClass doSomeActionWithString:str andAnotherString:str2]; [simpleClass doSomeActionWithString:@"" andAnotherString:@"asdasdsad"]; [simpleClass setSimpleClassZAZAZAZAZAZAZAZA:[simpleClass getSimpleClassZAZAZAZAZAZAZAZA]];

el resultado es:

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

porque messageExpression tiene el valor "antiguo" de getLocStart(); y getLocEnd(); ¿Cómo puedo arreglarlo?


Puede volver a escribir el nombre del selector reemplazando solo partes continuas del nombre del selector. Por ejemplo, reemplazar solo las partes subrayadas.

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

Para lograrlo solo necesitas

  • de piezas de selector - ObjCMessageExpr::getNumSelectorLocs()
  • sus ubicaciones - ObjCMessageExpr::getSelectorLoc(index)
  • sus longitudes - ObjCMessageExpr::getSelector().getNameForSlot(index).size() .

En general, puede volver a escribir ObjCMessageExpr con el siguiente RecursiveASTVisitor:

#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