return "";
}
+static llvm::StringRef
+getNameOrErrForObjCInterface(const ObjCInterfaceDecl *ID) {
+ return ID ? ID->getName() : "<<error-type>>";
+}
+
+std::string printObjCMethod(const ObjCMethodDecl &Method) {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+
+ OS << (Method.isInstanceMethod() ? '-' : '+') << '[';
+
+ // Should always be true.
+ if (const ObjCContainerDecl *C =
+ dyn_cast<ObjCContainerDecl>(Method.getDeclContext()))
+ OS << printObjCContainer(*C);
+
+ Method.getSelector().print(OS << ' ');
+ if (Method.isVariadic())
+ OS << ", ...";
+
+ OS << ']';
+ OS.flush();
+ return Name;
+}
+
+std::string printObjCContainer(const ObjCContainerDecl &C) {
+ if (const ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(&C)) {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ const ObjCInterfaceDecl *Class = Category->getClassInterface();
+ OS << getNameOrErrForObjCInterface(Class) << '(' << Category->getName()
+ << ')';
+ OS.flush();
+ return Name;
+ }
+ if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(&C)) {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ const ObjCInterfaceDecl *Class = CID->getClassInterface();
+ OS << getNameOrErrForObjCInterface(Class) << '(' << CID->getName() << ')';
+ OS.flush();
+ return Name;
+ }
+ return C.getNameAsString();
+}
+
SymbolID getSymbolID(const Decl *D) {
llvm::SmallString<128> USR;
if (index::generateUSRForDecl(D, USR))
#include "index/SymbolID.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/MacroInfo.h"
/// string if decl is not a template specialization.
std::string printTemplateSpecializationArgs(const NamedDecl &ND);
+/// Print the Objective-C method name, including the full container name, e.g.
+/// `-[MyClass(Category) method:]`
+std::string printObjCMethod(const ObjCMethodDecl &Method);
+
+/// Print the Objective-C container name including categories, e.g. `MyClass`,
+// `MyClass()`, `MyClass(Category)`, and `MyProtocol`.
+std::string printObjCContainer(const ObjCContainerDecl &C);
+
/// Gets the symbol ID for a declaration. Returned SymbolID might be null.
SymbolID getSymbolID(const Decl *D);
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
std::string getLocalScope(const Decl *D) {
std::vector<std::string> Scopes;
const DeclContext *DC = D->getDeclContext();
+
+ // ObjC scopes won't have multiple components for us to join, instead:
+ // - Methods: "-[Class methodParam1:methodParam2]"
+ // - Classes, categories, and protocols: "MyClass(Category)"
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC))
+ return printObjCMethod(*MD);
+ else if (const ObjCContainerDecl *CD = dyn_cast<ObjCContainerDecl>(DC))
+ return printObjCContainer(*CD);
+
auto GetName = [](const TypeDecl *D) {
if (!D->getDeclName().isEmpty()) {
PrintingPolicy Policy = D->getASTContext().getPrintingPolicy();
std::string getNamespaceScope(const Decl *D) {
const DeclContext *DC = D->getDeclContext();
+ // ObjC does not have the concept of namespaces, so instead we support
+ // local scopes.
+ if (isa<ObjCMethodDecl, ObjCContainerDecl>(DC))
+ return "";
+
if (const TagDecl *TD = dyn_cast<TagDecl>(DC))
return getNamespaceScope(TD);
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
HI.Name = "data";
HI.Type = "char";
HI.Kind = index::SymbolKind::Field;
- HI.NamespaceScope = "ObjC::"; // FIXME: fix it
+ HI.LocalScope = "ObjC::";
+ HI.NamespaceScope = "";
HI.Definition = "char data";
}},
{
HI.Name = "this";
HI.Definition = "const Foo<int, F> *";
}},
+ {
+ R"cpp(
+ @interface MYObject
+ @end
+ @interface MYObject (Private)
+ @property(nonatomic, assign) int privateField;
+ @end
+
+ int someFunction() {
+ MYObject *obj = [MYObject sharedInstance];
+ return obj.[[private^Field]];
+ }
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "privateField";
+ HI.Kind = index::SymbolKind::InstanceProperty;
+ HI.LocalScope = "MYObject(Private)::";
+ HI.NamespaceScope = "";
+ HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
+ "readwrite) int privateField;";
+ }},
+ {
+ R"cpp(
+ @protocol MYProtocol
+ @property(nonatomic, assign) int prop1;
+ @end
+
+ int someFunction() {
+ id<MYProtocol> obj = 0;
+ return obj.[[pro^p1]];
+ }
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "prop1";
+ HI.Kind = index::SymbolKind::InstanceProperty;
+ HI.LocalScope = "MYProtocol::";
+ HI.NamespaceScope = "";
+ HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
+ "readwrite) int prop1;";
+ }},
+ {R"objc(
+ @interface Foo
+ @end
+
+ @implementation Foo(Private)
+ + (int)somePrivateMethod {
+ int [[res^ult]] = 2;
+ return result;
+ }
+ @end
+ )objc",
+ [](HoverInfo &HI) {
+ HI.Name = "result";
+ HI.Definition = "int result = 2";
+ HI.Kind = index::SymbolKind::Variable;
+ HI.Type = "int";
+ HI.LocalScope = "+[Foo(Private) somePrivateMethod]::";
+ HI.NamespaceScope = "";
+ HI.Value = "2";
+ }},
+ {R"objc(
+ @interface Foo
+ @end
+
+ @implementation Foo
+ - (int)variadicArgMethod:(id)first, ... {
+ int [[res^ult]] = 0;
+ return result;
+ }
+ @end
+ )objc",
+ [](HoverInfo &HI) {
+ HI.Name = "result";
+ HI.Definition = "int result = 0";
+ HI.Kind = index::SymbolKind::Variable;
+ HI.Type = "int";
+ HI.LocalScope = "-[Foo variadicArgMethod:, ...]::";
+ HI.NamespaceScope = "";
+ HI.Value = "0";
+ }},
};
// Create a tiny index, so tests above can verify documentation is fetched.