1 //===-- ObjCLanguage.h ------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H
10 #define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H
11 
12 #include <cstring>
13 #include <vector>
14 
15 #include "Plugins/Language/ClangCommon/ClangHighlighter.h"
16 #include "lldb/Target/Language.h"
17 #include "lldb/Utility/ConstString.h"
18 #include "lldb/lldb-private.h"
19 
20 namespace lldb_private {
21 
22 class ObjCLanguage : public Language {
23   ClangHighlighter m_highlighter;
24 
25 public:
26   class MethodName {
27   public:
28     /// The static factory method for creating a MethodName.
29     ///
30     /// \param[in] name
31     ///   The name of the method.
32     ///
33     /// \param[in] strict
34     ///   Control whether or not the name parser is strict about +/- in the
35     ///   front of the name.
36     ///
37     /// \return If the name failed to parse as a valid Objective-C method name,
38     /// returns std::nullopt. Otherwise returns a const MethodName.
39     static std::optional<const MethodName> Create(llvm::StringRef name,
40                                                   bool strict);
41 
42     /// Determines if this method is a class method
43     ///
44     /// \return Returns true if the method is a class method. False otherwise.
IsClassMethod()45     bool IsClassMethod() const { return m_type == eTypeClassMethod; }
46 
47     /// Determines if this method is an instance method
48     ///
49     /// \return Returns true if the method is an instance method. False
50     /// otherwise.
IsInstanceMethod()51     bool IsInstanceMethod() const { return m_type == eTypeInstanceMethod; }
52 
53     /// Returns the full name of the method.
54     ///
55     /// This includes the class name, the category name (if applicable), and the
56     /// selector name.
57     ///
58     /// \return The name of the method in the form of a const std::string
59     /// reference.
GetFullName()60     const std::string &GetFullName() const { return m_full; }
61 
62     /// Creates a variation of this method without the category.
63     /// If this method has no category, it returns an empty string.
64     ///
65     /// Example:
66     ///   Full name: "+[NSString(my_additions) myStringWithCString:]"
67     ///   becomes "+[NSString myStringWithCString:]"
68     ///
69     /// \return The method name without the category or an empty string if there
70     /// was no category to begin with.
71     std::string GetFullNameWithoutCategory() const;
72 
73     /// Returns a reference to the class name.
74     ///
75     /// Example:
76     ///   Full name: "+[NSString(my_additions) myStringWithCString:]"
77     ///   will give you "NSString"
78     ///
79     /// \return A StringRef to the class name of this method.
80     llvm::StringRef GetClassName() const;
81 
82     /// Returns a reference to the class name with the category.
83     ///
84     /// Example:
85     ///   Full name: "+[NSString(my_additions) myStringWithCString:]"
86     ///   will give you "NSString(my_additions)"
87     ///
88     /// Note: If your method has no category, this will give the same output as
89     /// `GetClassName`.
90     ///
91     /// \return A StringRef to the class name (including the category) of this
92     /// method. If there was no category, returns the same as `GetClassName`.
93     llvm::StringRef GetClassNameWithCategory() const;
94 
95     /// Returns a reference to the category name.
96     ///
97     /// Example:
98     ///   Full name: "+[NSString(my_additions) myStringWithCString:]"
99     ///   will give you "my_additions"
100     /// \return A StringRef to the category name of this method. If no category
101     /// is present, the StringRef is empty.
102     llvm::StringRef GetCategory() const;
103 
104     /// Returns a reference to the selector name.
105     ///
106     /// Example:
107     ///   Full name: "+[NSString(my_additions) myStringWithCString:]"
108     ///   will give you "myStringWithCString:"
109     /// \return A StringRef to the selector of this method.
110     llvm::StringRef GetSelector() const;
111 
112   protected:
113     enum Type { eTypeUnspecified, eTypeClassMethod, eTypeInstanceMethod };
114 
MethodName(llvm::StringRef name,Type type)115     MethodName(llvm::StringRef name, Type type)
116         : m_full(name.str()), m_type(type) {}
117 
118     const std::string m_full;
119     Type m_type;
120   };
121 
122   ObjCLanguage() = default;
123 
124   ~ObjCLanguage() override = default;
125 
GetLanguageType()126   lldb::LanguageType GetLanguageType() const override {
127     return lldb::eLanguageTypeObjC;
128   }
129 
GetUserEntryPointName()130   llvm::StringRef GetUserEntryPointName() const override { return "main"; }
131 
132   // Get all possible names for a method. Examples:
133   // If method_name is "+[NSString(my_additions) myStringWithCString:]"
134   //   variant_names[0] => "+[NSString myStringWithCString:]"
135   // If name is specified without the leading '+' or '-' like
136   // "[NSString(my_additions) myStringWithCString:]"
137   //  variant_names[0] => "+[NSString(my_additions) myStringWithCString:]"
138   //  variant_names[1] => "-[NSString(my_additions) myStringWithCString:]"
139   //  variant_names[2] => "+[NSString myStringWithCString:]"
140   //  variant_names[3] => "-[NSString myStringWithCString:]"
141   // Also returns the FunctionNameType of each possible name.
142   std::vector<Language::MethodNameVariant>
143   GetMethodNameVariants(ConstString method_name) const override;
144 
145   bool SymbolNameFitsToLanguage(Mangled mangled) const override;
146 
147   lldb::TypeCategoryImplSP GetFormatters() override;
148 
149   std::vector<FormattersMatchCandidate>
150   GetPossibleFormattersMatches(ValueObject &valobj,
151                                lldb::DynamicValueType use_dynamic) override;
152 
153   std::unique_ptr<TypeScavenger> GetTypeScavenger() override;
154 
155   std::pair<llvm::StringRef, llvm::StringRef>
156   GetFormatterPrefixSuffix(llvm::StringRef type_hint) override;
157 
158   bool IsNilReference(ValueObject &valobj) override;
159 
GetNilReferenceSummaryString()160   llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; }
161 
162   bool IsSourceFile(llvm::StringRef file_path) const override;
163 
GetHighlighter()164   const Highlighter *GetHighlighter() const override { return &m_highlighter; }
165 
166   // Static Functions
167   static void Initialize();
168 
169   static void Terminate();
170 
171   static lldb_private::Language *CreateInstance(lldb::LanguageType language);
172 
GetPluginNameStatic()173   static llvm::StringRef GetPluginNameStatic() { return "objc"; }
174 
IsPossibleObjCMethodName(const char * name)175   static bool IsPossibleObjCMethodName(const char *name) {
176     if (!name)
177       return false;
178     bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
179     bool ends_right = (name[strlen(name) - 1] == ']');
180     return (starts_right && ends_right);
181   }
182 
IsPossibleObjCSelector(const char * name)183   static bool IsPossibleObjCSelector(const char *name) {
184     if (!name)
185       return false;
186 
187     if (strchr(name, ':') == nullptr)
188       return true;
189     else if (name[strlen(name) - 1] == ':')
190       return true;
191     else
192       return false;
193   }
194 
GetInstanceVariableName()195   llvm::StringRef GetInstanceVariableName() override { return "self"; }
196 
197   // PluginInterface protocol
GetPluginName()198   llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
199 };
200 
201 } // namespace lldb_private
202 
203 #endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H
204