Author: Nicolas Manichon Date: 2019-12-03T08:21:55-05:00 New Revision: cc3c935da24c8ebe4fd92638574462b762d92335
URL: https://github.com/llvm/llvm-project/commit/cc3c935da24c8ebe4fd92638574462b762d92335 DIFF: https://github.com/llvm/llvm-project/commit/cc3c935da24c8ebe4fd92638574462b762d92335.diff LOG: Add FunctionDecl::getParameterSourceRange() This source range covers the list of parameters of the function declaration, including the ellipsis for a variadic function. Added: Modified: clang/include/clang/AST/Decl.h clang/include/clang/AST/Type.h clang/lib/AST/ASTContext.cpp clang/lib/AST/Decl.cpp clang/lib/AST/Type.cpp clang/lib/Sema/SemaType.cpp clang/unittests/AST/SourceLocationTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 31adfc5c368a..c1544c9ded94 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1964,6 +1964,14 @@ class FunctionDecl : public DeclaratorDecl, void setRangeEnd(SourceLocation E) { EndRangeLoc = E; } + /// Returns the location of the ellipsis of a variadic function. + SourceLocation getEllipsisLoc() const { + const auto *FPT = getType()->getAs<FunctionProtoType>(); + if (FPT && FPT->isVariadic()) + return FPT->getEllipsisLoc(); + return SourceLocation(); + } + SourceRange getSourceRange() const override LLVM_READONLY; // Function definitions. @@ -2388,6 +2396,12 @@ class FunctionDecl : public DeclaratorDecl, /// limited representation in the AST. SourceRange getReturnTypeSourceRange() const; + /// Attempt to compute an informative source range covering the + /// function parameters, including the ellipsis of a variadic function. + /// The source range excludes the parentheses, and is invalid if there are + /// no parameters and no ellipsis. + SourceRange getParametersSourceRange() const; + /// Get the declared return type, which may diff er from the actual return /// type if the return type is deduced. QualType getDeclaredReturnType() const { diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 05e78aa78236..02c9aa403b5a 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -3728,9 +3728,9 @@ class FunctionProtoType final : public FunctionType, public llvm::FoldingSetNode, private llvm::TrailingObjects< - FunctionProtoType, QualType, FunctionType::FunctionTypeExtraBitfields, - FunctionType::ExceptionType, Expr *, FunctionDecl *, - FunctionType::ExtParameterInfo, Qualifiers> { + FunctionProtoType, QualType, SourceLocation, + FunctionType::FunctionTypeExtraBitfields, FunctionType::ExceptionType, + Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers> { friend class ASTContext; // ASTContext creates these. friend TrailingObjects; @@ -3741,6 +3741,9 @@ class FunctionProtoType final // Always present. Note that for the vast majority of FunctionProtoType, // these will be the only trailing objects. // + // * Optionally if the function is variadic, the SourceLocation of the + // ellipsis. + // // * Optionally if some extra data is stored in FunctionTypeExtraBitfields // (see FunctionTypeExtraBitfields and FunctionTypeBitfields): // a single FunctionTypeExtraBitfields. Present if and only if @@ -3812,6 +3815,7 @@ class FunctionProtoType final RefQualifierKind RefQualifier = RQ_None; ExceptionSpecInfo ExceptionSpec; const ExtParameterInfo *ExtParameterInfos = nullptr; + SourceLocation EllipsisLoc; ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {} @@ -3830,6 +3834,10 @@ class FunctionProtoType final return getNumParams(); } + unsigned numTrailingObjects(OverloadToken<SourceLocation>) const { + return isVariadic(); + } + unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const { return hasExtraBitfields(); } @@ -3941,6 +3949,7 @@ class FunctionProtoType final ExtProtoInfo EPI; EPI.ExtInfo = getExtInfo(); EPI.Variadic = isVariadic(); + EPI.EllipsisLoc = getEllipsisLoc(); EPI.HasTrailingReturn = hasTrailingReturn(); EPI.ExceptionSpec.Type = getExceptionSpecType(); EPI.TypeQuals = getMethodQuals(); @@ -4042,6 +4051,11 @@ class FunctionProtoType final /// Whether this function prototype is variadic. bool isVariadic() const { return FunctionTypeBits.Variadic; } + SourceLocation getEllipsisLoc() const { + return isVariadic() ? *getTrailingObjects<SourceLocation>() + : SourceLocation(); + } + /// Determines whether this function prototype contains a /// parameter pack at the end. /// diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index abfa33d0df08..eb02a61b234f 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3875,10 +3875,11 @@ QualType ASTContext::getFunctionTypeInternal( auto ESH = FunctionProtoType::getExceptionSpecSize( EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size()); size_t Size = FunctionProtoType::totalSizeToAlloc< - QualType, FunctionType::FunctionTypeExtraBitfields, + QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields, FunctionType::ExceptionType, Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, Qualifiers>( - NumArgs, FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type), + NumArgs, EPI.Variadic, + FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type), ESH.NumExceptionType, ESH.NumExprPtr, ESH.NumFunctionDeclPtr, EPI.ExtParameterInfos ? NumArgs : 0, EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 3723c868004f..bfcf7926861f 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3356,6 +3356,22 @@ SourceRange FunctionDecl::getReturnTypeSourceRange() const { return RTRange; } +SourceRange FunctionDecl::getParametersSourceRange() const { + unsigned NP = getNumParams(); + SourceLocation EllipsisLoc = getEllipsisLoc(); + + if (NP == 0 && EllipsisLoc.isInvalid()) + return SourceRange(); + + SourceLocation Begin = + NP > 0 ? ParamInfo[0]->getSourceRange().getBegin() : EllipsisLoc; + SourceLocation End = EllipsisLoc.isValid() + ? EllipsisLoc + : ParamInfo[NP - 1]->getSourceRange().getEnd(); + + return SourceRange(Begin, End); +} + SourceRange FunctionDecl::getExceptionSpecSourceRange() const { FunctionTypeLoc FTL = getFunctionTypeLoc(); return FTL ? FTL.getExceptionSpecRange() : SourceRange(); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 4fed5b410b17..2eae2ebb6174 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3065,6 +3065,12 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, } else { FunctionTypeBits.HasExtQuals = 0; } + + // Fill in the Ellipsis location info if present. + if (epi.Variadic) { + auto &EllipsisLoc = *getTrailingObjects<SourceLocation>(); + EllipsisLoc = epi.EllipsisLoc; + } } bool FunctionProtoType::hasDependentExceptionSpec() const { diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 2f5fdfb1f912..4cbf041533b2 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4810,6 +4810,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = EI; EPI.Variadic = FTI.isVariadic; + EPI.EllipsisLoc = FTI.getEllipsisLoc(); EPI.HasTrailingReturn = FTI.hasTrailingReturnType(); EPI.TypeQuals.addCVRUQualifiers( FTI.MethodQualifiers ? FTI.MethodQualifiers->getTypeQualifiers() diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp index 6b4dddc3850a..d104497974f1 100644 --- a/clang/unittests/AST/SourceLocationTest.cpp +++ b/clang/unittests/AST/SourceLocationTest.cpp @@ -648,6 +648,112 @@ TEST(FunctionDecl, FunctionDeclWithNoExceptSpecification) { Language::Lang_CXX11)); } +class FunctionDeclParametersRangeVerifier : public RangeVerifier<FunctionDecl> { +protected: + SourceRange getRange(const FunctionDecl &Function) override { + return Function.getParametersSourceRange(); + } +}; + +TEST(FunctionDeclParameters, FunctionDeclOnlyVariadic) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 8); + EXPECT_TRUE(Verifier.match("void f(...);\n", functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclVariadic) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 15); + EXPECT_TRUE(Verifier.match("void f(int a, ...);\n", functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclMacroVariadic) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(2, 8, 1, 18); + EXPECT_TRUE(Verifier.match("#define VARIADIC ...\n" + "void f(int a, VARIADIC);\n", + functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclMacroParams) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 16, 2, 20); + EXPECT_TRUE(Verifier.match("#define PARAMS int a, int b\n" + "void f(PARAMS, int c);", + functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclSingleParameter) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 12); + EXPECT_TRUE(Verifier.match("void f(int a);\n", functionDecl())); +} + +TEST(FunctionDeclParameters, MemberFunctionDecl) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(2, 8, 2, 12); + EXPECT_TRUE(Verifier.match("class A{\n" + "void f(int a);\n" + "};", + functionDecl())); +} + +TEST(FunctionDeclParameters, MemberFunctionDeclVariadic) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(2, 8, 2, 15); + EXPECT_TRUE(Verifier.match("class A{\n" + "void f(int a, ...);\n" + "};", + functionDecl())); +} + +TEST(FunctionDeclParameters, StaticFunctionDecl) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(2, 15, 2, 19); + EXPECT_TRUE(Verifier.match("class A{\n" + "static void f(int a);\n" + "};", + functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclMultipleParameters) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 28); + EXPECT_TRUE( + Verifier.match("void f(int a, int b, char *c);\n", functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclWithDefaultValue) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 16); + EXPECT_TRUE(Verifier.match("void f(int a = 5);\n", functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclWithVolatile) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 22); + EXPECT_TRUE(Verifier.match("void f(volatile int *i);", functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclWithConstParam) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 19); + EXPECT_TRUE(Verifier.match("void f(const int *i);", functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclWithConstVolatileParam) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 28); + EXPECT_TRUE(Verifier.match("void f(const volatile int *i);", functionDecl())); +} + +TEST(FunctionDeclParameters, FunctionDeclWithParamAttribute) { + FunctionDeclParametersRangeVerifier Verifier; + Verifier.expectRange(1, 8, 1, 36); + EXPECT_TRUE(Verifier.match("void f(__attribute__((unused)) int a) {}", + functionDecl())); +} + TEST(CXXMethodDecl, CXXMethodDeclWithThrowSpecification) { RangeVerifier<FunctionDecl> Verifier; Verifier.expectRange(2, 1, 2, 16); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits