1 //===----------------------------------------------------------------------===//
2 //
3 // Copyright (c) 2012, 2013, 2014, 2015 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 "UnifyFunctionDecl.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 
23 using namespace clang;
24 
25 static const char *DescriptionMsg =
26 "If a function is declared as static, make its definition \
27 as static as well, and remove the declaration. \n";
28 
29 static RegisterTransformation<UnifyFunctionDecl>
30          Trans("unify-function-decl", DescriptionMsg);
31 
Initialize(ASTContext & context)32 void UnifyFunctionDecl::Initialize(ASTContext &context)
33 {
34   Transformation::Initialize(context);
35 }
36 
HandleTopLevelDecl(DeclGroupRef D)37 bool UnifyFunctionDecl::HandleTopLevelDecl(DeclGroupRef D)
38 {
39   for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
40     const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I);
41     if (!FD)
42       return true;
43 
44     if (isInIncludedFile(FD))
45       return true;
46 
47     if (!FD->hasBody())
48       return true;
49 
50     const FunctionDecl *CanonicalFD = FD->getCanonicalDecl();
51     if (VisitedFunctionDecls.count(CanonicalFD))
52       return true;
53 
54     VisitedFunctionDecls.insert(CanonicalFD);
55   }
56   return true;
57 }
58 
HandleTranslationUnit(ASTContext & Ctx)59 void UnifyFunctionDecl::HandleTranslationUnit(ASTContext &Ctx)
60 {
61   doAnalysis();
62 
63   if (QueryInstanceOnly)
64     return;
65 
66   if (TransformationCounter > ValidInstanceNum) {
67     TransError = TransMaxInstanceError;
68     return;
69   }
70 
71   Ctx.getDiagnostics().setSuppressAllDiagnostics(false);
72 
73   TransAssert(TheFunctionDecl && "NULL TheFunctionDecl!");
74   TransAssert(TheFunctionDef && "NULL TheFunctionDef!");
75 
76   doRewriting();
77 
78   if (Ctx.getDiagnostics().hasErrorOccurred() ||
79       Ctx.getDiagnostics().hasFatalErrorOccurred())
80     TransError = TransInternalError;
81 }
82 
doAnalysis(void)83 void UnifyFunctionDecl::doAnalysis(void)
84 {
85   for (FunctionDeclSet::iterator I = VisitedFunctionDecls.begin(),
86        E = VisitedFunctionDecls.end(); I != E; ++I) {
87 
88     const FunctionDecl *FDDef = NULL;
89     const FunctionDecl *FDDecl = NULL;
90     const FunctionDecl *CanonicalFD = (*I);
91     const FunctionDecl *FirstFD = CanonicalFD->getCanonicalDecl();
92 
93     FunctionDecl::redecl_iterator RI = FirstFD->redecls_begin();
94     if (FirstFD->getSourceRange().isInvalid())
95       continue;
96     ++RI;
97     if (RI == FirstFD->redecls_end())
98       continue;
99 
100     const FunctionDecl *SecondFD = (*RI);
101     if (SecondFD->getSourceRange().isInvalid())
102       continue;
103     if (FirstFD->isThisDeclarationADefinition()) {
104       FDDef = FirstFD;
105       TransAssert(!SecondFD->isThisDeclarationADefinition() &&
106                   "Duplicated Definition!");
107       FDDecl = SecondFD;
108     }
109     else if (SecondFD->isThisDeclarationADefinition()) {
110       FDDef = SecondFD;
111       TransAssert(!FirstFD->isThisDeclarationADefinition() &&
112                   "Duplicated Definition!");
113       FDDecl = FirstFD;
114     }
115     else {
116       continue;
117     }
118 
119     if (!hasStaticKeyword(FDDecl) || hasStaticKeyword(FDDef))
120       continue;
121 
122     ValidInstanceNum++;
123     if (TransformationCounter == ValidInstanceNum) {
124       TheFunctionDef = FDDef;
125       TheFunctionDecl = FDDecl;
126     }
127   }
128 }
129 
hasStaticKeyword(const FunctionDecl * FD)130 bool UnifyFunctionDecl::hasStaticKeyword(const FunctionDecl *FD)
131 {
132   SourceRange FDRange = FD->getSourceRange();
133   SourceLocation StartLoc = FDRange.getBegin();
134   SourceLocation EndLoc = FD->getLocation();
135 
136   const char *StartBuf = SrcManager->getCharacterData(StartLoc);
137   const char *EndBuf = SrcManager->getCharacterData(EndLoc);
138   std::string Str;
139   if (StartBuf == EndBuf)
140     return false;
141 
142   TransAssert(StartBuf < EndBuf);
143   size_t Off = EndBuf - StartBuf;
144   Str.assign(StartBuf, Off);
145 
146   size_t Pos = Str.find("static");
147   return (Pos != std::string::npos);
148 }
149 
doRewriting(void)150 void UnifyFunctionDecl::doRewriting(void)
151 {
152   SourceRange FDDefRange = TheFunctionDef->getSourceRange();
153   SourceLocation StartLoc = FDDefRange.getBegin();
154   TheRewriter.InsertTextBefore(StartLoc, "static ");
155 
156   std::string TmpStr;
157   RewriteHelper->getFunctionDeclStrAndRemove(TheFunctionDecl, TmpStr);
158 }
159 
~UnifyFunctionDecl(void)160 UnifyFunctionDecl::~UnifyFunctionDecl(void)
161 {
162   // Nothing to do
163 }
164 
165