//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "UnifyFunctionDecl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "If a function is declared as static, make its definition \ as static as well, and remove the declaration. \n"; static RegisterTransformation Trans("unify-function-decl", DescriptionMsg); void UnifyFunctionDecl::Initialize(ASTContext &context) { Transformation::Initialize(context); } bool UnifyFunctionDecl::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { const FunctionDecl *FD = dyn_cast(*I); if (!FD) return true; if (isInIncludedFile(FD)) return true; if (!FD->hasBody()) return true; const FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); if (VisitedFunctionDecls.count(CanonicalFD)) return true; VisitedFunctionDecls.insert(CanonicalFD); } return true; } void UnifyFunctionDecl::HandleTranslationUnit(ASTContext &Ctx) { doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFunctionDecl && "NULL TheFunctionDecl!"); TransAssert(TheFunctionDef && "NULL TheFunctionDef!"); doRewriting(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void UnifyFunctionDecl::doAnalysis(void) { for (FunctionDeclSet::iterator I = VisitedFunctionDecls.begin(), E = VisitedFunctionDecls.end(); I != E; ++I) { const FunctionDecl *FDDef = NULL; const FunctionDecl *FDDecl = NULL; const FunctionDecl *CanonicalFD = (*I); const FunctionDecl *FirstFD = CanonicalFD->getCanonicalDecl(); FunctionDecl::redecl_iterator RI = FirstFD->redecls_begin(); if (FirstFD->getSourceRange().isInvalid()) continue; ++RI; if (RI == FirstFD->redecls_end()) continue; const FunctionDecl *SecondFD = (*RI); if (SecondFD->getSourceRange().isInvalid()) continue; if (FirstFD->isThisDeclarationADefinition()) { FDDef = FirstFD; TransAssert(!SecondFD->isThisDeclarationADefinition() && "Duplicated Definition!"); FDDecl = SecondFD; } else if (SecondFD->isThisDeclarationADefinition()) { FDDef = SecondFD; TransAssert(!FirstFD->isThisDeclarationADefinition() && "Duplicated Definition!"); FDDecl = FirstFD; } else { continue; } if (!hasStaticKeyword(FDDecl) || hasStaticKeyword(FDDef)) continue; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) { TheFunctionDef = FDDef; TheFunctionDecl = FDDecl; } } } bool UnifyFunctionDecl::hasStaticKeyword(const FunctionDecl *FD) { SourceRange FDRange = FD->getSourceRange(); SourceLocation StartLoc = FDRange.getBegin(); SourceLocation EndLoc = FD->getLocation(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); const char *EndBuf = SrcManager->getCharacterData(EndLoc); std::string Str; if (StartBuf == EndBuf) return false; TransAssert(StartBuf < EndBuf); size_t Off = EndBuf - StartBuf; Str.assign(StartBuf, Off); size_t Pos = Str.find("static"); return (Pos != std::string::npos); } void UnifyFunctionDecl::doRewriting(void) { SourceRange FDDefRange = TheFunctionDef->getSourceRange(); SourceLocation StartLoc = FDDefRange.getBegin(); TheRewriter.InsertTextBefore(StartLoc, "static "); std::string TmpStr; RewriteHelper->getFunctionDeclStrAndRemove(TheFunctionDecl, TmpStr); } UnifyFunctionDecl::~UnifyFunctionDecl(void) { // Nothing to do }