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.
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.
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.
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 
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 
126   lldb::LanguageType GetLanguageType() const override {
127     return lldb::eLanguageTypeObjC;
128   }
129 
130   // Get all possible names for a method. Examples:
131   // If method_name is "+[NSString(my_additions) myStringWithCString:]"
132   //   variant_names[0] => "+[NSString myStringWithCString:]"
133   // If name is specified without the leading '+' or '-' like
134   // "[NSString(my_additions) myStringWithCString:]"
135   //  variant_names[0] => "+[NSString(my_additions) myStringWithCString:]"
136   //  variant_names[1] => "-[NSString(my_additions) myStringWithCString:]"
137   //  variant_names[2] => "+[NSString myStringWithCString:]"
138   //  variant_names[3] => "-[NSString myStringWithCString:]"
139   // Also returns the FunctionNameType of each possible name.
140   std::vector<Language::MethodNameVariant>
141   GetMethodNameVariants(ConstString method_name) const override;
142 
143   bool SymbolNameFitsToLanguage(Mangled mangled) const override;
144 
145   lldb::TypeCategoryImplSP GetFormatters() override;
146 
147   std::vector<FormattersMatchCandidate>
148   GetPossibleFormattersMatches(ValueObject &valobj,
149                                lldb::DynamicValueType use_dynamic) override;
150 
151   std::unique_ptr<TypeScavenger> GetTypeScavenger() override;
152 
153   std::pair<llvm::StringRef, llvm::StringRef>
154   GetFormatterPrefixSuffix(llvm::StringRef type_hint) override;
155 
156   bool IsNilReference(ValueObject &valobj) override;
157 
158   llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; }
159 
160   bool IsSourceFile(llvm::StringRef file_path) const override;
161 
162   const Highlighter *GetHighlighter() const override { return &m_highlighter; }
163 
164   // Static Functions
165   static void Initialize();
166 
167   static void Terminate();
168 
169   static lldb_private::Language *CreateInstance(lldb::LanguageType language);
170 
171   static llvm::StringRef GetPluginNameStatic() { return "objc"; }
172 
173   static bool IsPossibleObjCMethodName(const char *name) {
174     if (!name)
175       return false;
176     bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
177     bool ends_right = (name[strlen(name) - 1] == ']');
178     return (starts_right && ends_right);
179   }
180 
181   static bool IsPossibleObjCSelector(const char *name) {
182     if (!name)
183       return false;
184 
185     if (strchr(name, ':') == nullptr)
186       return true;
187     else if (name[strlen(name) - 1] == ':')
188       return true;
189     else
190       return false;
191   }
192 
193   llvm::StringRef GetInstanceVariableName() override { return "self"; }
194 
195   // PluginInterface protocol
196   llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
197 };
198 
199 } // namespace lldb_private
200 
201 #endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H
202