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