summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/Decl.h14
-rw-r--r--clang/include/clang/AST/Type.h20
-rw-r--r--clang/lib/AST/ASTContext.cpp5
-rw-r--r--clang/lib/AST/Decl.cpp16
-rw-r--r--clang/lib/AST/Type.cpp6
-rw-r--r--clang/lib/Sema/SemaType.cpp1
-rw-r--r--clang/unittests/AST/SourceLocationTest.cpp106
7 files changed, 163 insertions, 5 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 31adfc5c368..c1544c9ded9 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1964,6 +1964,14 @@ public:
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 @@ public:
/// 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 differ 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 05e78aa7823..02c9aa403b5 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 @@ public:
RefQualifierKind RefQualifier = RQ_None;
ExceptionSpecInfo ExceptionSpec;
const ExtParameterInfo *ExtParameterInfos = nullptr;
+ SourceLocation EllipsisLoc;
ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {}
@@ -3830,6 +3834,10 @@ private:
return getNumParams();
}
+ unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
+ return isVariadic();
+ }
+
unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const {
return hasExtraBitfields();
}
@@ -3941,6 +3949,7 @@ public:
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 @@ public:
/// 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 abfa33d0df0..eb02a61b234 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 3723c868004..bfcf7926861 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 4fed5b410b1..2eae2ebb617 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 2f5fdfb1f91..4cbf041533b 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 6b4dddc3850..d104497974f 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);
OpenPOWER on IntegriCloud