Skip to content

Commit cc3c935

Browse files
balayetteAaronBallman
authored andcommitted
Add FunctionDecl::getParameterSourceRange()
This source range covers the list of parameters of the function declaration, including the ellipsis for a variadic function.
1 parent aedeab7 commit cc3c935

File tree

7 files changed

+163
-5
lines changed

7 files changed

+163
-5
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,14 @@ class FunctionDecl : public DeclaratorDecl,
19641964

19651965
void setRangeEnd(SourceLocation E) { EndRangeLoc = E; }
19661966

1967+
/// Returns the location of the ellipsis of a variadic function.
1968+
SourceLocation getEllipsisLoc() const {
1969+
const auto *FPT = getType()->getAs<FunctionProtoType>();
1970+
if (FPT && FPT->isVariadic())
1971+
return FPT->getEllipsisLoc();
1972+
return SourceLocation();
1973+
}
1974+
19671975
SourceRange getSourceRange() const override LLVM_READONLY;
19681976

19691977
// Function definitions.
@@ -2388,6 +2396,12 @@ class FunctionDecl : public DeclaratorDecl,
23882396
/// limited representation in the AST.
23892397
SourceRange getReturnTypeSourceRange() const;
23902398

2399+
/// Attempt to compute an informative source range covering the
2400+
/// function parameters, including the ellipsis of a variadic function.
2401+
/// The source range excludes the parentheses, and is invalid if there are
2402+
/// no parameters and no ellipsis.
2403+
SourceRange getParametersSourceRange() const;
2404+
23912405
/// Get the declared return type, which may differ from the actual return
23922406
/// type if the return type is deduced.
23932407
QualType getDeclaredReturnType() const {

clang/include/clang/AST/Type.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3728,9 +3728,9 @@ class FunctionProtoType final
37283728
: public FunctionType,
37293729
public llvm::FoldingSetNode,
37303730
private llvm::TrailingObjects<
3731-
FunctionProtoType, QualType, FunctionType::FunctionTypeExtraBitfields,
3732-
FunctionType::ExceptionType, Expr *, FunctionDecl *,
3733-
FunctionType::ExtParameterInfo, Qualifiers> {
3731+
FunctionProtoType, QualType, SourceLocation,
3732+
FunctionType::FunctionTypeExtraBitfields, FunctionType::ExceptionType,
3733+
Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers> {
37343734
friend class ASTContext; // ASTContext creates these.
37353735
friend TrailingObjects;
37363736

@@ -3741,6 +3741,9 @@ class FunctionProtoType final
37413741
// Always present. Note that for the vast majority of FunctionProtoType,
37423742
// these will be the only trailing objects.
37433743
//
3744+
// * Optionally if the function is variadic, the SourceLocation of the
3745+
// ellipsis.
3746+
//
37443747
// * Optionally if some extra data is stored in FunctionTypeExtraBitfields
37453748
// (see FunctionTypeExtraBitfields and FunctionTypeBitfields):
37463749
// a single FunctionTypeExtraBitfields. Present if and only if
@@ -3812,6 +3815,7 @@ class FunctionProtoType final
38123815
RefQualifierKind RefQualifier = RQ_None;
38133816
ExceptionSpecInfo ExceptionSpec;
38143817
const ExtParameterInfo *ExtParameterInfos = nullptr;
3818+
SourceLocation EllipsisLoc;
38153819

38163820
ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {}
38173821

@@ -3830,6 +3834,10 @@ class FunctionProtoType final
38303834
return getNumParams();
38313835
}
38323836

3837+
unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
3838+
return isVariadic();
3839+
}
3840+
38333841
unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const {
38343842
return hasExtraBitfields();
38353843
}
@@ -3941,6 +3949,7 @@ class FunctionProtoType final
39413949
ExtProtoInfo EPI;
39423950
EPI.ExtInfo = getExtInfo();
39433951
EPI.Variadic = isVariadic();
3952+
EPI.EllipsisLoc = getEllipsisLoc();
39443953
EPI.HasTrailingReturn = hasTrailingReturn();
39453954
EPI.ExceptionSpec.Type = getExceptionSpecType();
39463955
EPI.TypeQuals = getMethodQuals();
@@ -4042,6 +4051,11 @@ class FunctionProtoType final
40424051
/// Whether this function prototype is variadic.
40434052
bool isVariadic() const { return FunctionTypeBits.Variadic; }
40444053

4054+
SourceLocation getEllipsisLoc() const {
4055+
return isVariadic() ? *getTrailingObjects<SourceLocation>()
4056+
: SourceLocation();
4057+
}
4058+
40454059
/// Determines whether this function prototype contains a
40464060
/// parameter pack at the end.
40474061
///

clang/lib/AST/ASTContext.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3875,10 +3875,11 @@ QualType ASTContext::getFunctionTypeInternal(
38753875
auto ESH = FunctionProtoType::getExceptionSpecSize(
38763876
EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size());
38773877
size_t Size = FunctionProtoType::totalSizeToAlloc<
3878-
QualType, FunctionType::FunctionTypeExtraBitfields,
3878+
QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields,
38793879
FunctionType::ExceptionType, Expr *, FunctionDecl *,
38803880
FunctionProtoType::ExtParameterInfo, Qualifiers>(
3881-
NumArgs, FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type),
3881+
NumArgs, EPI.Variadic,
3882+
FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type),
38823883
ESH.NumExceptionType, ESH.NumExprPtr, ESH.NumFunctionDeclPtr,
38833884
EPI.ExtParameterInfos ? NumArgs : 0,
38843885
EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0);

