Skip to content

Commit 02c0b3b

Browse files
mattmccutchen-ccijohn-h-kastner
authored andcommitted
Reconstruct a parameter declaration if we can't get its original source
due to a macro. Cleanup: It doesn't seem like we need the special case for typedefs in tyToStr. Indeed, if the type is actually a TypedefType, I'd expect Clang to print it as such.
1 parent 6c05f9d commit 02c0b3b

File tree

4 files changed

+59
-20
lines changed

4 files changed

+59
-20
lines changed

clang/include/clang/3C/Utils.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,12 @@ bool isVarArgType(const std::string &TypeName);
142142
bool isStructOrUnionType(clang::VarDecl *VD);
143143

144144
// Helper method to print a Type in a way that can be represented in the source.
145-
std::string tyToStr(const clang::Type *T);
145+
// If Name is given, it is included as the variable name (which otherwise isn't
146+
// trivial to do with function pointers, etc.).
147+
std::string tyToStr(const clang::Type *T, const std::string &Name = "");
148+
149+
// Same as tyToStr with a QualType.
150+
std::string qtyToStr(clang::QualType QT, const std::string &Name = "");
146151

147152
// Get the end source location of the end of the provided function.
148153
clang::SourceLocation getFunctionDeclRParen(clang::FunctionDecl *FD,

clang/lib/3C/DeclRewriter.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,10 @@ void FunctionDeclBuilder::buildItypeDecl(PVConstraint *Defn,
700700
return;
701701
}
702702

703+
// Note: For a parameter, Type + IType will give the full declaration (including
704+
// the name) but the breakdown between Type and IType is not guaranteed. For a
705+
// return, Type will be what goes before the name and IType will be what goes
706+
// after the parentheses.
703707
void
704708
FunctionDeclBuilder::buildDeclVar(PVConstraint *IntCV, PVConstraint *ExtCV,
705709
DeclaratorDecl *Decl, std::string &Type,
@@ -725,19 +729,26 @@ FunctionDeclBuilder::buildDeclVar(PVConstraint *IntCV, PVConstraint *ExtCV,
725729
// For parameter variables, we try to extract the declaration from the source
726730
// code. This preserves macros and other formatting. This isn't possible for
727731
// return variables because the itype on returns is located after the
728-
// parameter list. Sometimes the source range for a parameter declaration is
729-
// not valid, for example if a function prototype is declared using a typedef.
730-
// For these cases, we just fall back to reconstructing the declaration from
731-
// the PVConstraint.
732-
SourceRange Range = Decl->getSourceRange();
733-
if (isa<ParmVarDecl>(Decl) && Range.isValid()) {
734-
Type = getSourceText(Range, *Context);
735-
IType = "";
732+
// parameter list. Sometimes we cannot get the original source for a parameter
733+
// declaration, for example if a function prototype is declared using a
734+
// typedef or the parameter declaration is inside a macro. For these cases, we
735+
// just fall back to reconstructing the declaration from the PVConstraint.
736+
ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Decl);
737+
if (PVD) {
738+
Type = getSourceText(PVD->getSourceRange(), *Context);
739+
if (!Type.empty()) {
740+
// Great, we got the original source including any itype and bounds.
741+
IType = "";
742+
return;
743+
}
744+
// Otherwise, reconstruct the name and type, and reuse the code below for
745+
// the itype and bounds.
746+
Type = qtyToStr(PVD->getOriginalType(), PVD->getNameAsString());
736747
} else {
737748
Type = ExtCV->getOriginalTy() + " ";
738-
IType = getExistingIType(ExtCV);
739-
IType += ABRewriter.getBoundsString(ExtCV, Decl, !IType.empty());
740749
}
750+
IType = getExistingIType(ExtCV);
751+
IType += ABRewriter.getBoundsString(ExtCV, Decl, !IType.empty());
741752
}
742753

743754
std::string FunctionDeclBuilder::getExistingIType(ConstraintVariable *DeclC) {

clang/lib/3C/Utils.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,15 +224,14 @@ bool isStructOrUnionType(clang::VarDecl *VD) {
224224
VD->getType().getTypePtr()->isUnionType();
225225
}
226226

227-
std::string tyToStr(const clang::Type *T) {
228-
if (auto TDT = dyn_cast<TypedefType>(T)) {
229-
auto D = TDT->getDecl();
230-
std::string s = D->getNameAsString();
231-
return s;
232-
} else {
233-
QualType QT(T, 0);
234-
return QT.getAsString();
235-
}
227+
std::string qtyToStr(clang::QualType QT, const std::string &Name) {
228+
std::string S = Name;
229+
QT.getAsStringInternal(S, LangOptions());
230+
return S;
231+
}
232+
233+
std::string tyToStr(const clang::Type *T, const std::string &Name) {
234+
return qtyToStr(QualType(T, 0), Name);
236235
}
237236

238237
Expr *removeAuxillaryCasts(Expr *E) {

clang/test/3C/params_in_macro.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Test that if FunctionDeclBuilder::buildDeclVar cannot get the original source
2+
// for a parameter declaration due to a macro, it reconstructs the declaration
3+
// (including the name) instead of leaving a blank.
4+
5+
// RUN: 3c -base-dir=%S %s -- | FileCheck -match-full-lines %s
6+
// RUN: 3c -base-dir=%S %s -- | %clang -c -fcheckedc-extension -x c -o /dev/null -
7+
8+
// 3C is not idempotent on this file because the first pass constrains the
9+
// pointers in the macros to wild but then inlines the macros, so the second
10+
// pass will make those pointers checked. So don't try to test idempotence.
11+
12+
typedef double mydouble;
13+
14+
// TODO: FunctionDeclBuilder::buildDeclVar should be able to handle an itype
15+
// here, but currently the PointerConstraintVariable constructor asserts when it
16+
// fails to retrieve the original source of the itype declaration.
17+
#define parms1 volatile mydouble d, void (*f)(void)
18+
#define parms2 int *const y : count(7), _Ptr<char> z
19+
20+
void test(parms1, int *x, parms2) {}
21+
// CHECK: void test(volatile mydouble d, void (*f)(void), _Ptr<int> x, int *const y : count(7), _Ptr<char> z) {}
22+
23+
// Before the bug fix, we got:
24+
// void test(, , _Ptr<int> x, , ) {}

0 commit comments

Comments
 (0)