-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Rework the printing of attributes #87281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
94f1c86
871f5b0
e7e2e90
a72cf87
fd21bb2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ | |
#include "clang/AST/ExprCXX.h" | ||
#include "clang/AST/PrettyPrinter.h" | ||
#include "clang/Basic/Module.h" | ||
#include "clang/Basic/SourceManager.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
using namespace clang; | ||
|
||
|
@@ -49,18 +50,6 @@ namespace { | |
|
||
void PrintObjCTypeParams(ObjCTypeParamList *Params); | ||
|
||
enum class AttrPrintLoc { | ||
None = 0, | ||
Left = 1, | ||
Right = 2, | ||
Any = Left | Right, | ||
|
||
LLVM_MARK_AS_BITMASK_ENUM(/*DefaultValue=*/Any) | ||
}; | ||
|
||
void prettyPrintAttributes(Decl *D, raw_ostream &out, | ||
AttrPrintLoc loc = AttrPrintLoc::Any); | ||
|
||
public: | ||
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, | ||
const ASTContext &Context, unsigned Indentation = 0, | ||
|
@@ -129,11 +118,10 @@ namespace { | |
const TemplateParameterList *Params); | ||
void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args, | ||
const TemplateParameterList *Params); | ||
|
||
inline void prettyPrintAttributes(Decl *D) { | ||
prettyPrintAttributes(D, Out); | ||
} | ||
|
||
enum class AttrPosAsWritten { Unknown = 0, Default, Left, Right }; | ||
void | ||
prettyPrintAttributes(const Decl *D, | ||
AttrPosAsWritten Pos = AttrPosAsWritten::Default); | ||
void prettyPrintPragmas(Decl *D); | ||
void printDeclType(QualType T, StringRef DeclName, bool Pack = false); | ||
}; | ||
|
@@ -250,87 +238,53 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) { | |
return Out; | ||
} | ||
|
||
// For CLANG_ATTR_LIST_CanPrintOnLeft macro. | ||
#include "clang/Basic/AttrLeftSideCanPrintList.inc" | ||
static DeclPrinter::AttrPosAsWritten getPosAsWritten(const Attr *A, | ||
const Decl *D) { | ||
SourceLocation ALoc = A->getLoc(); | ||
SourceLocation DLoc = D->getLocation(); | ||
const ASTContext &C = D->getASTContext(); | ||
if (ALoc.isInvalid() || DLoc.isInvalid()) | ||
return DeclPrinter::AttrPosAsWritten::Unknown; | ||
|
||
// For CLANG_ATTR_LIST_PrintOnLeft macro. | ||
#include "clang/Basic/AttrLeftSideMustPrintList.inc" | ||
if (C.getSourceManager().isBeforeInTranslationUnit(ALoc, DLoc)) | ||
return DeclPrinter::AttrPosAsWritten::Left; | ||
|
||
static bool canPrintOnLeftSide(attr::Kind kind) { | ||
#ifdef CLANG_ATTR_LIST_CanPrintOnLeft | ||
switch (kind) { | ||
CLANG_ATTR_LIST_CanPrintOnLeft | ||
return true; | ||
default: | ||
return false; | ||
} | ||
#else | ||
return false; | ||
#endif | ||
} | ||
|
||
static bool canPrintOnLeftSide(const Attr *A) { | ||
if (A->isStandardAttributeSyntax()) | ||
return false; | ||
|
||
return canPrintOnLeftSide(A->getKind()); | ||
return DeclPrinter::AttrPosAsWritten::Right; | ||
} | ||
|
||
static bool mustPrintOnLeftSide(attr::Kind kind) { | ||
#ifdef CLANG_ATTR_LIST_PrintOnLeft | ||
switch (kind) { | ||
CLANG_ATTR_LIST_PrintOnLeft | ||
return true; | ||
default: | ||
return false; | ||
} | ||
#else | ||
return false; | ||
#endif | ||
} | ||
|
||
static bool mustPrintOnLeftSide(const Attr *A) { | ||
if (A->isDeclspecAttribute()) | ||
return true; | ||
|
||
return mustPrintOnLeftSide(A->getKind()); | ||
} | ||
|
||
void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &Out, | ||
AttrPrintLoc Loc) { | ||
void DeclPrinter::prettyPrintAttributes(const Decl *D, | ||
AttrPosAsWritten Pos /*=Default*/) { | ||
if (Policy.PolishForDeclaration) | ||
return; | ||
|
||
if (D->hasAttrs()) { | ||
AttrVec &Attrs = D->getAttrs(); | ||
assert(Pos != AttrPosAsWritten::Unknown && "Use Default"); | ||
const AttrVec &Attrs = D->getAttrs(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I'd like an assert here to make sure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added an assert in the if-stmt. Is that what you meant? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that, it does what I want, yes. |
||
for (auto *A : Attrs) { | ||
if (A->isInherited() || A->isImplicit()) | ||
continue; | ||
|
||
AttrPrintLoc AttrLoc = AttrPrintLoc::Right; | ||
if (mustPrintOnLeftSide(A)) { | ||
// If we must always print on left side (e.g. declspec), then mark as | ||
// so. | ||
AttrLoc = AttrPrintLoc::Left; | ||
} else if (canPrintOnLeftSide(A)) { | ||
// For functions with body defined we print the attributes on the left | ||
// side so that GCC accept our dumps as well. | ||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); | ||
FD && FD->isThisDeclarationADefinition()) | ||
// In case Decl is a function with a body, then attrs should be print | ||
// on the left side. | ||
AttrLoc = AttrPrintLoc::Left; | ||
|
||
// In case it is a variable declaration with a ctor, then allow | ||
// printing on the left side for readbility. | ||
else if (const VarDecl *VD = dyn_cast<VarDecl>(D); | ||
VD && VD->getInit() && | ||
VD->getInitStyle() == VarDecl::CallInit) | ||
AttrLoc = AttrPrintLoc::Left; | ||
switch (A->getKind()) { | ||
#define ATTR(X) | ||
#define PRAGMA_SPELLING_ATTR(X) case attr::X: | ||
#include "clang/Basic/AttrList.inc" | ||
break; | ||
default: | ||
AttrPosAsWritten APos = getPosAsWritten(A, D); | ||
// Might trigger on programatically created attributes or declarations | ||
// with no source locations. | ||
assert(APos != AttrPosAsWritten::Unknown && | ||
"Invalid source location for attribute or decl."); | ||
assert(APos != AttrPosAsWritten::Default && | ||
"Default not a valid for an attribute location"); | ||
if (Pos == AttrPosAsWritten::Default || Pos == APos) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the case we are printing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we have not specified
That's doable but seemed outside of the scope of this PR since I am hoping to get it merged asap... |
||
if (Pos != AttrPosAsWritten::Left) | ||
Out << ' '; | ||
A->printPretty(Out, Policy); | ||
if (Pos == AttrPosAsWritten::Left) | ||
Out << ' '; | ||
} | ||
break; | ||
} | ||
// Only print the side matches the user requested. | ||
if ((Loc & AttrLoc) != AttrPrintLoc::None) | ||
A->printPretty(Out, Policy); | ||
} | ||
} | ||
} | ||
|
@@ -691,8 +645,10 @@ static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy, | |
|
||
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { | ||
if (!D->getDescribedFunctionTemplate() && | ||
!D->isFunctionTemplateSpecialization()) | ||
!D->isFunctionTemplateSpecialization()) { | ||
prettyPrintPragmas(D); | ||
prettyPrintAttributes(D, AttrPosAsWritten::Left); | ||
} | ||
|
||
if (D->isFunctionTemplateSpecialization()) | ||
Out << "template<> "; | ||
|
@@ -702,22 +658,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { | |
printTemplateParameters(D->getTemplateParameterList(I)); | ||
} | ||
|
||
std::string LeftsideAttrs; | ||
llvm::raw_string_ostream LSAS(LeftsideAttrs); | ||
|
||
prettyPrintAttributes(D, LSAS, AttrPrintLoc::Left); | ||
|
||
// prettyPrintAttributes print a space on left side of the attribute. | ||
if (LeftsideAttrs[0] == ' ') { | ||
// Skip the space prettyPrintAttributes generated. | ||
LeftsideAttrs.erase(0, LeftsideAttrs.find_first_not_of(' ')); | ||
|
||
// Add a single space between the attribute and the Decl name. | ||
LSAS << ' '; | ||
} | ||
|
||
Out << LeftsideAttrs; | ||
|
||
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D); | ||
CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D); | ||
CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D); | ||
|
@@ -883,7 +823,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { | |
Ty.print(Out, Policy, Proto); | ||
} | ||
|
||
prettyPrintAttributes(D, Out, AttrPrintLoc::Right); | ||
prettyPrintAttributes(D, AttrPosAsWritten::Right); | ||
|
||
if (D->isPureVirtual()) | ||
Out << " = 0"; | ||
|
@@ -976,27 +916,12 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) { | |
void DeclPrinter::VisitVarDecl(VarDecl *D) { | ||
prettyPrintPragmas(D); | ||
|
||
prettyPrintAttributes(D, AttrPosAsWritten::Left); | ||
|
||
if (const auto *Param = dyn_cast<ParmVarDecl>(D); | ||
Param && Param->isExplicitObjectParameter()) | ||
Out << "this "; | ||
|
||
std::string LeftSide; | ||
llvm::raw_string_ostream LeftSideStream(LeftSide); | ||
|
||
// Print attributes that should be placed on the left, such as __declspec. | ||
prettyPrintAttributes(D, LeftSideStream, AttrPrintLoc::Left); | ||
|
||
// prettyPrintAttributes print a space on left side of the attribute. | ||
if (LeftSide[0] == ' ') { | ||
// Skip the space prettyPrintAttributes generated. | ||
LeftSide.erase(0, LeftSide.find_first_not_of(' ')); | ||
|
||
// Add a single space between the attribute and the Decl name. | ||
LeftSideStream << ' '; | ||
} | ||
|
||
Out << LeftSide; | ||
|
||
QualType T = D->getTypeSourceInfo() | ||
? D->getTypeSourceInfo()->getType() | ||
: D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); | ||
|
@@ -1029,21 +954,16 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { | |
} | ||
} | ||
|
||
StringRef Name; | ||
|
||
Name = (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters && | ||
D->getIdentifier()) | ||
? D->getIdentifier()->deuglifiedName() | ||
: D->getName(); | ||
|
||
if (!Policy.SuppressTagKeyword && Policy.SuppressScope && | ||
!Policy.SuppressUnwrittenScope) | ||
MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out); | ||
printDeclType(T, Name); | ||
|
||
// Print the attributes that should be placed right before the end of the | ||
// decl. | ||
prettyPrintAttributes(D, Out, AttrPrintLoc::Right); | ||
printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters && | ||
D->getIdentifier()) | ||
? D->getIdentifier()->deuglifiedName() | ||
: D->getName()); | ||
|
||
prettyPrintAttributes(D, AttrPosAsWritten::Right); | ||
|
||
Expr *Init = D->getInit(); | ||
if (!Policy.SuppressInitializers && Init) { | ||
|
Uh oh!
There was an error while loading. Please reload this page.