أداة إعادة تجهيز مخصصة: سويفت

يسعى أي مهندس لجعل عملية عمله محسّنة قدر الإمكان. كمطورين لأجهزة iOS متنقلة ، غالبًا ما يتعين علينا العمل مع هياكل لغوية موحدة. تعمل Apple على تحسين أدوات المطورين من خلال بذل الكثير من الجهود لجعلها ملائمة لنا للبرمجة: تسليط الضوء على اللغة ، وطرق الإكمال التلقائي والعديد من ميزات IDE الأخرى التي تتيح لأصابعنا مواكبة الأفكار في رؤوسنا.



ماذا يفعل المهندس عندما تكون الأداة المطلوبة مفقودة؟ صحيح ، سوف يفعل كل شيء بنفسه! تحدثنا سابقًا عن إنشاء أدواتنا المخصصة ، والآن دعونا نتحدث عن كيفية تعديل Xcode وجعلها تعمل وفقًا لقواعدك.

لقد اتخذنا المهمة من JIRA Swift وصنعنا أداة تحول إذا ما تركنا حارسًا مكافئًا.



منذ الإصدار التاسع ، يوفر Xcode آلية إعادة تشكيل جديدة يمكنها تحويل التعليمات البرمجية محليًا ، داخل نفس ملف مصدر Swift ، أو بشكل عام عند إعادة تسمية طريقة أو خاصية تحدث في ملفات متعددة ، حتى لو كانت بلغات مختلفة.

يتم تطبيق إعادة التوطين المحلية بالكامل في برنامج مترجم SourceKit وإطار العمل ، وتقع الميزة في مستودع Swift مفتوح المصدر وتتم كتابتها بلغة C ++. يتعذر على الأشخاص العاديين تعديل إعادة التنظيم العالمي حاليًا ، لأن قاعدة كود Xcode مغلقة. لذلك ، سنناقش التاريخ المحلي ونتحدث عن كيفية تكرار تجربتنا.

ما تحتاجه لإنشاء أداة خاصة بك لإعادة التوطين المحلية:

  1. فهم C ++
  2. المعرفة الأساسية للمترجم
  3. فهم ما هو AST وكيفية العمل معها
  4. سويفت كود المصدر
  5. توجيه swift / docs / refactoring / SwiftLocalRefactoring.md
  6. الكثير من الصبر

قليلا عن AST


قليلا من الأساسيات النظرية قبل الغوص في الممارسة. دعونا نلقي نظرة على كيفية عمل بنية مترجم سويفت. بادئ ذي بدء ، المترجم هو المسؤول عن تحويل التعليمات البرمجية إلى رمز الجهاز القابل للتنفيذ.



من المراحل الموضحة للتحول ، الأكثر إثارة للاهتمام بالنسبة لنا هو إنشاء شجرة بناء جملة مجردة (AST) - رسم بياني تكون فيه القمم مشغلة والأوراق هي معاملاتها.



يتم استخدام أشجار بناء الجملة في المحلل اللغوي. يستخدم AST كتمثيل داخلي في المحول البرمجي / المترجم الشفهي لبرنامج كمبيوتر لتحسين وتوليد التعليمات البرمجية.

بعد إنشاء AST ، يتم إجراء التحليل لإنشاء AST مع التحقق من النوع الذي تم ترجمته إلى Swift Intermediate Language. يتم تحويل SIL ، تحسينه ، خفضه إلى LLVM IR ، والذي يجمع في نهاية المطاف إلى رمز الجهاز.

لإنشاء أداة إعادة التنظيم ، نحتاج إلى فهم AST وأن نكون قادرين على التعامل معها. لذلك ستتمكن الأداة من العمل بشكل صحيح مع أجزاء من الشفرة التي نريد معالجتها.

لإنشاء AST لملف ، قم بتشغيل الأمر: swiftc- dump -ast MyFile.swift

أدناه هو الإخراج إلى وحدة التحكم AST من الدالة if let ، والذي تم ذكره مسبقًا.



هناك ثلاثة أنواع رئيسية من العقد في Swift AST:

  • التعريفات (الفئات الفرعية من النوع Decl) ،
  • التعبيرات (الفئات الفرعية من النوع Expr) ،
  • عوامل التشغيل (فئات فرعية من النوع Stmt).

