Skip to content

Commit 17de215

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

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
@@ -302,6 +302,14 @@ class PointerVariableConstraint : public ConstraintVariable {
302302
static PointerVariableConstraint *
303303
derefPVConstraint(PointerVariableConstraint *PVC);
304304

305+
// Utility used by the constructor to obtain a string representation of a
306+
// declaration's base type. To preserve macros, this we first try to take
307+
// the type directly from source code. Where that is not possible, the type
308+
// is regenerated from the type in the clang AST.
309+
static std::string extractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
310+
QualType QT, const Type *Ty,
311+
const ASTContext &C, ProgramInfo &Info);
312+
305313
private:
306314
std::string BaseType;
307315
CAtoms Vars;
@@ -339,14 +347,6 @@ class PointerVariableConstraint : public ConstraintVariable {
339347
void addArrayAnnotations(std::stack<std::string> &ConstArrs,
340348
std::deque<std::string> &EndStrs) const;
341349

342-
// Utility used by the constructor to obtain a string representation of a
343-
// declaration's base type. To preserve macros, this we first try to take
344-
// the type directly from source code. Where that is not possible, the type
345-
// is regenerated from the type in the clang AST.
346-
static std::string extractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
347-
QualType QT, const Type *Ty,
348-
const ASTContext &C, ProgramInfo &Info);
349-
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
352352
// 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
@@ -106,6 +106,15 @@ class FunctionDeclReplacement
106106

107107
typedef std::map<Decl *, DeclReplacement *> RSet;
108108

109+
// Generate a string for the declaration that includes the name, type, and
110+
// storage qualifier (if any) but not a trailing semicolon. Honors names
111+
// assigned to unnamed structs by 3C. Used by DeclRewriter::rewriteMultiDecl for
112+
// variables that don't have a replacement and by StructVariableInitializer
113+
// (which appends an initializer).
114+
std::string mkStringForDeclWithUnchangedType(DeclaratorDecl *DD,
115+
ASTContext &Context,
116+
ProgramInfo &Info);
117+
109118
// This class is used to figure out which global variables are part of
110119
// multi-variable declarations. For local variables, all variables in a single
111120
// 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
@@ -402,36 +402,27 @@ void DeclRewriter::rewriteMultiDecl(DeclReplacement *N, RSet &ToRewrite,
402402
// When the type hasn't changed, we still need to insert the original
403403
// type for the variable.
404404

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

424420
// Do the replacement. PrevEnd is setup to be the source location of the
425421
// comma after the previous declaration in the multi-decl. getEndLoc is
426422
// either the end of the declaration or just before the initializer if
427423
// one is present.
428-
SourceRange SR(PrevEnd, DL->getEndLoc());
429-
rewriteSourceRange(R, SR, DeclStream.str());
430-
431-
// Undo prior trickery. This need to happen so that the PSL for the decl
432-
// is not changed since the PSL is used as a map key in a few places.
433-
if (VD && Init)
434-
VD->setInit(Init);
424+
SourceRange SR(PrevEnd, DD->DeclaratorDecl::getSourceRange().getEnd());
425+
rewriteSourceRange(R, SR, NewDeclStr);
435426
}
436427
}
437428

clang/lib/3C/RewriteUtils.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,33 @@
2121
using namespace llvm;
2222
using namespace clang;
2323

24+
std::string mkStringForDeclWithUnchangedType(DeclaratorDecl *DD,
25+
ASTContext &Context,
26+
ProgramInfo &Info) {
27+
std::string TypeWithName;
28+
if (isPtrOrArrayType(DD->getType())) {
29+
CVarOption CVO = Info.getVariable(DD, &Context);
30+
assert(CVO.hasValue() &&
31+
"Missing ConstraintVariable for unchanged variable in multi-decl");
32+
TypeWithName = CVO.getValue().mkString(Info.getConstraints());
33+
} else {
34+
// In this case, the type should just be the base type except for top-level
35+
// qualifiers. (REVIEW: Can we verify that somehow?)
36+
// PointerVariableConstraint::extractBaseType doesn't include qualifiers,
37+
// but since we know the type is not a pointer, it should be safe to just
38+
// add any qualifiers at the beginning of the string.
39+
std::string QualifierPrefix = DD->getType().getQualifiers().getAsString();
40+
if (!QualifierPrefix.empty())
41+
QualifierPrefix += " ";
42+
TypeWithName = QualifierPrefix +
43+
PointerVariableConstraint::extractBaseType(
44+
DD, DD->getTypeSourceInfo(), DD->getType(),
45+
DD->getType().getTypePtr(), Context, Info) +
46+
" " + std::string(DD->getName());
47+
}
48+
return getStorageQualifierString(DD) + TypeWithName;
49+
}
50+
2451
void GlobalVariableGroups::addGlobalDecl(Decl *VD, std::vector<Decl *> *VDVec) {
2552
if (VD && GlobVarGroups.find(VD) == GlobVarGroups.end()) {
2653
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(
6865
std::make_pair(VD, new VarDeclReplacement(VD, S, ToReplace)));
6966
}

0 commit comments

Comments
 (0)