clang/lib/AST/Decl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3356,6 +3356,22 @@ SourceRange FunctionDecl::getReturnTypeSourceRange() const {
33563356
return RTRange;
33573357
}
33583358

3359+
SourceRange FunctionDecl::getParametersSourceRange() const {
3360+
unsigned NP = getNumParams();
3361+
SourceLocation EllipsisLoc = getEllipsisLoc();
3362+
3363+
if (NP == 0 && EllipsisLoc.isInvalid())
3364+
return SourceRange();
3365+
3366+
SourceLocation Begin =
3367+
NP > 0 ? ParamInfo[0]->getSourceRange().getBegin() : EllipsisLoc;
3368+
SourceLocation End = EllipsisLoc.isValid()
3369+
? EllipsisLoc
3370+
: ParamInfo[NP - 1]->getSourceRange().getEnd();
3371+
3372+
return SourceRange(Begin, End);
3373+
}
3374+
33593375
SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
33603376
FunctionTypeLoc FTL = getFunctionTypeLoc();
33613377
return FTL ? FTL.getExceptionSpecRange() : SourceRange();

clang/lib/AST/Type.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3065,6 +3065,12 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
30653065
} else {
30663066
FunctionTypeBits.HasExtQuals = 0;
30673067
}
3068+
3069+
// Fill in the Ellipsis location info if present.
3070+
if (epi.Variadic) {
3071+
auto &EllipsisLoc = *getTrailingObjects<SourceLocation>();
3072+
EllipsisLoc = epi.EllipsisLoc;
3073+
}
30683074
}
30693075

30703076
bool FunctionProtoType::hasDependentExceptionSpec() const {

clang/lib/Sema/SemaType.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4810,6 +4810,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
48104810
FunctionProtoType::ExtProtoInfo EPI;
48114811
EPI.ExtInfo = EI;
48124812
EPI.Variadic = FTI.isVariadic;
4813+
EPI.EllipsisLoc = FTI.getEllipsisLoc();
48134814
EPI.HasTrailingReturn = FTI.hasTrailingReturnType();
48144815
EPI.TypeQuals.addCVRUQualifiers(
48154816
FTI.MethodQualifiers ? FTI.MethodQualifiers->getTypeQualifiers()

clang/unittests/AST/SourceLocationTest.cpp

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,112 @@ TEST(FunctionDecl, FunctionDeclWithNoExceptSpecification) {
648648
Language::Lang_CXX11));
649649
}
650650