أنها تتوافق مع الكيانات الثلاثة التي يتم استخدامها في لغة سويفت نفسها. أسماء الوظائف ، الهياكل ، المعلمات هي تصريحات. التعبيرات هي كيانات تُرجع قيمة ؛ على سبيل المثال ، استدعاء وظائف. المشغلون هم أجزاء من اللغة تحدد تدفق التحكم في تنفيذ التعليمات البرمجية ، لكن لا تُرجع قيمة (على سبيل المثال ، إذا أو لا تفعل).

هذا هو الحد الأدنى الذي تحتاج لمعرفته حول AST لعملك القادم.

كيف تعمل أداة إعادة البناء في النظرية


لتنفيذ أدوات إعادة التجهيز ، تحتاج إلى معلومات محددة حول مجال الكود الذي ستقوم بتغييره. يتم توفير المطورين مع الكيانات المساعدة التي تجمع البيانات. الأول ، ResolvedCursorInfo (إعادة هيكلة مبنية على المؤشر) ، يخبرك إذا كنا في بداية تعبير. إذا كان الأمر كذلك ، يتم إرجاع كائن برنامج التحويل البرمجي المقابل لهذا التعبير. يقوم الكيان الثاني ، RangeInfo (إعادة التنظيم على أساس النطاق) ، بتغليف بيانات حول النطاق الأصلي (على سبيل المثال ، عدد نقاط الدخول والخروج التي لديه).

يتم بدء إعادة بناء المستندة إلى المؤشر بواسطة موقع المؤشر في الملف المصدر. تطبق إجراءات إعادة التجهيز الأساليب التي تستخدمها آلية إعادة التجهيز لعرض الإجراءات المتاحة في IDE وإجراء التحويلات. أمثلة على الإجراءات المستندة إلى المؤشر: الانتقال إلى التعريف ، المساعدة السريعة ، إلخ.



النظر في الإجراءات المعتادة من الجانب الفني:

  1. عند تحديد موقع من محرر Xcode ، يتم تقديم طلب إلى sourcekitd (الإطار المسؤول عن التمييز وإكمال التعليمات البرمجية ، وما إلى ذلك) لعرض إجراءات إعادة التسكين المتاحة.
  2. يتم طلب كل إجراء متاح بواسطة كائن ResolvedCursorInfo للتحقق مما إذا كان هذا الإجراء ينطبق على الرمز المحدد.
  3. يتم إرجاع قائمة الإجراءات القابلة للتطبيق كاستجابة من sourcekitd وعرضها في Xcode.
  4. Xcode ثم يطبق التغييرات على أداة إعادة التمويل.

يتم البدء في إعادة التخزين على أساس النطاق من خلال اختيار مجموعة مستمرة من التعليمات البرمجية في الملف المصدر.



في هذه الحالة ، ستنتقل أداة إعادة التنظيم عبر سلسلة اتصال مماثلة تم وصفها. الفرق هو أنه عند تطبيقه ، يكون الإدخال هو RangeInfo بدلاً من ResolvedCursorInfo. يمكن للقراء المهتمين الرجوع إلى Refactoring.cpp لمزيد من المعلومات حول أمثلة مجموعة أدوات Apple.

والآن إلى ممارسة إنشاء أداة.

تدريب


بادئ ذي بدء ، تحتاج إلى تنزيل وبناء المترجم Swift. التعليمات التفصيلية موجودة في المستودع الرسمي ( readme.md ). فيما يلي الأوامر الرئيسية لاستنساخ الكود:

mkdir swift-source cd swift-source git clone https://github.com/apple/swift.git ./swift/utils/update-checkout --clone 

يستخدم Cmake لوصف هيكل واعتمادية المشروع. باستخدامه ، يمكنك إنشاء مشروع لـ Xcode (أكثر ملاءمة) أو للنينجا (أسرع) بسبب أحد الأوامر:

 ./utils/build-script --debug --xcode 

أو
 swift/utils/build-script --debug-debuginfo 

يتطلب التجميع الناجح أحدث إصدار من الإصدار التجريبي من Xcode (الإصدار 10.2.1 وقت كتابة هذا التقرير) - متاح على موقع Apple الرسمي على الويب . لاستخدام Xcode الجديد لإنشاء المشروع ، تحتاج إلى تسجيل المسار باستخدام الأداة المساعدة لتحديد xcode:

 sudo xcode-select -s /Users/username/Xcode.app 

إذا استخدمنا علامة - xcode لإنشاء مشروع لـ Xcode ، على التوالي ، ثم بعد عدة ساعات من التحويل البرمجي (حصلنا على أكثر قليلاً من اثنين) في مجلد الإنشاء ، سنجد ملف Swift.xcodeproj. عند فتح المشروع ، سنرى Xcode المألوف مع الفهرسة ، نقاط التوقف.

