llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Daniel Grumberg (daniel-grumberg) <details> <summary>Changes</summary> Ensure that block types get represented correctly in declaration fragments, as block parameter names are important for documentation clients we need a separate system from getFragmentsForType in order to have access to full ParmVarDecls for the parameters. rdar://118257401 --- Patch is 36.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/73369.diff 7 Files Affected: - (modified) clang/include/clang/ExtractAPI/DeclarationFragments.h (+6) - (modified) clang/lib/ExtractAPI/DeclarationFragments.cpp (+148-28) - (added) clang/test/ExtractAPI/objc_block.m (+965) - (modified) clang/test/ExtractAPI/objc_category.m (+4) - (modified) clang/test/ExtractAPI/objc_id_protocol.m (+8) - (modified) clang/test/ExtractAPI/objc_interface.m (+4) - (modified) clang/test/ExtractAPI/objc_property.m (+24) ``````````diff diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h index 316d83df13e9359..d719196b9a43ecb 100644 --- a/clang/include/clang/ExtractAPI/DeclarationFragments.h +++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h @@ -24,6 +24,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/Specifiers.h" #include "clang/Lex/MacroInfo.h" #include "llvm/ADT/SmallVector.h" @@ -410,6 +411,11 @@ class DeclarationFragmentsBuilder { /// Build DeclarationFragments for a parameter variable declaration /// ParmVarDecl. static DeclarationFragments getFragmentsForParam(const ParmVarDecl *); + + static DeclarationFragments + getFragmentsForBlock(const NamedDecl *BlockDecl, FunctionTypeLoc &Block, + FunctionProtoTypeLoc &BlockProto, + DeclarationFragments &After); }; template <typename FunctionT> diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index 02fa6cd6119ecac..eb6eea0aaf54655 100644 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -15,6 +15,8 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/QualTypeNames.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/OperatorKinds.h" #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" @@ -24,6 +26,40 @@ using namespace clang::extractapi; using namespace llvm; +namespace { + +void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo, + clang::FunctionTypeLoc &Block, + clang::FunctionProtoTypeLoc &BlockProto) { + if (!TSInfo) + return; + + clang::TypeLoc TL = TSInfo->getTypeLoc().getUnqualifiedLoc(); + while (true) { + // Look through qualified types + if (auto QualifiedTL = TL.getAs<clang::QualifiedTypeLoc>()) { + TL = QualifiedTL.getUnqualifiedLoc(); + continue; + } + + if (auto AttrTL = TL.getAs<clang::AttributedTypeLoc>()) { + TL = AttrTL.getModifiedLoc(); + continue; + } + + // Try to get the function prototype behind the block pointer type, + // then we're done. + if (auto BlockPtr = TL.getAs<clang::BlockPointerTypeLoc>()) { + TL = BlockPtr.getPointeeLoc().IgnoreParens(); + Block = TL.getAs<clang::FunctionTypeLoc>(); + BlockProto = TL.getAs<clang::FunctionProtoTypeLoc>(); + } + break; + } +} + +} // namespace + DeclarationFragments &DeclarationFragments::appendSpace() { if (!Fragments.empty()) { Fragment &Last = Fragments.back(); @@ -218,7 +254,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( // Declaration fragments of a pointer type is the declaration fragments of // the pointee type followed by a `*`, - if (T->isPointerType()) + if (T->isPointerType() && !T->isFunctionPointerType()) return Fragments .append(getFragmentsForType(T->getPointeeType(), Context, After)) .append(" *", DeclarationFragments::FragmentKind::Text); @@ -449,10 +485,6 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { .append(VarDecl::getStorageClassSpecifierString(SC), DeclarationFragments::FragmentKind::Keyword) .appendSpace(); - QualType T = - Var->getTypeSourceInfo() - ? Var->getTypeSourceInfo()->getType() - : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType()); // Capture potential fragments that needs to be placed after the variable name // ``` @@ -460,8 +492,23 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { // char (*ptr_to_array)[6]; // ``` DeclarationFragments After; - return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After)) - .appendSpace() + FunctionTypeLoc BlockLoc; + FunctionProtoTypeLoc BlockProtoLoc; + findTypeLocForBlockDecl(Var->getTypeSourceInfo(), BlockLoc, BlockProtoLoc); + + if (!BlockLoc) { + QualType T = Var->getTypeSourceInfo() + ? Var->getTypeSourceInfo()->getType() + : Var->getASTContext().getUnqualifiedObjCPointerType( + Var->getType()); + + Fragments.append(getFragmentsForType(T, Var->getASTContext(), After)) + .appendSpace(); + } else { + Fragments.append(getFragmentsForBlock(Var, BlockLoc, BlockProtoLoc, After)); + } + + return Fragments .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) .append(";", DeclarationFragments::FragmentKind::Text); @@ -504,13 +551,23 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { DeclarationFragments Fragments, After; - QualType T = Param->getTypeSourceInfo() - ? Param->getTypeSourceInfo()->getType() - : Param->getASTContext().getUnqualifiedObjCPointerType( - Param->getType()); + auto *TSInfo = Param->getTypeSourceInfo(); + + QualType T = TSInfo ? TSInfo->getType() + : Param->getASTContext().getUnqualifiedObjCPointerType( + Param->getType()); + + FunctionTypeLoc BlockLoc; + FunctionProtoTypeLoc BlockProtoLoc; + findTypeLocForBlockDecl(TSInfo, BlockLoc, BlockProtoLoc); + + DeclarationFragments TypeFragments; + if (BlockLoc) + TypeFragments.append( + getFragmentsForBlock(Param, BlockLoc, BlockProtoLoc, After)); + else + TypeFragments.append(getFragmentsForType(T, Param->getASTContext(), After)); - DeclarationFragments TypeFragments = - getFragmentsForType(T, Param->getASTContext(), After); if (TypeFragments.begin()->Spelling.substr(0, 14).compare("type-parameter") == 0) { std::string ProperArgName = getNameForTemplateArgument( @@ -522,17 +579,60 @@ DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { TypeFragments.begin()->Spelling.swap(ProperArgName); } - if (Param->isObjCMethodParameter()) + if (Param->isObjCMethodParameter()) { Fragments.append("(", DeclarationFragments::FragmentKind::Text) .append(std::move(TypeFragments)) - .append(") ", DeclarationFragments::FragmentKind::Text); - else - Fragments.append(std::move(TypeFragments)).appendSpace(); + .append(std::move(After)) + .append(") ", DeclarationFragments::FragmentKind::Text) + .append(Param->getName(), + DeclarationFragments::FragmentKind::InternalParam); + } else { + Fragments.append(std::move(TypeFragments)); + if (!T->isBlockPointerType()) + Fragments.appendSpace(); + Fragments + .append(Param->getName(), + DeclarationFragments::FragmentKind::InternalParam) + .append(std::move(After)); + } + return Fragments; +} - return Fragments - .append(Param->getName(), - DeclarationFragments::FragmentKind::InternalParam) - .append(std::move(After)); +DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock( + const NamedDecl *BlockDecl, FunctionTypeLoc &Block, + FunctionProtoTypeLoc &BlockProto, DeclarationFragments &After) { + DeclarationFragments Fragments; + + DeclarationFragments RetTyAfter; + auto ReturnValueFragment = getFragmentsForType( + Block.getTypePtr()->getReturnType(), BlockDecl->getASTContext(), After); + + Fragments.append(std::move(ReturnValueFragment)) + .append(std::move(RetTyAfter)) + .appendSpace() + .append("(^", DeclarationFragments::FragmentKind::Text); + + After.append(")", DeclarationFragments::FragmentKind::Text); + unsigned NumParams = Block.getNumParams(); + + if (!BlockProto || NumParams == 0) { + if (BlockProto && BlockProto.getTypePtr()->isVariadic()) + After.append("(...)", DeclarationFragments::FragmentKind::Text); + else + After.append("()", DeclarationFragments::FragmentKind::Text); + } else { + After.append("(", DeclarationFragments::FragmentKind::Text); + for (unsigned I = 0; I != NumParams; ++I) { + if (I) + After.append(", ", DeclarationFragments::FragmentKind::Text); + After.append(getFragmentsForParam(Block.getParam(I))); + if (I == NumParams - 1 && BlockProto.getTypePtr()->isVariadic()) + After.append(", ...", DeclarationFragments::FragmentKind::Text); + } + After.append(")", DeclarationFragments::FragmentKind::Text); + } + + return Fragments; } DeclarationFragments @@ -595,11 +695,18 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { Fragments.append(std::move(After)); Fragments.append("(", DeclarationFragments::FragmentKind::Text); - for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) { + unsigned NumParams = Func->getNumParams(); + for (unsigned i = 0; i != NumParams; ++i) { if (i) Fragments.append(", ", DeclarationFragments::FragmentKind::Text); Fragments.append(getFragmentsForParam(Func->getParamDecl(i))); } + + if (Func->isVariadic()) { + if (NumParams > 0) + Fragments.append(", ", DeclarationFragments::FragmentKind::Text); + Fragments.append("...", DeclarationFragments::FragmentKind::Text); + } Fragments.append(")", DeclarationFragments::FragmentKind::Text); Fragments.append(DeclarationFragments::getExceptionSpecificationString( @@ -1248,14 +1355,27 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( 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)) - .appendSpace() + Fragments.appendSpace(); + + FunctionTypeLoc BlockLoc; + FunctionProtoTypeLoc BlockProtoLoc; + findTypeLocForBlockDecl(Property->getTypeSourceInfo(), BlockLoc, + BlockProtoLoc); + + auto PropType = Property->getType(); + if (!BlockLoc) + Fragments + .append(getFragmentsForType(PropType, Property->getASTContext(), After)) + .appendSpace(); + else + Fragments.append( + getFragmentsForBlock(Property, BlockLoc, BlockProtoLoc, After)); + + return Fragments .append(Property->getName(), DeclarationFragments::FragmentKind::Identifier) - .append(std::move(After)); + .append(std::move(After)) + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol( diff --git a/clang/test/ExtractAPI/objc_block.m b/clang/test/ExtractAPI/objc_block.m new file mode 100644 index 000000000000000..a7a4f5696333c18 --- /dev/null +++ b/clang/test/ExtractAPI/objc_block.m @@ -0,0 +1,965 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang_cc1 -extract-api -fblocks -triple arm64-apple-macosx \ +// RUN: -x objective-c-header %t/input.h -o %t/output.json -verify + +// Generator version is not consistent across test runs, normalize it. +// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \ +// RUN: %t/output.json >> %t/output-normalized.json +// RUN: diff %t/reference.output.json %t/output-normalized.json + +//--- input.h +@interface Foo +-(void)methodBlockNoParam:(void (^)())block; +-(void)methodBlockWithParam:(int (^)(int foo))block; +-(void)methodBlockWithMultipleParam:(int (^)(int foo, unsigned baz))block; +-(void)methodBlockVariadic:(int (^)(int foo, ...))block; +@end + +void func(int (^arg)(int foo)); + +int (^global)(int foo); + +///expected-no-diagnostics + +//--- reference.output.json.in +{ + "metadata": { + "formatVersion": { + "major": 0, + "minor": 5, + "patch": 3 + }, + "generator": "?" + }, + "module": { + "name": "", + "platform": { + "architecture": "arm64", + "operatingSystem": { + "minimumVersion": { + "major": 11, + "minor": 0, + "patch": 0 + }, + "name": "macosx" + }, + "vendor": "apple" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:objc(cs)Foo(im)methodBlockNoParam:", + "target": "c:objc(cs)Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Foo(im)methodBlockWithParam:", + "target": "c:objc(cs)Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Foo(im)methodBlockWithMultipleParam:", + "target": "c:objc(cs)Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Foo(im)methodBlockVariadic:", + "target": "c:objc(cs)Foo", + "targetFallback": "Foo" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "identifier", + "spelling": "global" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ");" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:@global" + }, + "kind": { + "displayName": "Global Variable", + "identifier": "objective-c.var" + }, + "location": { + "position": { + "character": 6, + "line": 9 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "global" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "global" + } + ], + "title": "global" + }, + "pathComponents": [ + "global" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "func" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "internalParam", + "spelling": "arg" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": "));" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "internalParam", + "spelling": "arg" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ")" + } + ], + "name": "arg" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:@F@func" + }, + "kind": { + "displayName": "Function", + "identifier": "objective-c.func" + }, + "location": { + "position": { + "character": 5, + "line": 7 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "func" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "func" + } + ], + "title": "func" + }, + "pathComponents": [ + "func" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Foo" + }, + "kind": { + "displayName": "Class", + "identifier": "objective-c.class" + }, + "location": { + "position": { + "character": 11, + "line": 0 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "title": "Foo" + }, + "pathComponents": [ + "Foo" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "methodBlockNoParam:" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")()) " + }, + { + "kind": "internalParam", + "spelling": "block" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/73369 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits