Hi rsmith,
This patch improves attribute printing by taking the source location of
attributes into account when print them out. Previously, we hard code the print
out locations for attributes and this has some issues especially for C++11
attributes for example:
void foo [[noreturn]] (); would be printed out as
void foo () [[noreturn]]; which has a different semantic with source.
This patch uses the source locations of the attributes and VarDecl /
FunctionDecl to print out attributes at expected locations as described in
source files. It also fixes several FIXMEs in existing tests.
http://llvm-reviews.chandlerc.com/D395
Files:
lib/AST/DeclPrinter.cpp
test/SemaCXX/cxx11-attr-print.cpp
test/SemaCXX/attr-print.cpp
test/Sema/attr-print.c
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -28,6 +28,7 @@
class DeclPrinter : public DeclVisitor<DeclPrinter> {
raw_ostream &Out;
PrintingPolicy Policy;
+ SourceManager &SourceMgr;
unsigned Indentation;
bool PrintInstantiation;
@@ -39,9 +40,10 @@
public:
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
+ SourceManager &SourceMgr,
unsigned Indentation = 0, bool PrintInstantiation = false)
- : Out(Out), Policy(Policy), Indentation(Indentation),
- PrintInstantiation(PrintInstantiation) { }
+ : Out(Out), Policy(Policy), SourceMgr(SourceMgr),
+ Indentation(Indentation), PrintInstantiation(PrintInstantiation) { }
void VisitDeclContext(DeclContext *DC, bool Indent = true);
@@ -85,20 +87,76 @@
void PrintTemplateParameters(const TemplateParameterList *Params,
const TemplateArgumentList *Args = 0);
void prettyPrintAttributes(Decl *D);
+ /// \brief Pretty print a list of attributes to an output stream.
+ void prettyPrintAttributes(AttrVec &Attrs, llvm::raw_ostream &OS);
};
}
+
void Decl::print(raw_ostream &Out, unsigned Indentation,
bool PrintInstantiation) const {
- print(Out, getASTContext().getPrintingPolicy(), Indentation, PrintInstantiation);
+ print(Out, getASTContext().getPrintingPolicy(),
+ Indentation, PrintInstantiation);
}
void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation, bool PrintInstantiation) const {
- DeclPrinter Printer(Out, Policy, Indentation, PrintInstantiation);
+ DeclPrinter Printer(Out, Policy, getASTContext().getSourceManager(),
+ Indentation, PrintInstantiation);
Printer.Visit(const_cast<Decl*>(this));
}
+/// \brief Get a list of attributes appear before a source location.
+static void getAttributesBeforeSourceLocation(Decl *D, AttrVec &Attrs,
+ SourceManager &SourceMgr,
+ SourceLocation Loc) {
+ if (!D->hasAttrs())
+ return;
+
+ AttrVec &Attributes = D->getAttrs();
+ for (AttrVec::const_iterator I = Attributes.begin(), E = Attributes.end();
+ I != E; ++I) {
+ Attr *Attribute = *I;
+ if (SourceMgr.isBeforeInTranslationUnit(Attribute->getLocation(), Loc))
+ Attrs.push_back(Attribute);
+ }
+}
+
+/// \brief Get a list of attributes appear after a source location.
+static void getAttributesAfterSourceLocation(Decl *D, AttrVec &Attrs,
+ SourceManager &SourceMgr,
+ SourceLocation Loc) {
+ if (!D->hasAttrs())
+ return;
+
+ AttrVec &Attributes = D->getAttrs();
+ for (AttrVec::const_iterator I = Attributes.begin(), E = Attributes.end();
+ I != E; ++I) {
+ Attr *Attribute = *I;
+ if (SourceMgr.isBeforeInTranslationUnit(Loc, Attribute->getLocation()))
+ Attrs.push_back(Attribute);
+ }
+}
+
+/// \brief Get a list of attributes appear within a source range.
+static void getAttributesWithinSourceRange(Decl *D, AttrVec &Attrs,
+ SourceManager &SourceMgr,
+ SourceLocation RangeStart,
+ SourceLocation RangeEnd) {
+ if (!D->hasAttrs())
+ return;
+
+ AttrVec &Attributes = D->getAttrs();
+ for (AttrVec::const_iterator I = Attributes.begin(), E = Attributes.end();
+ I != E; ++I) {
+ Attr *Attribute = *I;
+ if (SourceMgr.isBeforeInTranslationUnit(RangeStart,
+ Attribute->getLocation()) &&
+ SourceMgr.isBeforeInTranslationUnit(Attribute->getLocation(), RangeEnd))
+ Attrs.push_back(Attribute);
+ }
+}
+
static QualType GetBaseType(QualType T) {
// FIXME: This should be on the Type class!
QualType BaseType = T;
@@ -170,9 +228,10 @@
const DeclContext *DC = this;
while (!DC->isTranslationUnit())
DC = DC->getParent();
-
+
ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
- DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), 0);
+ DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(),
+ Ctx.getSourceManager(), 0);
Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
}
@@ -185,7 +244,7 @@
void DeclPrinter::prettyPrintAttributes(Decl *D) {
if (Policy.PolishForDeclaration)
return;
-
+
if (D->hasAttrs()) {
AttrVec &Attrs = D->getAttrs();
for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) {
@@ -195,6 +254,16 @@
}
}
+void DeclPrinter::prettyPrintAttributes(AttrVec &Attrs, llvm::raw_ostream &OS) {
+ if (Policy.PolishForDeclaration)
+ return;
+
+ for (AttrVec::const_iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ (*I)->printPretty(OS, Policy);
+ }
+}
+
void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
this->Indent();
Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
@@ -387,6 +456,15 @@
}
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+ // Collect and print out attributes appear at the very
+ // start of a function declaration.
+ AttrVec Attrs;
+ getAttributesBeforeSourceLocation(D, Attrs, SourceMgr,
+ D->getNameInfo().getLoc());
+ prettyPrintAttributes(Attrs, Out);
+ if (Attrs.size())
+ Out << " ";
+
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
if (!Policy.SuppressSpecifiers) {
switch (D->getStorageClassAsWritten()) {
@@ -416,6 +494,23 @@
}
if (isa<FunctionType>(Ty)) {
+ // Collect and print attributes appear between function declarator-id and
+ // parameter-type-list.
+ Attrs.clear();
+ SourceLocation StartLoc = D->getNameInfo().getEndLoc();
+ TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
+ const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL);
+ assert(FTLoc && "empty function type loc!");
+ SourceLocation EndLoc = FTLoc->getLParenLoc();
+ getAttributesWithinSourceRange(D, Attrs, SourceMgr, StartLoc, EndLoc);
+
+ std::string AttrStr;
+ llvm::raw_string_ostream AttrPrinter(AttrStr);
+ prettyPrintAttributes(Attrs, AttrPrinter);
+ Proto += AttrPrinter.str();
+ if (Attrs.size())
+ Proto += " ";
+
const FunctionType *AFT = Ty->getAs<FunctionType>();
const FunctionProtoType *FT = 0;
if (D->hasWrittenPrototype())
@@ -424,7 +519,9 @@
Proto += "(";
if (FT) {
llvm::raw_string_ostream POut(Proto);
- DeclPrinter ParamPrinter(POut, SubPolicy, Indentation);
+ DeclPrinter ParamPrinter(POut, SubPolicy,
+ D->getASTContext().getSourceManager(),
+ Indentation);
for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
if (i) POut << ", ";
ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
@@ -443,7 +540,7 @@
}
Proto += ")";
-
+
if (FT) {
if (FT->isConst())
Proto += " const";
@@ -478,6 +575,16 @@
}
}
+ // Collect and print attributes appear after function
+ // parameter-type-list.
+ Attrs.clear();
+ AttrStr.clear();
+ llvm::raw_string_ostream OS(AttrStr);
+ getAttributesAfterSourceLocation(D, Attrs, SourceMgr,
+ FTLoc->getRParenLoc());
+ prettyPrintAttributes(Attrs, OS);
+ Proto += OS.str();
+
if (CDecl) {
bool HasInitializerList = false;
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
@@ -549,8 +656,6 @@
Ty.print(Out, Policy, Proto);
}
- prettyPrintAttributes(D);
-
if (D->isPure())
Out << " = 0";
else if (D->isDeletedAsWritten())
@@ -562,7 +667,9 @@
// This is a K&R function definition, so we need to print the
// parameters.
Out << '\n';
- DeclPrinter ParamPrinter(Out, SubPolicy, Indentation);
+ DeclPrinter ParamPrinter(Out, SubPolicy,
+ D->getASTContext().getSourceManager(),
+ Indentation);
Indentation += Policy.Indentation;
for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
Indent();
@@ -633,6 +740,15 @@
void DeclPrinter::VisitVarDecl(VarDecl *D) {
+ // Collect and print attributes appear before
+ // declared variable.
+ AttrVec Attrs;
+ getAttributesBeforeSourceLocation(D, Attrs, SourceMgr,
+ D->getLocation());
+ prettyPrintAttributes(Attrs, Out);
+ if (Attrs.size())
+ Out << " ";
+
StorageClass SCAsWritten = D->getStorageClassAsWritten();
if (!Policy.SuppressSpecifiers && SCAsWritten != SC_None)
Out << VarDecl::getStorageClassSpecifierString(SCAsWritten) << " ";
@@ -668,7 +784,12 @@
Out << ")";
}
}
- prettyPrintAttributes(D);
+
+ // Collect and print attributes after declared variable.
+ Attrs.clear();
+ getAttributesAfterSourceLocation(D, Attrs, SourceMgr,
+ D->getLocation());
+ prettyPrintAttributes(Attrs, Out);
}
void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
@@ -853,8 +974,8 @@
void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (PrintInstantiation) {
TemplateParameterList *Params = D->getTemplateParameters();
- for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end();
- I != E; ++I) {
+ for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(),
+ E = D->spec_end(); I != E; ++I) {
PrintTemplateParameters(Params, (*I)->getTemplateSpecializationArgs());
Visit(*I);
}
@@ -866,8 +987,8 @@
void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (PrintInstantiation) {
TemplateParameterList *Params = D->getTemplateParameters();
- for (ClassTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end();
- I != E; ++I) {
+ for (ClassTemplateDecl::spec_iterator I = D->spec_begin(),
+ E = D->spec_end(); I != E; ++I) {
PrintTemplateParameters(Params, &(*I)->getTemplateArgs());
Visit(*I);
Out << '\n';
Index: test/SemaCXX/cxx11-attr-print.cpp
===================================================================
--- test/SemaCXX/cxx11-attr-print.cpp
+++ test/SemaCXX/cxx11-attr-print.cpp
@@ -3,23 +3,22 @@
// CHECK: int x __attribute__((aligned(4)));
int x __attribute__((aligned(4)));
-// FIXME: Print this at a valid location for a __declspec attr.
-// CHECK: int y __declspec(align(4));
+// CHECK: __declspec(align(4)) int y;
__declspec(align(4)) int y;
-// CHECK: gnu::aligned(4)]];
+// CHECK: int z {{\[}}[gnu::aligned(4)]];
int z [[gnu::aligned(4)]];
// CHECK: __attribute__((deprecated("warning")));
int a __attribute__((deprecated("warning")));
-// CHECK: gnu::deprecated("warning")]];
+// CHECK: {{\[}}[gnu::deprecated("warning")]];
int b [[gnu::deprecated("warning")]];
-// CHECK: int cxx11_alignas alignas(4);
+// CHECK: alignas(4) int cxx11_alignas;
alignas(4) int cxx11_alignas;
-// CHECK: int c11_alignas _Alignas(alignof(int));
+// CHECK: _Alignas(alignof(int)) int c11_alignas;
_Alignas(int) int c11_alignas;
// CHECK: void foo() __attribute__((const));
@@ -31,24 +30,22 @@
// CHECK: int f1() __attribute__((warn_unused_result));
int f1() __attribute__((warn_unused_result));
-// CHECK: clang::warn_unused_result]];
+// CHECK: int f2 {{\[}}[clang::warn_unused_result]] ();
int f2 [[clang::warn_unused_result]] ();
-// CHECK: gnu::warn_unused_result]];
+// CHECK: int f3 {{\[}}[gnu::warn_unused_result]] ();
int f3 [[gnu::warn_unused_result]] ();
-// FIXME: ast-print need to print C++11
-// attribute after function declare-id.
-// CHECK: noreturn]];
+// CHECK: void f4 {{\[}}[noreturn]] ();
void f4 [[noreturn]] ();
-// CHECK: std::noreturn]];
+// CHECK: void f5 {{\[}}[std::noreturn]] ();
void f5 [[std::noreturn]] ();
// CHECK: __attribute__((gnu_inline));
inline void f6() __attribute__((gnu_inline));
-// CHECK: gnu::gnu_inline]];
+// CHECK: inline void f7 {{\[}}[gnu::gnu_inline]] ();
inline void f7 [[gnu::gnu_inline]] ();
// arguments printing
@@ -57,8 +54,8 @@
// CHECK: int m __attribute__((aligned(4
// CHECK: int n alignas(4
-// CHECK: static int f() __attribute__((pure))
-// CHECK: static int g() {{\[}}[gnu::pure]]
+// CHECK: __attribute__((pure)) static int f()
+// CHECK: {{\[}}[gnu::pure]] static int g()
template <typename T> struct S {
__attribute__((aligned(4))) int m;
alignas(4) int n;
@@ -72,6 +69,9 @@
// CHECK: int m __attribute__((aligned(4
// CHECK: int n alignas(4
-// CHECK: static int f() __attribute__((pure))
-// CHECK: static int g() {{\[}}[gnu::pure]]
+// CHECK: __attribute__((pure)) static int f()
+// CHECK: {{\[}}[gnu::pure]] static int g()
template struct S<int>;
+
+// CHECK: {{\[}}[noreturn]] void combo {{\[}}[gnu::deprecated("")]] {{\[}}[gnu::pure]] () __attribute__((always_inline));
+[[noreturn]] void combo [[gnu::pure]] [[gnu::deprecated("")]] () __attribute__((always_inline));
Index: test/SemaCXX/attr-print.cpp
===================================================================
--- test/SemaCXX/attr-print.cpp
+++ test/SemaCXX/attr-print.cpp
@@ -3,8 +3,7 @@
// CHECK: int x __attribute__((aligned(4)));
int x __attribute__((aligned(4)));
-// FIXME: Print this at a valid location for a __declspec attr.
-// CHECK: int y __declspec(align(4));
+// CHECK: __declspec(align(4)) int y;
__declspec(align(4)) int y;
// CHECK: void foo() __attribute__((const));
Index: test/Sema/attr-print.c
===================================================================
--- test/Sema/attr-print.c
+++ test/Sema/attr-print.c
@@ -3,8 +3,7 @@
// CHECK: int x __attribute__((aligned(4)));
int x __attribute__((aligned(4)));
-// FIXME: Print this at a valid location for a __declspec attr.
-// CHECK: int y __declspec(align(4));
+// CHECK: __declspec(align(4)) int y;
__declspec(align(4)) int y;
// CHECK: void foo() __attribute__((const));
@@ -14,8 +13,8 @@
void bar() __attribute__((__const));
// FIXME: Print these at a valid location for these attributes.
-// CHECK: int *p32 __ptr32;
+// CHECK: __ptr32 int *p32;
int * __ptr32 p32;
-// CHECK: int *p64 __ptr64;
+// CHECK: __ptr64 int *p64;
int * __ptr64 p64;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits