Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions clang-tools-extra/clangd/unittests/InlayHintTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1577,19 +1577,21 @@ TEST(TypeHints, Aliased) {
}

TEST(TypeHints, CallingConvention) {
// Check that we don't crash for lambdas without a FunctionTypeLoc
// Check that we don't crash for lambdas with an annotation
// https://github.com/clangd/clangd/issues/2223
std::string Code = R"cpp(
Annotations Source(R"cpp(
void test() {
[]() __cdecl {};
[]($lambda[[)]]__cdecl {};
}
)cpp";
TestTU TU = TestTU::withCode(Code);
)cpp");
TestTU TU = TestTU::withCode(Source.code());
TU.ExtraArgs.push_back("--target=x86_64-w64-mingw32");
TU.PredefineMacros = true; // for the __cdecl
auto AST = TU.build();

EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type), IsEmpty());
EXPECT_THAT(
hintsOfKind(AST, InlayHintKind::Type),
ElementsAre(HintMatcher(ExpectedHint{"-> void", "lambda"}, Source)));
}

TEST(TypeHints, Decltype) {
Expand Down
21 changes: 19 additions & 2 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3910,8 +3910,25 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {

FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
const TypeSourceInfo *TSI = getTypeSourceInfo();
return TSI ? TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>()
: FunctionTypeLoc();

if (!TSI)
return FunctionTypeLoc();

TypeLoc TL = TSI->getTypeLoc();
FunctionTypeLoc FTL;

while (!(FTL = TL.getAs<FunctionTypeLoc>())) {
if (const auto PTL = TL.getAs<ParenTypeLoc>())
TL = PTL.getInnerLoc();
else if (const auto ATL = TL.getAs<AttributedTypeLoc>())
TL = ATL.getEquivalentTypeLoc();
else if (const auto MQTL = TL.getAs<MacroQualifiedTypeLoc>())
TL = MQTL.getInnerLoc();
else
break;
}

return FTL;
}

SourceRange FunctionDecl::getReturnTypeSourceRange() const {
Expand Down
69 changes: 69 additions & 0 deletions clang/unittests/AST/AttrTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ TEST(Attr, AnnotateType) {
struct S { int mem; };
int [[clang::annotate_type("int")]]
S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;

// Function Type Attributes
__attribute__((noreturn)) int f_noreturn();

#define NO_RETURN __attribute__((noreturn))
NO_RETURN int f_macro_attribue();

int (__attribute__((noreturn)) f_paren_attribute)();

int (
NO_RETURN
(
__attribute__((warn_unused_result))
(f_w_paren_and_attr)
)
) ();
)cpp");

{
Expand Down Expand Up @@ -153,6 +169,59 @@ TEST(Attr, AnnotateType) {
EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
}

{
const FunctionDecl *Func = getFunctionNode(AST.get(), "f_noreturn");
const FunctionTypeLoc FTL = Func->getFunctionTypeLoc();
const FunctionType *FT = FTL.getTypePtr();

EXPECT_TRUE(FT->getNoReturnAttr());
}

{
for (auto should_have_func_type_loc : {
"f_macro_attribue",
"f_paren_attribute",
"f_w_paren_and_attr",
}) {
llvm::errs() << "O: " << should_have_func_type_loc << "\n";
const FunctionDecl *Func =
getFunctionNode(AST.get(), should_have_func_type_loc);

EXPECT_TRUE(Func->getFunctionTypeLoc());
}
}

// The following test verifies getFunctionTypeLoc returns a type
// which takes into account the attribute (instead of only the nake
// type).
//
// This is hard to do with C/C++ because it seems using a function
// type attribute with a C/C++ function declaration only results
// with either:
//
// 1. It does NOT produce any AttributedType (for example it only
// sets one flag of the FunctionType's ExtInfo, e.g. NoReturn).
// 2. It produces an AttributedType with modified type and
// equivalent type that are equal (for example, that's what
// happens with Calling Convention attributes).
//
// Fortunately, ObjC has one specific function type attribute that
// creates an AttributedType with different modified type and
// equivalent type.
auto AST_ObjC = buildASTFromCodeWithArgs(
R"objc(
__attribute__((ns_returns_retained)) id f();
)objc",
{"-fobjc-arc", "-fsyntax-only", "-fobjc-runtime=macosx-10.7"},
"input.mm");
{
const FunctionDecl *f = getFunctionNode(AST_ObjC.get(), "f");
const FunctionTypeLoc FTL = f->getFunctionTypeLoc();

const FunctionType *FT = FTL.getTypePtr();
EXPECT_TRUE(FT->getExtInfo().getProducesResult());
}

// Test type annotation on an `__auto_type` type in C mode.
AST = buildASTFromCodeWithArgs(R"c(
__auto_type [[clang::annotate_type("auto")]] auto_var = 1;
Expand Down
Loading