Skip to content

Commit 1a7854e

Browse files
Get the correct form of the base type for multi-decl vars with unchanged
types.
1 parent bac92a1 commit 1a7854e

File tree

5 files changed

+63
-39
lines changed

5 files changed

+63
-39
lines changed

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,14 @@ class PointerVariableConstraint : public ConstraintVariable {
258258
static PointerVariableConstraint *
259259
derefPVConstraint(PointerVariableConstraint *PVC);
260260

261+
// Utility used by the constructor to obtain a string representation of a
262+
// declaration's base type. To preserve macros, this we first try to take
263+
// the type directly from source code. Where that is not possible, the type
264+
// is regenerated from the type in the clang AST.
265+
static std::string extractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
266+
QualType QT, const Type *Ty,
267+
const ASTContext &C, ProgramInfo &Info);
268+
261269
private:
262270
std::string BaseType;
263271
CAtoms Vars;
@@ -295,14 +303,6 @@ class PointerVariableConstraint : public ConstraintVariable {
295303
void addArrayAnnotations(std::stack<std::string> &ConstArrs,
296304
std::deque<std::string> &EndStrs) const;
297305

298-
// Utility used by the constructor to obtain a string representation of a
299-
// declaration's base type. To preserve macros, this we first try to take
300-
// the type directly from source code. Where that is not possible, the type
301-
// is regenerated from the type in the clang AST.
302-
static std::string extractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
303-
QualType QT, const Type *Ty,
304-
const ASTContext &C, ProgramInfo &Info);
305-
306306
// Try to extract string representation of the base type for a declaration
307307
// from the source code. If the base type cannot be extracted from source, an
308308
// empty string is returned instead.

clang/include/clang/3C/RewriteUtils.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ class DComp {
142142

143143
typedef std::set<DeclReplacement *, DComp> RSet;
144144

145+
// Generate a string for the declaration that includes the name, type, and
146+
// storage qualifier (if any) but not a trailing semicolon. Honors names
147+
// assigned to unnamed structs by 3C. Used by DeclRewriter::rewriteMultiDecl for
148+
// variables that don't have a replacement and by StructVariableInitializer
149+
// (which appends an initializer).
150+
std::string mkStringForDeclWithUnchangedType(DeclaratorDecl *DD,
151+
ASTContext &Context,
152+
ProgramInfo &Info);
153+
145154
// This class is used to figure out which global variables are part of
146155
// multi-variable declarations. For local variables, all variables in a single
147156
// multi declaration are grouped together in a DeclStmt object. This is not the

clang/lib/3C/DeclRewriter.cpp

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -419,36 +419,27 @@ void DeclRewriter::rewriteMultiDecl(DeclReplacement *N, RSet &ToRewrite,
419419
// When the type hasn't changed, we still need to insert the original
420420
// type for the variable.
421421

422-
// This is a bit of trickery needed to get a string representation of
423-
// the declaration without the initializer. We don't want to rewrite to
424-
// initializer because this causes problems when rewriting casts and
425-
// generic function calls later on. (issue 267)
426-
auto *VD = dyn_cast<VarDecl>(DL);
427-
Expr *Init = nullptr;
428-
if (VD && VD->hasInit()) {
429-
Init = VD->getInit();
430-
VD->setInit(nullptr);
431-
}
432-
433-
// Dump the declaration (without the initializer) to a string. Printing
434-
// the AST node gives the full declaration including the base type which
435-
// is not present in the multi-decl source code.
436-
std::string DeclStr = "";
437-
raw_string_ostream DeclStream(DeclStr);
438-
DL->print(DeclStream);
439-
assert("Original decl string empty." && !DeclStream.str().empty());
422+
// Note: rewriteMultiDecl is currently called only by
423+
// rewriteFieldOrVarDecl with VarDecls or FieldDecls, and DeclaratorDecl
424+
// is a superclass of both. When we add support for typedef multi-decls,
425+
// we'll need to change this code.
426+
DeclaratorDecl *DD = cast<DeclaratorDecl>(DL);
427+
std::string NewDeclStr = mkStringForDeclWithUnchangedType(DD, A, Info);
428+
429+
// If the variable has an initializer, we want this rewrite to end
430+
// before the initializer to avoid interfering with any other rewrites
431+
// that 3C needs to make inside the initializer expression (issue 267).
432+
// VarDecl's implementation of the getSourceRange virtual method
433+
// includes the initializer, but we can manually call DeclaratorDecl's
434+
// implementation, which excludes the initializer.
435+
SourceLocation EndLoc = DD->DeclaratorDecl::getSourceRange().getEnd();
440436

441437
// Do the replacement. PrevEnd is setup to be the source location of the
442438
// comma after the previous declaration in the multi-decl. getEndLoc is
443439
// either the end of the declaration or just before the initializer if
444440
// one is present.
445-
SourceRange SR(PrevEnd, DL->getEndLoc());
446-
rewriteSourceRange(R, SR, DeclStream.str());
447-
448-
// Undo prior trickery. This need to happen so that the PSL for the decl
449-
// is not changed since the PSL is used as a map key in a few places.
450-
if (VD && Init)
451-
VD->setInit(Init);
441+
SourceRange SR(PrevEnd, DD->DeclaratorDecl::getSourceRange().getEnd());
442+
rewriteSourceRange(R, SR, NewDeclStr);
452443
}
453444
}
454445

