|
17 | 17 | #include "swift/AST/Module.h"
|
18 | 18 | #include "swift/AST/ModuleLoader.h"
|
19 | 19 | #include "swift/AST/PluginRegistry.h"
|
| 20 | +#include "swift/AST/SourceFile.h" |
20 | 21 | #include "swift/Basic/Assertions.h"
|
21 | 22 | #include "swift/Basic/FileTypes.h"
|
22 | 23 | #include "swift/Basic/JSONSerialization.h"
|
23 | 24 | #include "swift/Frontend/FrontendOptions.h"
|
| 25 | +#include "swift/IDE/SourceEntityWalker.h" |
24 | 26 |
|
25 | 27 | #include "clang/Basic/Module.h"
|
| 28 | +#include "clang/AST/DeclObjC.h" |
26 | 29 |
|
27 | 30 | #include "llvm/ADT/SmallPtrSet.h"
|
28 | 31 | #include "llvm/ADT/SmallString.h"
|
@@ -810,3 +813,69 @@ bool swift::emitLoadedModuleTraceIfNeeded(ModuleDecl *mainModule,
|
810 | 813 | }
|
811 | 814 | return false;
|
812 | 815 | }
|
| 816 | + |
| 817 | + |
| 818 | +bool swift::emitObjCMessageSendTraceIfNeeded(ModuleDecl *mainModule, |
| 819 | + const FrontendOptions &opts) { |
| 820 | + ASTContext &ctxt = mainModule->getASTContext(); |
| 821 | + assert(!ctxt.hadError() && |
| 822 | + "We should've already exited earlier if there was an error."); |
| 823 | + class ObjcMethodRefereceCollector: public SourceEntityWalker { |
| 824 | + std::set<const clang::ObjCMethodDecl*> results; |
| 825 | + bool visitDeclReference(ValueDecl *D, CharSourceRange Range, |
| 826 | + TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, |
| 827 | + Type T, ReferenceMetaData Data) override { |
| 828 | + if (!Range.isValid()) |
| 829 | + return true; |
| 830 | + if (auto *clangD = dyn_cast_or_null<clang::ObjCMethodDecl>(D->getClangDecl())) { |
| 831 | + results.insert(clangD); |
| 832 | + } |
| 833 | + return true; |
| 834 | + } |
| 835 | + public: |
| 836 | + void dump(llvm::raw_ostream &OS) { |
| 837 | + OS << "[\n"; |
| 838 | + for (const clang::ObjCMethodDecl* clangD: results) { |
| 839 | + auto &SM = clangD->getASTContext().getSourceManager(); |
| 840 | + clang::SourceLocation Loc = clangD->getLocation(); |
| 841 | + if (!Loc.isValid()) { |
| 842 | + continue; |
| 843 | + } |
| 844 | + OS << "\t{\n"; |
| 845 | + OS << "\t\t\"method_name\": \"" << clangD->getNameAsString() << "\",\n"; |
| 846 | + OS << "\t\t\"location\": \"" << Loc.printToString(SM) << "\"\n"; |
| 847 | + OS << "\t}"; |
| 848 | + OS << ",\n"; |
| 849 | + } |
| 850 | + OS << "{} ]\n"; |
| 851 | + } |
| 852 | + }; |
| 853 | + opts.InputsAndOutputs.forEachInput([&](const InputFile &input) { |
| 854 | + auto loadedModuleTracePath = input.getLoadedModuleTracePath(); |
| 855 | + if (loadedModuleTracePath.empty()) |
| 856 | + return false; |
| 857 | + llvm::SmallString<128> tracePath {loadedModuleTracePath}; |
| 858 | + llvm::sys::path::remove_filename(tracePath); |
| 859 | + llvm::sys::path::append(tracePath, "SWIFT_OBJC_MESSAGE_TRACE"); |
| 860 | + if (!llvm::sys::fs::exists(tracePath)) { |
| 861 | + if (llvm::sys::fs::create_directory(tracePath)) |
| 862 | + return false; |
| 863 | + } |
| 864 | + llvm::sys::path::append(tracePath, "%%%%-%%%%-%%%%.json"); |
| 865 | + int tmpFD; |
| 866 | + if (llvm::sys::fs::createUniqueFile(tracePath.str(), tmpFD, tracePath)) { |
| 867 | + return false; |
| 868 | + } |
| 869 | + // Write the contents of the buffer. |
| 870 | + llvm::raw_fd_ostream out(tmpFD, /*shouldClose=*/true); |
| 871 | + ObjcMethodRefereceCollector collector; |
| 872 | + for (auto *FU : mainModule->getFiles()) { |
| 873 | + if (auto *SF = dyn_cast<SourceFile>(FU)) { |
| 874 | + collector.walk(*SF); |
| 875 | + } |
| 876 | + } |
| 877 | + collector.dump(out); |
| 878 | + return true; |
| 879 | + }); |
| 880 | + return false; |
| 881 | +} |
0 commit comments