Skip to content

Commit dcf9da0

Browse files
Assign record names and use them in extractBaseType.
1 parent b7a119a commit dcf9da0

File tree

6 files changed

+104
-3
lines changed

6 files changed

+104
-3
lines changed

clang/include/clang/3C/ConstraintVariables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ class PointerVariableConstraint : public ConstraintVariable {
345345
// is regenerated from the type in the clang AST.
346346
static std::string extractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
347347
QualType QT, const Type *Ty,
348-
const ASTContext &C);
348+
const ASTContext &C, ProgramInfo &Info);
349349

350350
// Try to extract string representation of the base type for a declaration
351351
// from the source code. If the base type cannot be extracted from source, an

clang/include/clang/3C/ProgramInfo.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,23 @@ class ProgramInfo : public ProgramVariableAdder {
178178
void registerTranslationUnits(
179179
const std::vector<std::unique_ptr<clang::ASTUnit>> &ASTs);
180180

181+
// Members related to automatic name generation for unnamed inline
182+
// RecordDecls:
183+
184+
// Set of RecordDecl names already used at least once in the program, so we
185+
// can avoid colliding with them.
186+
std::set<std::string> UsedRecordNames;
187+
188+
// Map from PSL of an originally unnamed RecordDecl to the name we assigned to
189+
// it, so we can ensure that names are assigned consistently when 3C naively
190+
// rewrites the same header file multiple times as part of different
191+
// translation units (see
192+
// https://github.com/correctcomputation/checkedc-clang/issues/374#issuecomment-804283984).
193+
std::map<PersistentSourceLoc, std::string> AssignedRecordNames;
194+
195+
void findUsedRecordNames(DeclContext *DC, ASTContext &Context);
196+
void nameUnnamedRecords(DeclContext *DC, ASTContext &Context);
197+
181198
private:
182199
// List of constraint variables for declarations, indexed by their location in
183200
// the source. This information persists across invocations of the constraint

clang/lib/3C/3C.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,13 @@ bool _3CInterface::addVariables() {
522522

523523
std::lock_guard<std::mutex> Lock(InterfaceMutex);
524524

525+
// Unnamed RecordDecl stuff.
526+
// REVIEW: Move to a separate _3CInterface pass?
527+
for (auto &TU : ASTs)
528+
GlobalProgramInfo.findUsedRecordNames(TU->getASTContext().getTranslationUnitDecl(), TU->getASTContext());
529+
for (auto &TU : ASTs)
530+
GlobalProgramInfo.nameUnnamedRecords(TU->getASTContext().getTranslationUnitDecl(), TU->getASTContext());
531+
525532
// 1. Add Variables.
526533
VariableAdderConsumer VA = VariableAdderConsumer(GlobalProgramInfo, nullptr);
527534
for (auto &TU : ASTs)

clang/lib/3C/ConstraintVariables.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ PointerVariableConstraint::PointerVariableConstraint(
522522
TSInfo);
523523

524524
// Get a string representing the type without pointer and array indirection.
525-
BaseType = extractBaseType(D, TSInfo, QT, Ty, C);
525+
BaseType = extractBaseType(D, TSInfo, QT, Ty, C, I);
526526

527527
// check if the type is some depth of pointers to void
528528
// TODO: is this what the field should mean? do we want to include other
@@ -606,7 +606,25 @@ std::string PointerVariableConstraint::extractBaseType(DeclaratorDecl *D,
606606
TypeSourceInfo *TSI,
607607
QualType QT,
608608
const Type *Ty,
609-
const ASTContext &C) {
609+
const ASTContext &C,
610+
ProgramInfo &Info) {
611+
// If the base type is an unnamed RecordType to which we assigned a name, use
612+
// that name.
613+
const Type *UnelaboratedTy = Ty;
614+
if (const ElaboratedType *ETy = dyn_cast<ElaboratedType>(Ty))
615+
UnelaboratedTy = ETy->getNamedType().getTypePtr();
616+
if (const RecordType *RTy = dyn_cast<RecordType>(UnelaboratedTy)) {
617+
RecordDecl *RD = RTy->getDecl();
618+
if (RD->getName().empty()) {
619+
// REVIEW: Can this const_cast be avoided?
620+
PersistentSourceLoc PSL = PersistentSourceLoc::mkPSL(RD, const_cast<ASTContext &>(C));
621+
auto Iter = Info.AssignedRecordNames.find(PSL);
622+
if (Iter != Info.AssignedRecordNames.end())
623+
return std::string(RD->getKindName()) + " " + Iter->second;
624+
// XXX: Can we get here in writable code? We should have named all unnamed RecordDecls in writable code.
625+
}
626+
}
627+
610628
std::string BaseTypeStr = tryExtractBaseType(D, TSI, QT, Ty, C);
611629
// Fall back to rebuilding the base type based on type passed to constructor
612630
if (BaseTypeStr.empty())

clang/lib/3C/DeclRewriter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ void DeclRewriter::rewriteMultiDecl(DeclReplacement *N, RSet &ToRewrite,
369369
"no other decls?");
370370
rewriteSourceRange(R, CharSourceRange::getCharRange(
371371
SameLineDecls[1]->getBeginLoc(), DL->getBeginLoc()), "");
372+
// TODO: If the struct is unnamed, insert its assigned name.
372373
} else if (IsFirst) {
373374
// Rewriting the first declaration is easy. Nothing should change if its
374375
// type does not to be rewritten. When rewriting is required, it is

clang/lib/3C/ProgramInfo.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,3 +1162,61 @@ void ProgramInfo::registerTranslationUnits(
11621162
Idx++;
11631163
}
11641164
}
1165+
1166+
void ProgramInfo::findUsedRecordNames(DeclContext *DC, ASTContext &Context) {
1167+
// We do our own traversal via `decls` rather than using RecursiveASTVisitor.
1168+
// This has the advantage of visiting RecordDecls in function parameters,
1169+
// which RecursiveASTVisitor doesn't do by default, though using such
1170+
// RecordDecls is poor practice anyway.
1171+
for (Decl *D : DC->decls()) {
1172+
if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
1173+
if (!RD->getName().empty()) {
1174+
// There may be duplicate names if the same RecordDecl is seen in
1175+
// multiple translation units or different RecordDecls with the same
1176+
// name are used in different scopes. That is OK.
1177+
UsedRecordNames.insert(std::string(RD->getName()));
1178+
}
1179+
}
1180+
if (DeclContext *NestedDC = dyn_cast<DeclContext>(D)) {
1181+
findUsedRecordNames(NestedDC, Context);
1182+
}
1183+
}
1184+
}
1185+
1186+
void ProgramInfo::nameUnnamedRecords(DeclContext *DC, ASTContext &Context) {
1187+
for (Decl *D : DC->decls()) {
1188+
if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
1189+
if (RD->getName().empty() && !RD->isAnonymousStructOrUnion()) {
1190+
PersistentSourceLoc PSL = PersistentSourceLoc::mkPSL(RD, Context);
1191+
if (canWrite(PSL.getFileName()) && AssignedRecordNames.find(PSL) == AssignedRecordNames.end()) {
1192+
std::string Basename = "unnamed";
1193+
// Try to name the record after a variable (or, field, typedef, etc.)
1194+
// in the same multi-decl that uses the record as its base type.
1195+
// XXX: Are there cases in which the name would be used (e.g., not for
1196+
// flattened records) but a suitable variable doesn't exist?
1197+
// REVIEW: If, by this point, we have built a data structure linking
1198+
// together the RecordDecl and all variables in the multi-decl, we
1199+
// could consult it instead of doing this ad-hoc check.
1200+
NamedDecl *NextDecl = cast_or_null<NamedDecl>(RD->getNextDeclInContext());
1201+
if (NextDecl != nullptr && !NextDecl->getName().empty() &&
1202+
// XXX: Wanted: Analogue of isBeforeInTranslationUnit for `<=`.
1203+
!Context.getSourceManager().isBeforeInTranslationUnit(RD->getBeginLoc(), NextDecl->getBeginLoc())) {
1204+
Basename = std::string(NextDecl->getName());
1205+
}
1206+
std::string NewName;
1207+
for (int Num = 1; ; Num++) {
1208+
NewName = Basename + "_" + std::string(RD->getKindName()) + "_" + std::to_string(Num);
1209+
if (UsedRecordNames.find(NewName) == UsedRecordNames.end())
1210+
break;
1211+
}
1212+
AssignedRecordNames.insert(std::make_pair(PSL, NewName));
1213+
// Don't assign the same name to another originally unnamed record.
1214+
UsedRecordNames.insert(NewName);
1215+
}
1216+
}
1217+
}
1218+
if (DeclContext *NestedDC = dyn_cast<DeclContext>(D)) {
1219+
nameUnnamedRecords(NestedDC, Context);
1220+
}
1221+
}
1222+
}

0 commit comments

Comments
 (0)