clang/lib/3C/RewriteUtils.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,33 @@ bool DComp::operator()(DeclReplacement *Lhs, DeclReplacement *Rhs) const {
8888
return SM.isBeforeInTranslationUnit(X2, Y1);
8989
}
9090

91+
std::string mkStringForDeclWithUnchangedType(DeclaratorDecl *DD,
92+
ASTContext &Context,
93+
ProgramInfo &Info) {
94+
std::string TypeWithName;
95+
if (isPtrOrArrayType(DD->getType())) {
96+
CVarOption CVO = Info.getVariable(DD, &Context);
97+
assert(CVO.hasValue() &&
98+
"Missing ConstraintVariable for unchanged variable in multi-decl");
99+
TypeWithName = CVO.getValue().mkString(Info.getConstraints());
100+
} else {
101+
// In this case, the type should just be the base type except for top-level
102+
// qualifiers. (REVIEW: Can we verify that somehow?)
103+
// PointerVariableConstraint::extractBaseType doesn't include qualifiers,
104+
// but since we know the type is not a pointer, it should be safe to just
105+
// add any qualifiers at the beginning of the string.
106+
std::string QualifierPrefix = DD->getType().getQualifiers().getAsString();
107+
if (!QualifierPrefix.empty())
108+
QualifierPrefix += " ";
109+
TypeWithName = QualifierPrefix +
110+
PointerVariableConstraint::extractBaseType(
111+
DD, DD->getTypeSourceInfo(), DD->getType(),
112+
DD->getType().getTypePtr(), Context, Info) +
113+
" " + std::string(DD->getName());
114+
}
115+
return getStorageQualifierString(DD) + TypeWithName;
116+
}
117+
91118
void GlobalVariableGroups::addGlobalDecl(Decl *VD, std::vector<Decl *> *VDVec) {
92119
if (VD && GlobVarGroups.find(VD) == GlobVarGroups.end()) {
93120
if (VDVec == nullptr)

clang/lib/3C/StructInit.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "clang/3C/StructInit.h"
1313
#include "clang/3C/MappingVisitor.h"
14+
#include "clang/3C/RewriteUtils.h"
1415
#include "clang/Tooling/Transformer/SourceCode.h"
1516
#include <sstream>
1617

@@ -58,12 +59,8 @@ void StructVariableInitializer::insertVarDecl(VarDecl *VD, DeclStmt *S) {
5859
bool IsVarExtern = VD->getStorageClass() == StorageClass::SC_Extern;
5960
if (!IsVarExtern && !VD->hasInit() && hasCheckedMembers(VD)) {
6061
// Create replacement declaration text with an initializer.
61-
const clang::Type *Ty = VD->getType().getTypePtr();
62-
std::string TQ = VD->getType().getQualifiers().getAsString();
63-
if (!TQ.empty())
64-
TQ += " ";
65-
std::string ToReplace = getStorageQualifierString(VD) + TQ + tyToStr(Ty) +
66-
" " + VD->getName().str() + " = {}";
62+
std::string ToReplace =
63+
mkStringForDeclWithUnchangedType(VD, *Context, I) + " = {}";
6764
RewriteThese.insert(new VarDeclReplacement(VD, S, ToReplace));
6865
}
6966
}

0 commit comments

Comments
 (0)