1 //===----------------------------------------------------------------------===//
2 //
3 // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2019 The University of Utah
4 // All rights reserved.
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See the file COPYING for details.
8 //
9 //===----------------------------------------------------------------------===//
10
11 #if HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 #include "TemplateNonTypeArgToInt.h"
16
17 #include "clang/AST/RecursiveASTVisitor.h"
18 #include "clang/AST/ASTContext.h"
19 #include "clang/Basic/SourceManager.h"
20
21 #include "TransformationManager.h"
22 #include "CommonTemplateArgumentVisitor.h"
23
24 using namespace clang;
25 using namespace clang_delta_common_visitor;
26
27 static const char *DescriptionMsg =
28 "This pass tries to replace a template non-type argument \
29 wth an integer (if its type is compatible) \n";
30
31 static RegisterTransformation<TemplateNonTypeArgToInt>
32 Trans("template-non-type-arg-to-int", DescriptionMsg);
33
34 class TemplateNonTypeArgToIntArgCollector : public
35 RecursiveASTVisitor<TemplateNonTypeArgToIntArgCollector> {
36
37 public:
TemplateNonTypeArgToIntArgCollector(TemplateNonTypeArgToInt * Instance)38 explicit TemplateNonTypeArgToIntArgCollector(
39 TemplateNonTypeArgToInt *Instance)
40 : ConsumerInstance(Instance)
41 { }
42
43 bool VisitClassTemplateDecl(ClassTemplateDecl *D);
44
45 bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
46
47 private:
48 TemplateNonTypeArgToInt *ConsumerInstance;
49
50 };
51
VisitClassTemplateDecl(ClassTemplateDecl * D)52 bool TemplateNonTypeArgToIntArgCollector::VisitClassTemplateDecl(
53 ClassTemplateDecl *D)
54 {
55 if (D->isThisDeclarationADefinition())
56 ConsumerInstance->handleOneTemplateDecl(D);
57 return true;
58 }
59
VisitFunctionTemplateDecl(FunctionTemplateDecl * D)60 bool TemplateNonTypeArgToIntArgCollector::VisitFunctionTemplateDecl(
61 FunctionTemplateDecl *D)
62 {
63 if (D->isThisDeclarationADefinition())
64 ConsumerInstance->handleOneTemplateDecl(D);
65 return true;
66 }
67
68 class TemplateNonTypeArgToIntASTVisitor : public
69 CommonTemplateArgumentVisitor<TemplateNonTypeArgToIntASTVisitor,
70 TemplateNonTypeArgToInt> {
71
72 public:
TemplateNonTypeArgToIntASTVisitor(TemplateNonTypeArgToInt * Instance)73 explicit TemplateNonTypeArgToIntASTVisitor(
74 TemplateNonTypeArgToInt *Instance)
75 : CommonTemplateArgumentVisitor<TemplateNonTypeArgToIntASTVisitor,
76 TemplateNonTypeArgToInt>(Instance)
77 { }
78 };
79
Initialize(ASTContext & context)80 void TemplateNonTypeArgToInt::Initialize(ASTContext &context)
81 {
82 Transformation::Initialize(context);
83 CollectionVisitor = new TemplateNonTypeArgToIntASTVisitor(this);
84 ArgCollector = new TemplateNonTypeArgToIntArgCollector(this);
85 }
86
HandleTranslationUnit(ASTContext & Ctx)87 void TemplateNonTypeArgToInt::HandleTranslationUnit(ASTContext &Ctx)
88 {
89 if (TransformationManager::isCLangOpt() ||
90 TransformationManager::isOpenCLLangOpt()) {
91 ValidInstanceNum = 0;
92 }
93 else {
94 ArgCollector->TraverseDecl(Ctx.getTranslationUnitDecl());
95 CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl());
96 }
97
98 if (QueryInstanceOnly)
99 return;
100
101 if (TransformationCounter > ValidInstanceNum) {
102 TransError = TransMaxInstanceError;
103 return;
104 }
105
106 Ctx.getDiagnostics().setSuppressAllDiagnostics(false);
107 if (TheExpr) {
108 RewriteHelper->replaceExpr(TheExpr, IntString);
109 }
110 else if (TheValueDecl) {
111 RewriteHelper->replaceValueDecl(TheValueDecl,
112 "int " + TheValueDecl->getNameAsString());
113 }
114 else {
115 TransAssert(0 && "No valid targets!");
116 }
117
118 if (Ctx.getDiagnostics().hasErrorOccurred() ||
119 Ctx.getDiagnostics().hasFatalErrorOccurred())
120 TransError = TransInternalError;
121 }
122
isValidTemplateArgument(const TemplateArgument & Arg)123 bool TemplateNonTypeArgToInt::isValidTemplateArgument(
124 const TemplateArgument &Arg)
125 {
126 TemplateArgument::ArgKind K = Arg.getKind();
127 switch (K) {
128 case TemplateArgument::Declaration: {
129 return true;
130 }
131
132 case TemplateArgument::Expression: {
133 const Expr *E = Arg.getAsExpr()->IgnoreParenCasts();
134 if (dyn_cast<IntegerLiteral>(E) || dyn_cast<CXXBoolLiteralExpr>(E))
135 return false;
136 if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
137 UnaryOperator::Opcode Op = UO->getOpcode();
138 if((Op == UO_Minus) || (Op == UO_Plus))
139 return false;
140 }
141
142 return true;
143 }
144
145 default:
146 TransAssert(0 && "Unreachable code!");
147 return false;
148 }
149 TransAssert(0 && "Unreachable code!");
150 return false;
151 }
152
handleOneTemplateArgumentLoc(const TemplateArgumentLoc & ArgLoc)153 void TemplateNonTypeArgToInt::handleOneTemplateArgumentLoc(
154 const TemplateArgumentLoc &ArgLoc)
155 {
156 if (ArgLoc.getLocation().isInvalid())
157 return;
158 const TemplateArgument &Arg = ArgLoc.getArgument();
159
160 if (!isValidTemplateArgument(Arg))
161 return;
162
163 ValidInstanceNum++;
164 if (ValidInstanceNum == TransformationCounter) {
165 TheExpr = ArgLoc.getLocInfo().getAsExpr();
166 Expr::EvalResult Result;
167 if (!TheExpr->isValueDependent() &&
168 TheExpr->EvaluateAsInt(Result, *Context)) {
169 llvm::APSInt IVal = Result.Val.getInt();
170 IntString = IVal.toString(10);
171 }
172 }
173 }
174
handleTemplateArgumentLocs(const TemplateDecl * D,const TemplateArgumentLoc * TAL,unsigned NumArgs)175 void TemplateNonTypeArgToInt::handleTemplateArgumentLocs(
176 const TemplateDecl *D, const TemplateArgumentLoc *TAL, unsigned NumArgs)
177 {
178 TransAssert(D && "NULL TemplateDecl!");
179 if (!TAL)
180 return;
181 TemplateParameterIdxSet *ValidIdx =
182 DeclToParamIdx[dyn_cast<TemplateDecl>(D->getCanonicalDecl())];
183 if (!ValidIdx)
184 return;
185 for (unsigned I = 0; I < NumArgs; ++I) {
186 if (ValidIdx->count(I))
187 handleOneTemplateArgumentLoc(TAL[I]);
188 }
189 }
190
handleTemplateSpecializationTypeLoc(const TemplateSpecializationTypeLoc & TLoc)191 void TemplateNonTypeArgToInt::handleTemplateSpecializationTypeLoc(
192 const TemplateSpecializationTypeLoc &TLoc)
193 {
194 const Type *Ty = TLoc.getTypePtr();
195 const TemplateSpecializationType *TST =
196 Ty->getAs<TemplateSpecializationType>();
197 TemplateName TplName = TST->getTemplateName();
198 const TemplateDecl *TplD = TplName.getAsTemplateDecl();
199
200 TemplateParameterIdxSet *ValidIdx =
201 DeclToParamIdx[dyn_cast<TemplateDecl>(TplD->getCanonicalDecl())];
202 if (!ValidIdx)
203 return;
204 for (unsigned I = 0; I < TLoc.getNumArgs(); ++I) {
205 if (ValidIdx->count(I))
206 handleOneTemplateArgumentLoc(TLoc.getArgLoc(I));
207 }
208 }
209
isValidParameter(const NamedDecl * ND)210 bool TemplateNonTypeArgToInt::isValidParameter(const NamedDecl *ND)
211 {
212 const NonTypeTemplateParmDecl *NonTypeD =
213 dyn_cast<NonTypeTemplateParmDecl>(ND);
214 if (!NonTypeD)
215 return false;
216 // To avoid something like replacing int with int.
217 if (NonTypeD->getType().getAsString() == "int")
218 return false;
219 const Type *Ty = NonTypeD->getType().getTypePtr();
220 return Ty->isIntegerType();
221 }
222
handleOneTemplateDecl(const TemplateDecl * D)223 void TemplateNonTypeArgToInt::handleOneTemplateDecl(const TemplateDecl *D)
224 {
225 if (isInIncludedFile(D))
226 return;
227 TemplateParameterIdxSet *ValidParamIdx = new TemplateParameterIdxSet();
228 TemplateParameterList *TPList = D->getTemplateParameters();
229 unsigned Idx = 0;
230 for (TemplateParameterList::const_iterator I = TPList->begin(),
231 E = TPList->end(); I != E; ++I) {
232 const NamedDecl *ParamND = (*I);
233 if (isValidParameter(ParamND)) {
234 ValidParamIdx->insert(Idx);
235 if (const ValueDecl* ValD = dyn_cast<ValueDecl>(ParamND)) {
236 ++ValidInstanceNum;
237 if (ValidInstanceNum == TransformationCounter)
238 TheValueDecl = ValD;
239 }
240 }
241 Idx++;
242 }
243
244 TransAssert(!DeclToParamIdx[D] && "Duplicate TemplateDecl!");
245 DeclToParamIdx[dyn_cast<TemplateDecl>(D->getCanonicalDecl())] = ValidParamIdx;
246 }
247
~TemplateNonTypeArgToInt()248 TemplateNonTypeArgToInt::~TemplateNonTypeArgToInt()
249 {
250 delete CollectionVisitor;
251 delete ArgCollector;
252 }
253
254