لإنشاء أداة جديدة ، نحتاج إلى إضافة الكود مع منطق الصك إلى الملف: lib / IDE / Refactoring.cpp وتحديد طريقتين ، قابل للتطبيق و performChange. في الطريقة الأولى ، نقرر ما إذا كان سيتم إخراج خيار إعادة التسكين للرمز المحدد. وفي الثانية - كيفية تحويل التعليمات البرمجية المحددة لتطبيق إعادة البيع.

بعد الانتهاء من الإعداد ، يبقى تنفيذ الخطوات التالية:

  1. قم بتطوير منطق الأداة (يمكن إجراء التطوير بعدة طرق - من خلال سلسلة الأدوات ، من خلال Ninja ، من خلال Xcode ، سيتم شرح جميع الخيارات أدناه)
  2. تنفيذ طريقتين: isApplicable و performChange (فهي مسؤولة عن الوصول إلى الأداة وتشغيلها)
  3. تشخيص واختبار الأداة النهائية قبل إرسال PR إلى مستودع Swift الرسمي.

اختبار تشغيل الأداة من خلال toolchain


ستأخذك طريقة التطوير هذه كثيرًا من الوقت نظرًا للتجميع الطويل للمكونات ، لكن النتيجة ستكون مرئية على الفور في Xcode - طريقة التحقق منها يدويًا.

للبدء ، دعونا نبني سلسلة أدوات Swift باستخدام الأمر:

 ./utils/build-toolchain some_bundle_id 

سيستغرق تجميع مجموعة الأدوات وقتًا أطول من تجميع المترجم والتبعيات. الإخراج هو الملف swift-LOCAL-yyyy-mm-dd.xctoolchain في مجلد التثبيت السريع ليلا ، والذي تحتاج إلى نقله إلى Xcode: / Library / Developer / Toolchains /. بعد ذلك ، في إعدادات IDE ، حدد toolchain الجديدة ، أعد تشغيل Xcode.



حدد جزءًا من التعليمات البرمجية التي يجب أن تعالجها الأداة ، وابحث عن الأداة في قائمة السياق.

التنمية من خلال الاختبارات مع النينجا


إذا كان المشروع مصممًا للنينجا واخترت مسار TDD ، فإن التطوير من خلال الاختبارات مع Ninja هو أحد الخيارات التي تناسبك. سلبيات - لا يمكنك تعيين نقاط التوقف ، كما هو الحال في التطوير من خلال Xcode.

لذلك ، نحن بحاجة إلى التحقق من أن الأداة الجديدة معروضة في Xcode عندما يحدد المستخدم بنية الحماية في الكود المصدر. نكتب الاختبار في ملف الاختبار / إعادة التوطين الحالي / RefactoringKind / basic.swift:

 func testConvertToGuardExpr(idxOpt: Int?) {    if let idx = idxOpt {        print(idx)    } } //     . // RUN: %refactor -source-filename %s -pos=266:3 -end-pos=268:4 | %FileCheck %s -check-prefix=CHECK-CONVERT-TO-GUARD-EXPRESSION // CHECK-CONVERT-TO-GUARD-EXPRESSION: Convert To Guard Expression 


نشير إلى أنه عند تمييز الكود بين 266 عمودًا 3 أعمدة و 268 صفًا 4 أعمدة ، نتوقع ظهور عنصر قائمة باستخدام أداة جديدة.

يمكن أن يوفر استخدام البرنامج النصي lit.py تغذية مرتدة أسرع لدورة التطوير الخاصة بك. يمكنك تحديد دعوى اختبار الفائدة. في حالتنا ، سيكون هذا الجناح RefactoringKind:

./llvm/utils/lit/lit.py -sv ./build/Ninja-RelWithDebInfoAssert/swift-macosx-x86_64/test-macosx-x86_64/refactoring/RefactoringKind/
نتيجة لذلك ، سيتم إطلاق اختبارات لهذا الملف فقط. سوف يستغرق تنفيذها بضع عشرات من الثواني. ستتم مناقشة المزيد من المعلومات حول lit.py لاحقًا في قسم التشخيص والاختبار.
فشل الاختبار ، وهو أمر طبيعي لنموذج TDD. بعد كل شيء ، حتى الآن لم نكتب سطرًا واحدًا من التعليمات البرمجية مع منطق الأداة.

التنمية من خلال تصحيح الأخطاء و Xcode


