From f5b107940ab1d302ac4ad48a92d8d95bb7af9676 Mon Sep 17 00:00:00 2001 From: Alp Toker Date: Wed, 2 Jul 2014 12:55:58 +0000 Subject: [PATCH] Make FunctionDecl::getReturnTypeSourceRange() support non-builtin types Also document that the function is a "best-effort" facility to extract source ranges from limited AST type location info. llvm-svn: 212174 --- clang/include/clang/AST/Decl.h | 3 +++ clang/lib/AST/Decl.cpp | 19 +++++++++++-------- clang/lib/Sema/SemaDeclAttr.cpp | 13 ++++--------- clang/test/Sema/warn-main-return-type.c | 10 ++++++---- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 0f04c08742f9..978c3c85cef4 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1896,6 +1896,9 @@ public: return getType()->getAs()->getReturnType(); } + /// \brief Attempt to compute an informative source range covering the + /// function return type. This may omit qualifiers and other information with + /// limited representation in the AST. SourceRange getReturnTypeSourceRange() const; /// \brief Determine the type of an expression that calls this function. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 702a2e32e3ea..fdf94a8ad5e8 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2691,17 +2691,20 @@ SourceRange FunctionDecl::getReturnTypeSourceRange() const { const TypeSourceInfo *TSI = getTypeSourceInfo(); if (!TSI) return SourceRange(); - - TypeLoc TL = TSI->getTypeLoc(); - FunctionTypeLoc FunctionTL = TL.getAs(); - if (!FunctionTL) + FunctionTypeLoc FTL = + TSI->getTypeLoc().IgnoreParens().getAs(); + if (!FTL) return SourceRange(); - TypeLoc ResultTL = FunctionTL.getReturnLoc(); - if (ResultTL.getUnqualifiedLoc().getAs()) - return ResultTL.getSourceRange(); + // Skip self-referential return types. + const SourceManager &SM = getASTContext().getSourceManager(); + SourceRange RTRange = FTL.getReturnLoc().getSourceRange(); + SourceLocation Boundary = getNameInfo().getLocStart(); + if (RTRange.isInvalid() || Boundary.isInvalid() || + !SM.isBeforeInTranslationUnit(RTRange.getEnd(), Boundary)) + return SourceRange(); - return SourceRange(); + return RTRange; } /// \brief For an inline function definition in C, or for a gnu_inline function diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index dcb6530552df..a1d1d0c4a584 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3029,16 +3029,11 @@ static void handleOptimizeNoneAttr(Sema &S, Decl *D, static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { FunctionDecl *FD = cast(D); if (!FD->getReturnType()->isVoidType()) { - TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens(); - if (FunctionTypeLoc FTL = TL.getAs()) { - S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) + SourceRange RTRange = FD->getReturnTypeSourceRange(); + S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) << FD->getType() - << FixItHint::CreateReplacement(FTL.getReturnLoc().getSourceRange(), - "void"); - } else { - S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) - << FD->getType(); - } + << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void") + : FixItHint()); return; } diff --git a/clang/test/Sema/warn-main-return-type.c b/clang/test/Sema/warn-main-return-type.c index c6f3a0c1011a..f8bcbc555fc5 100644 --- a/clang/test/Sema/warn-main-return-type.c +++ b/clang/test/Sema/warn-main-return-type.c @@ -22,8 +22,8 @@ double main() { return 0.0; } -// Currently we suggest to replace only 'float' here because we don't store -// enough source locations. +// TODO: Store qualifier source locations for return types so +// we can replace the full type with this fix-it. // // expected-error@+3 {{conflicting types for 'main}} // expected-warning@+2 {{return type of 'main' is not 'int'}} @@ -35,9 +35,11 @@ const float main() { typedef void *(*fptr)(int a); -// expected-error@+2 {{conflicting types for 'main}} -// expected-warning@+1 {{return type of 'main' is not 'int'}} +// expected-error@+3 {{conflicting types for 'main}} +// expected-warning@+2 {{return type of 'main' is not 'int'}} +// expected-note@+1 {{change return type to 'int'}} fptr main() { +// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:5}:"int" return (fptr) 0; }