651+
class FunctionDeclParametersRangeVerifier : public RangeVerifier<FunctionDecl> {
652+
protected:
653+
SourceRange getRange(const FunctionDecl &Function) override {
654+
return Function.getParametersSourceRange();
655+
}
656+
};
657+
658+
TEST(FunctionDeclParameters, FunctionDeclOnlyVariadic) {
659+
FunctionDeclParametersRangeVerifier Verifier;
660+
Verifier.expectRange(1, 8, 1, 8);
661+
EXPECT_TRUE(Verifier.match("void f(...);\n", functionDecl()));
662+
}
663+
664+
TEST(FunctionDeclParameters, FunctionDeclVariadic) {
665+
FunctionDeclParametersRangeVerifier Verifier;
666+
Verifier.expectRange(1, 8, 1, 15);
667+
EXPECT_TRUE(Verifier.match("void f(int a, ...);\n", functionDecl()));
668+
}
669+
670+
TEST(FunctionDeclParameters, FunctionDeclMacroVariadic) {
671+
FunctionDeclParametersRangeVerifier Verifier;
672+
Verifier.expectRange(2, 8, 1, 18);
673+
EXPECT_TRUE(Verifier.match("#define VARIADIC ...\n"
674+
"void f(int a, VARIADIC);\n",
675+
functionDecl()));
676+
}
677+
678+
TEST(FunctionDeclParameters, FunctionDeclMacroParams) {
679+
FunctionDeclParametersRangeVerifier Verifier;
680+
Verifier.expectRange(1, 16, 2, 20);
681+
EXPECT_TRUE(Verifier.match("#define PARAMS int a, int b\n"
682+
"void f(PARAMS, int c);",
683+
functionDecl()));
684+
}
685+
686+
TEST(FunctionDeclParameters, FunctionDeclSingleParameter) {
687+
FunctionDeclParametersRangeVerifier Verifier;
688+
Verifier.expectRange(1, 8, 1, 12);
689+
EXPECT_TRUE(Verifier.match("void f(int a);\n", functionDecl()));
690+
}
691+
692+
TEST(FunctionDeclParameters, MemberFunctionDecl) {
693+
FunctionDeclParametersRangeVerifier Verifier;
694+
Verifier.expectRange(2, 8, 2, 12);
695+
EXPECT_TRUE(Verifier.match("class A{\n"
696+
"void f(int a);\n"
697+
"};",
698+
functionDecl()));
699+
}
700+
701+
TEST(FunctionDeclParameters, MemberFunctionDeclVariadic) {
702+
FunctionDeclParametersRangeVerifier Verifier;
703+
Verifier.expectRange(2, 8, 2, 15);
704+
EXPECT_TRUE(Verifier.match("class A{\n"
705+
"void f(int a, ...);\n"
706+
"};",
707+
functionDecl()));
708+
}
709+
710+
TEST(FunctionDeclParameters, StaticFunctionDecl) {
711+
FunctionDeclParametersRangeVerifier Verifier;
712+
Verifier.expectRange(2, 15, 2, 19);
713+
EXPECT_TRUE(Verifier.match("class A{\n"
714+
"static void f(int a);\n"
715+
"};",
716+
functionDecl()));
717+
}
718+
719+
TEST(FunctionDeclParameters, FunctionDeclMultipleParameters) {
720+
FunctionDeclParametersRangeVerifier Verifier;
721+
Verifier.expectRange(1, 8, 1, 28);
722+
EXPECT_TRUE(
723+
Verifier.match("void f(int a, int b, char *c);\n", functionDecl()));
724+
}
725+
726+
TEST(FunctionDeclParameters, FunctionDeclWithDefaultValue) {
727+
FunctionDeclParametersRangeVerifier Verifier;
728+
Verifier.expectRange(1, 8, 1, 16);
729+
EXPECT_TRUE(Verifier.match("void f(int a = 5);\n", functionDecl()));
730+
}
731+
732+
TEST(FunctionDeclParameters, FunctionDeclWithVolatile) {
733+
FunctionDeclParametersRangeVerifier Verifier;
734+
Verifier.expectRange(1, 8, 1, 22);
735+
EXPECT_TRUE(Verifier.match("void f(volatile int *i);", functionDecl()));
736+
}
737+
738+
TEST(FunctionDeclParameters, FunctionDeclWithConstParam) {
739+
FunctionDeclParametersRangeVerifier Verifier;
740+
Verifier.expectRange(1, 8, 1, 19);
741+
EXPECT_TRUE(Verifier.match("void f(const int *i);", functionDecl()));
742+
}
743+
744+
TEST(FunctionDeclParameters, FunctionDeclWithConstVolatileParam) {
745+
FunctionDeclParametersRangeVerifier Verifier;
746+
Verifier.expectRange(1, 8, 1, 28);
747+
EXPECT_TRUE(Verifier.match("void f(const volatile int *i);", functionDecl()));
748+
}
749+
750+
TEST(FunctionDeclParameters, FunctionDeclWithParamAttribute) {
751+
FunctionDeclParametersRangeVerifier Verifier;
752+
Verifier.expectRange(1, 8, 1, 36);
753+
EXPECT_TRUE(Verifier.match("void f(__attribute__((unused)) int a) {}",
754+
functionDecl()));
755+
}
756+
651757
TEST(CXXMethodDecl, CXXMethodDeclWithThrowSpecification) {
652758
RangeVerifier<FunctionDecl> Verifier;
653759
Verifier.expectRange(2, 1, 2, 16);

0 commit comments

Comments
 (0)