aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/ExtractAPI/DeclarationFragments.cpp
diff options
context:
space:
mode:
authorZixu Wang <zixu_wang@apple.com>2022-03-24 18:19:30 -0700
committerZixu Wang <zixu_wang@apple.com>2022-03-29 14:29:39 -0700
commit9b36e126fdb1da4d7e255e089ef225dfb130ef63 (patch)
tree1b7b71ed8d09993adad441b97bb918d16bbb75b0 /clang/lib/ExtractAPI/DeclarationFragments.cpp
parent686dcbe8b018759b5443c05bfeeb7abf4d9cf09c (diff)
downloadllvm-9b36e126fdb1da4d7e255e089ef225dfb130ef63.zip
llvm-9b36e126fdb1da4d7e255e089ef225dfb130ef63.tar.gz
llvm-9b36e126fdb1da4d7e255e089ef225dfb130ef63.tar.bz2
[clang][extract-api] Add Objective-C interface support
Add support for Objective-C interface declarations in ExtractAPI. Depends on D122495 Differential Revision: https://reviews.llvm.org/D122446
Diffstat (limited to 'clang/lib/ExtractAPI/DeclarationFragments.cpp')
-rw-r--r--clang/lib/ExtractAPI/DeclarationFragments.cpp210
1 files changed, 198 insertions, 12 deletions
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 1980e8e..b35388e 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -245,6 +245,22 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
// unqualified base type.
QualType Base = T->getCanonicalTypeUnqualified();
+ // Render Objective-C `id`/`instancetype` as keywords.
+ if (T->isObjCIdType())
+ return Fragments.append(Base.getAsString(),
+ DeclarationFragments::FragmentKind::Keyword);
+
+ // If the base type is an ObjCInterfaceType, use the underlying
+ // ObjCInterfaceDecl for the true USR.
+ if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(Base)) {
+ const auto *Decl = ObjCIT->getDecl();
+ SmallString<128> USR;
+ index::generateUSRForDecl(Decl, USR);
+ return Fragments.append(Decl->getName(),
+ DeclarationFragments::FragmentKind::TypeIdentifier,
+ USR);
+ }
+
// Default fragment builder for other kinds of types (BuiltinType etc.)
SmallString<128> USR;
clang::index::generateUSRForType(Base, Context, USR);
@@ -454,27 +470,183 @@ DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) {
return Fragments;
}
-FunctionSignature
-DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *Func) {
- FunctionSignature Signature;
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface(
+ const ObjCInterfaceDecl *Interface) {
+ DeclarationFragments Fragments;
+ // Build the base of the Objective-C interface declaration.
+ Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append(Interface->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+
+ // Build the inheritance part of the declaration.
+ if (const ObjCInterfaceDecl *SuperClass = Interface->getSuperClass()) {
+ SmallString<128> SuperUSR;
+ index::generateUSRForDecl(SuperClass, SuperUSR);
+ Fragments.append(" : ", DeclarationFragments::FragmentKind::Text)
+ .append(SuperClass->getName(),
+ DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR);
+ }
- for (const auto *Param : Func->parameters()) {
- StringRef Name = Param->getName();
- DeclarationFragments Fragments = getFragmentsForParam(Param);
+ return Fragments;
+}
- Signature.addParameter(Name, Fragments);
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod(
+ const ObjCMethodDecl *Method) {
+ DeclarationFragments Fragments, After;
+ // Build the instance/class method indicator.
+ if (Method->isClassMethod())
+ Fragments.append("+ ", DeclarationFragments::FragmentKind::Text);
+ else if (Method->isInstanceMethod())
+ Fragments.append("- ", DeclarationFragments::FragmentKind::Text);
+
+ // Build the return type.
+ Fragments.append("(", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForType(Method->getReturnType(),
+ Method->getASTContext(), After))
+ .append(std::move(After))
+ .append(")", DeclarationFragments::FragmentKind::Text);
+
+ // Build the selector part.
+ Selector Selector = Method->getSelector();
+ if (Selector.getNumArgs() == 0)
+ // For Objective-C methods that don't take arguments, the first (and only)
+ // slot of the selector is the method name.
+ Fragments.appendSpace().append(
+ Selector.getNameForSlot(0),
+ DeclarationFragments::FragmentKind::Identifier);
+
+ // For Objective-C methods that take arguments, build the selector slots.
+ for (unsigned i = 0, end = Method->param_size(); i != end; ++i) {
+ Fragments.appendSpace()
+ .append(Selector.getNameForSlot(i),
+ // The first slot is the name of the method, record as an
+ // identifier, otherwise as exteranl parameters.
+ i == 0 ? DeclarationFragments::FragmentKind::Identifier
+ : DeclarationFragments::FragmentKind::ExternalParam)
+ .append(":", DeclarationFragments::FragmentKind::Text);
+
+ // Build the internal parameter.
+ const ParmVarDecl *Param = Method->getParamDecl(i);
+ Fragments.append(getFragmentsForParam(Param));
}
- DeclarationFragments After;
- DeclarationFragments Returns =
- getFragmentsForType(Func->getReturnType(), Func->getASTContext(), After)
- .append(std::move(After));
+ return Fragments;
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
+ const ObjCPropertyDecl *Property) {
+ DeclarationFragments Fragments, After;
+
+ // Build the Objective-C property keyword.
+ Fragments.append("@property", DeclarationFragments::FragmentKind::Keyword);
+
+ const auto Attributes = Property->getPropertyAttributes();
+ // Build the attributes if there is any associated with the property.
+ if (Attributes != ObjCPropertyAttribute::kind_noattr) {
+ // No leading comma for the first attribute.
+ bool First = true;
+ Fragments.append(" (", DeclarationFragments::FragmentKind::Text);
+ // Helper function to render the attribute.
+ auto RenderAttribute =
+ [&](ObjCPropertyAttribute::Kind Kind, StringRef Spelling,
+ StringRef Arg = "",
+ DeclarationFragments::FragmentKind ArgKind =
+ DeclarationFragments::FragmentKind::Identifier) {
+ // Check if the `Kind` attribute is set for this property.
+ if ((Attributes & Kind) && !Spelling.empty()) {
+ // Add a leading comma if this is not the first attribute rendered.
+ if (!First)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ // Render the spelling of this attribute `Kind` as a keyword.
+ Fragments.append(Spelling,
+ DeclarationFragments::FragmentKind::Keyword);
+ // If this attribute takes in arguments (e.g. `getter=getterName`),
+ // render the arguments.
+ if (!Arg.empty())
+ Fragments.append("=", DeclarationFragments::FragmentKind::Text)
+ .append(Arg, ArgKind);
+ First = false;
+ }
+ };
+
+ // Go through all possible Objective-C property attributes and render set
+ // ones.
+ RenderAttribute(ObjCPropertyAttribute::kind_class, "class");
+ RenderAttribute(ObjCPropertyAttribute::kind_direct, "direct");
+ RenderAttribute(ObjCPropertyAttribute::kind_nonatomic, "nonatomic");
+ RenderAttribute(ObjCPropertyAttribute::kind_atomic, "atomic");
+ RenderAttribute(ObjCPropertyAttribute::kind_assign, "assign");
+ RenderAttribute(ObjCPropertyAttribute::kind_retain, "retain");
+ RenderAttribute(ObjCPropertyAttribute::kind_strong, "strong");
+ RenderAttribute(ObjCPropertyAttribute::kind_copy, "copy");
+ RenderAttribute(ObjCPropertyAttribute::kind_weak, "weak");
+ RenderAttribute(ObjCPropertyAttribute::kind_unsafe_unretained,
+ "unsafe_unretained");
+ RenderAttribute(ObjCPropertyAttribute::kind_readwrite, "readwrite");
+ RenderAttribute(ObjCPropertyAttribute::kind_readonly, "readonly");
+ RenderAttribute(ObjCPropertyAttribute::kind_getter, "getter",
+ Property->getGetterName().getAsString());
+ RenderAttribute(ObjCPropertyAttribute::kind_setter, "setter",
+ Property->getSetterName().getAsString());
+
+ // Render nullability attributes.
+ if (Attributes & ObjCPropertyAttribute::kind_nullability) {
+ QualType Type = Property->getType();
+ if (const auto Nullability =
+ AttributedType::stripOuterNullability(Type)) {
+ if (!First)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ if (*Nullability == NullabilityKind::Unspecified &&
+ (Attributes & ObjCPropertyAttribute::kind_null_resettable))
+ Fragments.append("null_resettable",
+ DeclarationFragments::FragmentKind::Keyword);
+ else
+ Fragments.append(
+ getNullabilitySpelling(*Nullability, /*isContextSensitive=*/true),
+ DeclarationFragments::FragmentKind::Keyword);
+ First = false;
+ }
+ }
+
+ Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+ }
+
+ // Build the property type and name, and return the completed fragments.
+ return Fragments.appendSpace()
+ .append(getFragmentsForType(Property->getType(),
+ Property->getASTContext(), After))
+ .append(Property->getName(),
+ DeclarationFragments::FragmentKind::Identifier)
+ .append(std::move(After));
+}
- Signature.setReturnType(Returns);
+template <typename FunctionT>
+FunctionSignature
+DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) {
+ FunctionSignature Signature;
+
+ DeclarationFragments ReturnType, After;
+ ReturnType
+ .append(getFragmentsForType(Function->getReturnType(),
+ Function->getASTContext(), After))
+ .append(std::move(After));
+ Signature.setReturnType(ReturnType);
+
+ for (const auto *Param : Function->parameters())
+ Signature.addParameter(Param->getName(), getFragmentsForParam(Param));
return Signature;
}
+// Instantiate template for FunctionDecl.
+template FunctionSignature
+DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *);
+
+// Instantiate template for ObjCMethodDecl.
+template FunctionSignature
+DeclarationFragmentsBuilder::getFunctionSignature(const ObjCMethodDecl *);
+
// Subheading of a symbol defaults to its name.
DeclarationFragments
DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) {
@@ -484,3 +656,17 @@ DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) {
DeclarationFragments::FragmentKind::Identifier);
return Fragments;
}
+
+// Subheading of an Objective-C method is a `+` or `-` sign indicating whether
+// it's a class method or an instance method, followed by the selector name.
+DeclarationFragments
+DeclarationFragmentsBuilder::getSubHeading(const ObjCMethodDecl *Method) {
+ DeclarationFragments Fragments;
+ if (Method->isClassMethod())
+ Fragments.append("+ ", DeclarationFragments::FragmentKind::Text);
+ else if (Method->isInstanceMethod())
+ Fragments.append("- ", DeclarationFragments::FragmentKind::Text);
+
+ return Fragments.append(Method->getNameAsString(),
+ DeclarationFragments::FragmentKind::Identifier);
+}