وأخيرًا ، طريقة التطوير الأخيرة عندما تم بناء المشروع تحت Xcode. الإضافة الرئيسية هي القدرة على تعيين نقاط التوقف والتحكم في تصحيح الأخطاء.

عند إنشاء مشروع تحت Xcode ، يتم إنشاء ملف Swift.xcodeproj في المجلد build / Xcode-DebugAssert / swift-macosx-x86_64 /. عند فتح هذا الملف لأول مرة ، من الأفضل اختيار إنشاء مخططات يدويًا لإنشاء ALL_BUILD و refactor بنفسك:



بعد ذلك ، نقوم ببناء المشروع باستخدام ALL_BUILD مرة واحدة ، وبعد ذلك نستخدم مخطط refactor السريع.

يتم تجميع أداة إعادة بيع الأراضي في ملف منفصل قابل للتنفيذ - سريع refactor. يمكن عرض التعليمات الخاصة بهذا الملف باستخدام علامة –help. المعلمات الأكثر إثارة للاهتمام بالنسبة لنا هي:

 -source-filename=<string> //   -pos=<string> //   -end-pos=<string> //   -kind //   

يمكن تحديدها في المخطط كوسيطات. يمكنك الآن تعيين نقاط التوقف للتوقف في الأماكن ذات الاهتمام عند بدء تشغيل الأداة. بالطريقة المعتادة ، باستخدام أوامر p و po في وحدة تحكم Xcode ، فإنه يعرض قيم المتغيرات المقابلة.



تطبيق قابل للتطبيق


يقبل الأسلوب isApplicable ResolvedRangeInfo مع معلومات حول العقد AST من جزء التعليمات البرمجية المحددة في الإدخال. عند إخراج الطريقة ، يتم تحديد ما إذا كان سيتم عرض الأداة أم لا في قائمة سياق Xcode. يمكن العثور على واجهة ResolvedRangeInfo الكاملة في ملف التضمين / swift / IDE / Utils.h .

ضع في اعتبارك حقول فئة ResolvedRangeInfo الأكثر فائدة في حالتنا:

  • RangeKind - أول شيء فعله هو التحقق من نوع المنطقة المحددة. إذا كانت المنطقة غير صالحة (غير صالحة) ، يمكنك إرجاع false. إذا كان النوع يناسبنا ، على سبيل المثال ، SingleStatement أو MultiStatement ، فانتقل ؛

  • ContainedNodes - مجموعة من عناصر AST التي تقع في النطاق المحدد. نريد التأكد من قيام المستخدم بتحديد النطاق الذي ستدخله الإنشاءات إن سمحت. للقيام بذلك ، نأخذ العنصر الأول من الصفيف ونتحقق من أن هذا العنصر يتوافق مع IfStmt (الفئة التي تحدد عقدة AST لعقدة العبارة الخاصة بالنوع الفرعي if). بعد ذلك ، انظر الشرط. لتبسيط التنفيذ ، سنقوم بإخراج الأداة للتعبيرات فقط بشرط واحد. حسب نوع الشرط (CK_PatternBinding) ، نحدد أن هذا مسموح به.



لاختبار isApplicable ، قم بإضافة نموذج التعليمة البرمجية إلى ملف اختبار / refactoring / RefactoringKind / basic.swift .



لكي يحاكي الاختبار مكالمة إلى أداتنا ، يلزمك إضافة سطر في ملف tools / swift-refactor / swift-refactor.cpp .  



نحن ننفذ performChange


يتم استدعاء هذه الطريقة عند تحديد أداة إعادة التجهيز في قائمة السياق. الأسلوب لديه حق الوصول إلى ResolvedRangeInfo ، وكذلك في isApplicable. نستخدم ResolvedRangeInfo ونكتب منطق أداة تحويل الشفرة.

عند إنشاء رمز للرموز الثابتة (ينظمه بناء جملة اللغة) ، يمكنك استخدام الكيانات من مساحة الاسم tok. على سبيل المثال ، بالنسبة للكلمة الرئيسية للحراسة ، استخدم tok :: kw_guard. بالنسبة إلى الرموز الديناميكية (المعدلة بواسطة المطور ، على سبيل المثال ، اسم الوظيفة) ، تحتاج إلى تحديدها من صفيف عناصر AST.

لتحديد مكان إدراج الرمز المحول ، نستخدم النطاق المحدد بالكامل باستخدام بنية RangeInfo.ContentRange.



التشخيص والاختبار


