Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ TEST(WorkspaceSymbols, Unnamed) {
ElementsAre(AllOf(qName("UnnamedStruct"),
withKind(SymbolKind::Variable))));
EXPECT_THAT(getSymbols(TU, "InUnnamed"),
ElementsAre(AllOf(qName("(anonymous struct)::InUnnamed"),
ElementsAre(AllOf(qName("(unnamed struct)::InUnnamed"),
withKind(SymbolKind::Field))));
}

Expand Down Expand Up @@ -656,15 +656,16 @@ TEST(DocumentSymbols, Enums) {
getSymbols(TU.build()),
ElementsAre(
AllOf(withName("(anonymous enum)"), withDetail("enum"),
children(AllOf(withName("Red"), withDetail("(unnamed)")))),
children(AllOf(withName("Red"), withDetail("(unnamed enum)")))),
AllOf(withName("Color"), withDetail("enum"),
children(AllOf(withName("Green"), withDetail("Color")))),
AllOf(withName("Color2"), withDetail("enum"),
children(AllOf(withName("Yellow"), withDetail("Color2")))),
AllOf(withName("ns"),
children(AllOf(withName("(anonymous enum)"), withDetail("enum"),
children(AllOf(withName("Black"),
withDetail("(unnamed)"))))))));
AllOf(
withName("ns"),
children(AllOf(withName("(anonymous enum)"), withDetail("enum"),
children(AllOf(withName("Black"),
withDetail("(unnamed enum)"))))))));
}

TEST(DocumentSymbols, Macro) {
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1827,7 +1827,7 @@ TEST_F(FindExplicitReferencesTest, AllRefsInFoo) {
int (*$2^fptr)(int $3^a, int) = nullptr;
}
)cpp",
"0: targets = {(unnamed)}\n"
"0: targets = {(unnamed class)}\n"
"1: targets = {x}, decl\n"
"2: targets = {fptr}, decl\n"
"3: targets = {a}, decl\n"},
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/unittests/HoverTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2103,7 +2103,7 @@ TEST(Hover, All) {
HI.NamespaceScope = "";
// FIXME: This should be `(anon enum)::`
HI.LocalScope = "";
HI.Type = "enum (unnamed)";
HI.Type = "enum (unnamed enum)";
HI.Definition = "ONE";
HI.Value = "0";
}},
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1470,8 +1470,8 @@ TEST_F(SymbolCollectorTest, NamelessSymbols) {
} Foo;
)";
runSymbolCollector(Header, /*Main=*/"");
EXPECT_THAT(Symbols, UnorderedElementsAre(qName("Foo"),
qName("(anonymous struct)::a")));
EXPECT_THAT(Symbols,
UnorderedElementsAre(qName("Foo"), qName("(unnamed struct)::a")));
}

TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3771,6 +3771,9 @@ class TagDecl : public TypeDecl,
/// True if this decl is currently being defined.
void setBeingDefined(bool V = true) { TagDeclBits.IsBeingDefined = V; }

void printAnonymousTagDecl(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const;

public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
Expand Down
7 changes: 5 additions & 2 deletions clang/include/clang/AST/PrettyPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ struct PrintingPolicy {
/// Create a default printing policy for the specified language.
PrintingPolicy(const LangOptions &LO)
: Indentation(2), SuppressSpecifiers(false),
SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
SuppressScope(false), SuppressUnwrittenScope(false),
SuppressTagKeyword(LO.CPlusPlus),
SuppressTagKeywordInAnonymousTagNames(false),
IncludeTagDefinition(false), SuppressScope(false),
SuppressUnwrittenScope(false),
SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant),
SuppressInitializers(false), ConstantArraySizeAsWritten(false),
AnonymousTagLocations(true), SuppressStrongLifetime(false),
Expand Down Expand Up @@ -121,6 +123,7 @@ struct PrintingPolicy {
/// \endcode
LLVM_PREFERRED_TYPE(bool)
unsigned SuppressTagKeyword : 1;
unsigned SuppressTagKeywordInAnonymousTagNames : 1;

/// When true, include the body of a tag definition.
///
Expand Down
88 changes: 75 additions & 13 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeBase.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
Expand Down Expand Up @@ -1789,13 +1790,17 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
}
else
OS << *ND;
} else if (const auto *RD = dyn_cast<RecordDecl>(DC)) {
if (TypedefNameDecl *TD = RD->getTypedefNameForAnonDecl())
OS << *TD;
else if (!RD->getIdentifier())
OS << "(anonymous " << RD->getKindName() << ')';
else
OS << *RD;
} else if (const auto *RD = llvm::dyn_cast<RecordDecl>(DC)) {
PrintingPolicy Copy(P);
// As part of a scope we want to print anonymous names as:
// ..::(anonymous struct)::..
//
// I.e., suppress tag locations, suppress leading keyword, *don't*
// suppress tag in name
Copy.SuppressTagKeyword = true;
Copy.SuppressTagKeywordInAnonymousTagNames = false;
Copy.AnonymousTagLocations = false;
RD->printName(OS, Copy);
} else if (const auto *FD = dyn_cast<FunctionDecl>(DC)) {
const FunctionProtoType *FT = nullptr;
if (FD->hasWrittenPrototype())
Expand Down Expand Up @@ -4954,19 +4959,76 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
}
}

void TagDecl::printAnonymousTagDecl(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const {
if (TypedefNameDecl *Typedef = getTypedefNameForAnonDecl()) {
assert(Typedef->getIdentifier() && "Typedef without identifier?");
OS << Typedef->getIdentifier()->getName();
return;
}

bool SuppressTagKeywordInName = Policy.SuppressTagKeywordInAnonymousTagNames;

// Emit leading keyword. Since we printed a leading keyword make sure we
// don't print the tag as part of the name too.
if (!Policy.SuppressTagKeyword) {
OS << getKindName() << ' ';
SuppressTagKeywordInName = true;
}

// Make an unambiguous representation for anonymous types, e.g.
// (anonymous enum at /usr/include/string.h:120:9)
OS << (Policy.MSVCFormatting ? '`' : '(');

if (isa<CXXRecordDecl>(this) && cast<CXXRecordDecl>(this)->isLambda()) {
OS << "lambda";
SuppressTagKeywordInName = true;
} else if ((isa<RecordDecl>(this) &&
cast<RecordDecl>(this)->isAnonymousStructOrUnion())) {
OS << "anonymous";
} else {
OS << "unnamed";
}

if (!SuppressTagKeywordInName)
OS << ' ' << getKindName();

if (Policy.AnonymousTagLocations) {
PresumedLoc PLoc =
getASTContext().getSourceManager().getPresumedLoc(getLocation());
if (PLoc.isValid()) {
OS << " at ";
StringRef File = PLoc.getFilename();
llvm::SmallString<1024> WrittenFile(File);
if (auto *Callbacks = Policy.Callbacks)
WrittenFile = Callbacks->remapPath(File);
// Fix inconsistent path separator created by
// clang::DirectoryLookup::LookupFile when the file path is relative
// path.
llvm::sys::path::Style Style =
llvm::sys::path::is_absolute(WrittenFile)
? llvm::sys::path::Style::native
: (Policy.MSVCFormatting
? llvm::sys::path::Style::windows_backslash
: llvm::sys::path::Style::posix);
llvm::sys::path::native(WrittenFile, Style);
OS << WrittenFile << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
}
}

OS << (Policy.MSVCFormatting ? '\'' : ')');
}

void TagDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
DeclarationName Name = getDeclName();
// If the name is supposed to have an identifier but does not have one, then
// the tag is anonymous and we should print it differently.
if (Name.isIdentifier() && !Name.getAsIdentifierInfo()) {
// If the caller wanted to print a qualified name, they've already printed
// the scope. And if the caller doesn't want that, the scope information
// is already printed as part of the type.
PrintingPolicy Copy(Policy);
Copy.SuppressScope = true;
QualType(getASTContext().getCanonicalTagType(this)).print(OS, Copy);
printAnonymousTagDecl(OS, Policy);

return;
}

// Otherwise, do the normal printing.
Name.print(OS, Policy);
}
Expand Down
61 changes: 13 additions & 48 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeBase.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/ExceptionSpecificationType.h"
Expand Down Expand Up @@ -1518,18 +1519,19 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
return;
}

bool HasKindDecoration = false;

bool PrintedKindDecoration = false;
if (T->isCanonicalUnqualified()) {
if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) {
HasKindDecoration = true;
PrintedKindDecoration = true;
OS << D->getKindName();
OS << ' ';
}
} else {
OS << TypeWithKeyword::getKeywordName(T->getKeyword());
if (T->getKeyword() != ElaboratedTypeKeyword::None)
if (T->getKeyword() != ElaboratedTypeKeyword::None) {
PrintedKindDecoration = true;
OS << ' ';
}
}

