Skip to content

Commit 4263f16

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

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
@@ -278,6 +278,14 @@ class PointerVariableConstraint : public ConstraintVariable {
278278
static PointerVariableConstraint *
279279
derefPVConstraint(PointerVariableConstraint *PVC);
280280

281+
// Utility used by the constructor to obtain a string representation of a
282+
// declaration's base type. To preserve macros, this we first try to take
283+
// the type directly from source code. Where that is not possible, the type
284+
// is regenerated from the type in the clang AST.
285+
static std::string extractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
286+
QualType QT, const Type *Ty,
287+
const ASTContext &C, ProgramInfo &Info);
288+
281289
private:
282290
std::string BaseType;
283291
CAtoms Vars;
@@ -315,14 +323,6 @@ class PointerVariableConstraint : public ConstraintVariable {
315323
void addArrayAnnotations(std::stack<std::string> &ConstArrs,
316324
std::deque<std::string> &EndStrs) const;
317325

318-
// Utility used by the constructor to obtain a string representation of a
319-
// declaration's base type. To preserve macros, this we first try to take
320-
// the type directly from source code. Where that is not possible, the type
321-
// is regenerated from the type in the clang AST.
322-
static std::string extractBaseType(DeclaratorDecl *D, TypeSourceInfo *TSI,
323-
QualType QT, const Type *Ty,
324-
const ASTContext &C, ProgramInfo &Info);
325-
326326
// Try to extract string representation of the base type for a declaration
327327
// from the source code. If the base type cannot be extracted from source, an
328328
// 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
@@ -108,6 +108,15 @@ class FunctionDeclReplacement
108108

109109
typedef std::map<Decl *, DeclReplacement *> RSet;
110110

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

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

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

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)