قبل أن تنتهي من العمل على أداة ، تحتاج إلى التحقق من صحة عملها مرة أخرى. الاختبارات سوف تساعدنا مرة أخرى. يمكن تشغيل الاختبارات واحدة في كل مرة أو مع جميع النطاقات المتاحة. أسهل طريقة لتشغيل مجموعة اختبار Swift بأكملها هي من خلال --test command على utils / build-script ، والذي سيقوم بتشغيل مجموعة الاختبار الرئيسية. سيؤدي استخدام utils / build-script إلى إعادة بناء جميع الأهداف ، مما يمكن أن يزيد بشكل كبير من وقت دورة تصحيح الأخطاء.

تأكد من تشغيل اختبارات التحقق من صحة اختبار utils / build - script قبل إجراء تغييرات كبيرة على برنامج التحويل البرمجي أو واجهة برمجة التطبيقات.

هناك طريقة أخرى لتشغيل جميع اختبارات وحدة المترجم - من خلال النينجا ، فحص النينجا السريع من build / preset / swift-macosx-x86_64. سوف يستغرق حوالي 15 دقيقة.

وأخيرا ، الخيار عندما تحتاج إلى تشغيل الاختبارات بشكل منفصل. لاستدعاء البرنامج النصي lit.py مباشرةً من LLVM ، يجب عليك تكوينه لاستخدام دليل الإنشاء المحلي. على سبيل المثال:

 % $ {LLVM_SOURCE_ROOT} /utils/lit/lit.py -sv $ {SWIFT_BUILD_DIR} / test-macosx-x86_64 / Parse / 

سيؤدي هذا إلى إجراء الاختبارات في دليل 'test / Parse /' لنظام macos 64 بت. يوفر الخيار -sv مؤشرًا لتنفيذ الاختبار ويظهر نتائج الاختبارات الفاشلة فقط.

يحتوي Lit.py على بعض الميزات المفيدة الأخرى ، مثل اختبارات التوقيت واختبار زمن الانتقال. يمكنك عرض هذه الميزات وغيرها باستخدام lit.py -h. الأكثر فائدة يمكن العثور عليها هنا .

لتشغيل اختبار واحد ، اكتب:

  ./llvm/utils/lit/lit.py -sv ./build/Ninja-RelWithDebInfoAssert/swift-macosx-x86_64/test-macosx-x86_64/refactoring/RefactoringKind/basic.swift 

إذا احتجنا إلى سحب آخر التغييرات في برنامج التحويل البرمجي ، فإننا نحتاج إلى تحديث جميع التبعيات وإجراء إعادة صياغة. للترقية ، شغّل ./utils/update-checkout.

النتائج


لقد نجحنا في تحقيق هدفنا - وهو إنشاء أداة لم تكن موجودة سابقًا في IDE لتحسين العمل. إذا كانت لديك أيضًا أفكار حول كيفية تحسين منتجات Apple وتجعل الحياة أسهل لمجتمع iOS بأكمله ، فلا تتردد في استخدام العلامة التجارية المضادة ، لأنها أسهل مما يبدو للوهلة الأولى!

في عام 2015 ، حملت Apple شفرة مصدر Swift إلى المجال العام ، مما أتاح الوصول إلى تفاصيل تنفيذ برنامج التحويل البرمجي الخاص بها. بالإضافة إلى ذلك ، مع Xcode 9 ، يمكنك إضافة أدوات إعادة تجهيز محلية. المعرفة الأساسية لـ C ++ وجهاز التحويل البرمجي كافية لجعل IDE المفضل لديك أكثر ملاءمة.

كانت التجربة الموصوفة مفيدة لنا - بالإضافة إلى إنشاء أداة تُبسّط عملية التطوير ، حصلنا على معرفة قوية حقًا باللغة. يتيح لك صندوق Pandora المفتوح قليلًا مع عمليات منخفضة المستوى النظر إلى المهام اليومية من زاوية جديدة.

نأمل أن تكتسب المعرفة المكتسبة تفهمك للتطور!

تمت كتابة المواد بشكل مشترك مع @ victoriaqb - Victoria Kashlina ، مطور نظام التشغيل iOS.

مصادر


  1. جهاز التحويل البرمجي السريع. الجزء 2
  2. كيفية بناء سويفت القائم على أداة مترجم؟ دليل خطوة بخطوة
  3. إلقاء سويفت AST لمشروع iOS
  4. إدخال sourcekitd اختبار الإجهاد
  5. اختبار سريع
  6. [SR-5744] إعادة تنظيم العمل لتحويل if-let إلى guard-let والعكس بالعكس # 24566

Source: https://habr.com/ru/post/ar460227/


All Articles