if (!Policy.FullyQualifiedName && !T->isCanonicalUnqualified()) {
Expand All @@ -1543,53 +1545,16 @@ void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {

if (const IdentifierInfo *II = D->getIdentifier())
OS << II->getName();
else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) {
assert(Typedef->getIdentifier() && "Typedef without identifier?");
OS << Typedef->getIdentifier()->getName();
} else {
// Make an unambiguous representation for anonymous types, e.g.
// (anonymous enum at /usr/include/string.h:120:9)
OS << (Policy.MSVCFormatting ? '`' : '(');

if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
OS << "lambda";
HasKindDecoration = true;
} else if ((isa<RecordDecl>(D) && cast<RecordDecl>(D)->isAnonymousStructOrUnion())) {
OS << "anonymous";
} else {
OS << "unnamed";
}
else {
clang::PrintingPolicy Copy(Policy);

if (Policy.AnonymousTagLocations) {
// Suppress the redundant tag keyword if we just printed one.
// We don't have to worry about ElaboratedTypes here because you can't
// refer to an anonymous type with one.
if (!HasKindDecoration)
OS << " " << D->getKindName();

PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc(
D->getLocation());
if (PLoc.isValid()) {
OS << " at ";
StringRef File = PLoc.getFilename();
llvm::SmallString<1024> WrittenFile(File);
if (auto *Callbacks = Policy.Callbacks)
WrittenFile = Callbacks->remapPath(File);
// Fix inconsistent path separator created by
// clang::DirectoryLookup::LookupFile when the file path is relative
// path.
llvm::sys::path::Style Style =
llvm::sys::path::is_absolute(WrittenFile)
? llvm::sys::path::Style::native
: (Policy.MSVCFormatting
? llvm::sys::path::Style::windows_backslash
: llvm::sys::path::Style::posix);
llvm::sys::path::native(WrittenFile, Style);
OS << WrittenFile << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
}
// Suppress the redundant tag keyword if we just printed one.
if (PrintedKindDecoration) {
Copy.SuppressTagKeywordInAnonymousTagNames = true;
Copy.SuppressTagKeyword = true;
}

OS << (Policy.MSVCFormatting ? '\'' : ')');
D->printName(OS, Copy);
}

// If this is a class template specialization, print the template
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TypeBase.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/LLVM.h"
#include "clang/Lex/Lexer.h"
Expand Down Expand Up @@ -514,7 +515,14 @@ static StringRef getNodeName(const RecordDecl &Node,
return Node.getName();
}
Scratch.clear();
return ("(anonymous " + Node.getKindName() + ")").toStringRef(Scratch);

llvm::raw_svector_ostream OS(Scratch);

PrintingPolicy Copy(Node.getASTContext().getPrintingPolicy());
Copy.AnonymousTagLocations = false;
Node.printName(OS, Copy);

return OS.str();
}

static StringRef getNodeName(const NamespaceDecl &Node,
Expand Down
4 changes: 2 additions & 2 deletions clang/test/AST/HLSL/cbuffer.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,15 @@ cbuffer CB {
// CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
RWBuffer<float> f;
} s9;
// CHECK: VarDecl {{.*}} s9 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:[[# @LINE - 8]]:3
// CHECK: VarDecl {{.*}} s9 'hlsl_constant struct (unnamed at {{.*}}cbuffer.hlsl:[[# @LINE - 8]]:3
// CHECK: CXXRecordDecl {{.*}} struct definition
struct {
// CHECK: FieldDecl {{.*}} g 'float'
float g;
// CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
RWBuffer<float> f;
} s10;
// CHECK: VarDecl {{.*}} s10 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:[[# @LINE - 6]]:3
// CHECK: VarDecl {{.*}} s10 'hlsl_constant struct (unnamed at {{.*}}cbuffer.hlsl:[[# @LINE - 6]]:3
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_anon definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} e 'float'
Expand Down
8 changes: 4 additions & 4 deletions clang/test/AST/ast-dump-decl-json.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ void testParmVarDecl(int TestParmVarDecl);
// CHECK-NEXT: },
// CHECK-NEXT: "name": "e",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "enum (unnamed enum at {{.*}}:31:3)"
// CHECK-NEXT: "qualType": "enum (unnamed at {{.*}}:31:3)"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
Expand Down Expand Up @@ -776,7 +776,7 @@ void testParmVarDecl(int TestParmVarDecl);
// CHECK-NEXT: },
// CHECK-NEXT: "name": "testRecordDeclAnon1",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "struct (unnamed struct at {{.*}}:46:3)"
// CHECK-NEXT: "qualType": "struct (unnamed at {{.*}}:46:3)"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
Expand Down Expand Up @@ -1150,7 +1150,7 @@ void testParmVarDecl(int TestParmVarDecl);
// CHECK-NEXT: "name": "TestFunctionDecl",
// CHECK-NEXT: "mangledName": "TestFunctionDecl",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "int (int, enum (unnamed enum at {{.*}}:69:29))"
// CHECK-NEXT: "qualType": "int (int, enum (unnamed at {{.*}}:69:29))"
// CHECK-NEXT: },
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
Expand Down Expand Up @@ -1202,7 +1202,7 @@ void testParmVarDecl(int TestParmVarDecl);
// CHECK-NEXT: },
// CHECK-NEXT: "name": "y",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "enum (unnamed enum at {{.*}}:69:29)"
// CHECK-NEXT: "qualType": "enum (unnamed at {{.*}}:69:29)"
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: {
Expand Down
4 changes: 2 additions & 2 deletions clang/test/AST/ast-dump-records-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ struct Derived6 : virtual public Bases... {
// CHECK-NEXT: },
// CHECK-NEXT: "name": "b",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "struct (unnamed struct at {{.*}}:16:3)"
// CHECK-NEXT: "qualType": "struct (unnamed at {{.*}}:16:3)"
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: {
Expand Down Expand Up @@ -2071,7 +2071,7 @@ struct Derived6 : virtual public Bases... {
// CHECK-NEXT: },
// CHECK-NEXT: "name": "b",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "struct (unnamed struct at {{.*}}:50:3)"
// CHECK-NEXT: "qualType": "struct (unnamed at {{.*}}:50:3)"
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: {
Expand Down
Loading
Loading