forked from OSchip/llvm-project
[clang-move] Only move used helper declarations.
Summary: Instead of moving all the helper declarations blindly, this patch implements an AST-based call graph solution to make clang-move only move used helper decls to new.cc and remove unused decls in old.cc. Depends on D27674. Reviewers: ioeric Subscribers: mgorny, cfe-commits Differential Revision: https://reviews.llvm.org/D27673 llvm-svn: 290873
This commit is contained in:
parent
48d232d3e7
commit
3626516b14
|
@ -4,8 +4,10 @@ set(LLVM_LINK_COMPONENTS
|
|||
|
||||
add_clang_library(clangMove
|
||||
ClangMove.cpp
|
||||
HelperDeclRefGraph.cpp
|
||||
|
||||
LINK_LIBS
|
||||
clangAnalysis
|
||||
clangAST
|
||||
clangASTMatchers
|
||||
clangBasic
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangMove.h"
|
||||
#include "HelperDeclRefGraph.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Format/Format.h"
|
||||
|
@ -16,8 +17,11 @@
|
|||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
#include "clang/Tooling/Core/Replacement.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
#define DEBUG_TYPE "clang-move"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
|
@ -394,6 +398,25 @@ createInsertedReplacements(const std::vector<std::string> &Includes,
|
|||
clang::tooling::Replacement(FileName, 0, 0, NewCode));
|
||||
}
|
||||
|
||||
// Return a set of all decls which are used/referenced by the given Decls.
|
||||
// Specically, given a class member declaration, this method will return all
|
||||
// decls which are used by the whole class.
|
||||
llvm::DenseSet<const Decl *>
|
||||
getUsedDecls(const HelperDeclRefGraph *RG,
|
||||
const std::vector<const NamedDecl *> &Decls) {
|
||||
assert(RG);
|
||||
llvm::DenseSet<const CallGraphNode *> Nodes;
|
||||
for (const auto *D : Decls) {
|
||||
auto Result = RG->getReachableNodes(
|
||||
HelperDeclRGBuilder::getOutmostClassOrFunDecl(D));
|
||||
Nodes.insert(Result.begin(), Result.end());
|
||||
}
|
||||
llvm::DenseSet<const Decl *> Results;
|
||||
for (const auto *Node : Nodes)
|
||||
Results.insert(Node->getDecl());
|
||||
return Results;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
|
@ -455,24 +478,18 @@ void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
|||
//============================================================================
|
||||
// Matchers for old cc
|
||||
//============================================================================
|
||||
auto InOldCCNamedOrGlobalNamespace =
|
||||
allOf(hasParent(decl(anyOf(namespaceDecl(unless(isAnonymous())),
|
||||
translationUnitDecl()))),
|
||||
InOldCC);
|
||||
// Matching using decls/type alias decls which are in named namespace or
|
||||
// global namespace. Those in classes, functions and anonymous namespaces are
|
||||
// covered in other matchers.
|
||||
auto IsOldCCTopLevelDecl = allOf(
|
||||
hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
|
||||
// Matching using decls/type alias decls which are in named/anonymous/global
|
||||
// namespace, these decls are always copied to new.h/cc. Those in classes,
|
||||
// functions are covered in other matchers.
|
||||
Finder->addMatcher(
|
||||
namedDecl(anyOf(usingDecl(InOldCCNamedOrGlobalNamespace),
|
||||
usingDirectiveDecl(InOldCCNamedOrGlobalNamespace),
|
||||
typeAliasDecl( InOldCCNamedOrGlobalNamespace)))
|
||||
namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
|
||||
usingDirectiveDecl(IsOldCCTopLevelDecl),
|
||||
typeAliasDecl(IsOldCCTopLevelDecl)))
|
||||
.bind("using_decl"),
|
||||
this);
|
||||
|
||||
// Match anonymous namespace decl in old cc.
|
||||
Finder->addMatcher(namespaceDecl(isAnonymous(), InOldCC).bind("anonymous_ns"),
|
||||
this);
|
||||
|
||||
// Match static functions/variable definitions which are defined in named
|
||||
// namespaces.
|
||||
Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
|
||||
|
@ -489,13 +506,37 @@ void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
|||
}
|
||||
auto InMovedClass =
|
||||
hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
|
||||
auto IsOldCCStaticDefinition =
|
||||
allOf(isDefinition(), unless(InMovedClass), InOldCCNamedOrGlobalNamespace,
|
||||
isStaticStorageClass());
|
||||
Finder->addMatcher(namedDecl(anyOf(functionDecl(IsOldCCStaticDefinition),
|
||||
varDecl(IsOldCCStaticDefinition)))
|
||||
.bind("static_decls"),
|
||||
this);
|
||||
|
||||
// Matchers for helper declarations in old.cc.
|
||||
auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
|
||||
auto DefinitionInOldCC = allOf(isDefinition(), unless(InMovedClass), InOldCC);
|
||||
auto IsOldCCHelperDefinition =
|
||||
allOf(DefinitionInOldCC, anyOf(isStaticStorageClass(), InAnonymousNS));
|
||||
// Match helper classes separately with helper functions/variables since we
|
||||
// want to reuse these matchers in finding helpers usage below.
|
||||
auto HelperFuncOrVar = namedDecl(anyOf(functionDecl(IsOldCCHelperDefinition),
|
||||
varDecl(IsOldCCHelperDefinition)));
|
||||
auto HelperClasses = cxxRecordDecl(DefinitionInOldCC, InAnonymousNS);
|
||||
// Save all helper declarations in old.cc.
|
||||
Finder->addMatcher(
|
||||
namedDecl(anyOf(HelperFuncOrVar, HelperClasses)).bind("helper_decls"),
|
||||
this);
|
||||
|
||||
// Construct an AST-based call graph of helper declarations in old.cc.
|
||||
// In the following matcheres, "dc" is a caller while "helper_decls" and
|
||||
// "used_class" is a callee, so a new edge starting from caller to callee will
|
||||
// be add in the graph.
|
||||
//
|
||||
// Find helper function/variable usages.
|
||||
Finder->addMatcher(
|
||||
declRefExpr(to(HelperFuncOrVar), hasAncestor(decl().bind("dc")))
|
||||
.bind("func_ref"),
|
||||
&RGBuilder);
|
||||
// Find helper class usages.
|
||||
Finder->addMatcher(
|
||||
typeLoc(loc(recordType(hasDeclaration(HelperClasses.bind("used_class")))),
|
||||
hasAncestor(decl().bind("dc"))),
|
||||
&RGBuilder);
|
||||
|
||||
//============================================================================
|
||||
// Matchers for old files, including old.h/old.cc
|
||||
|
@ -543,12 +584,13 @@ void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
|
|||
else
|
||||
MovedDecls.push_back(FWD);
|
||||
}
|
||||
} else if (const auto *ANS =
|
||||
Result.Nodes.getNodeAs<clang::NamespaceDecl>("anonymous_ns")) {
|
||||
MovedDecls.push_back(ANS);
|
||||
} else if (const auto *ND =
|
||||
Result.Nodes.getNodeAs<clang::NamedDecl>("static_decls")) {
|
||||
MovedDecls.push_back(ND);
|
||||
} else if (const auto *ND =
|
||||
Result.Nodes.getNodeAs<clang::NamedDecl>("helper_decls")) {
|
||||
MovedDecls.push_back(ND);
|
||||
HelperDeclarations.push_back(ND);
|
||||
} else if (const auto *UD =
|
||||
Result.Nodes.getNodeAs<clang::NamedDecl>("using_decl")) {
|
||||
MovedDecls.push_back(UD);
|
||||
|
@ -567,9 +609,6 @@ void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
|
|||
SmallVector<char, 128> HeaderWithSearchPath;
|
||||
llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
|
||||
std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
|
||||
// FIXME: Add old.h to the new.cc/h when the new target has dependencies on
|
||||
// old.h/c. For instance, when moved class uses another class defined in
|
||||
// old.h, the old.h should be added in new.h.
|
||||
if (AbsoluteOldHeader ==
|
||||
MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
|
||||
HeaderWithSearchPath.size()))) {
|
||||
|
@ -591,6 +630,28 @@ void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
|
|||
|
||||
void ClangMoveTool::removeDeclsInOldFiles() {
|
||||
if (RemovedDecls.empty()) return;
|
||||
|
||||
// If old_header is not specified (only move declarations from old.cc), remain
|
||||
// all the helper function declarations in old.cc as UnremovedDeclsInOldHeader
|
||||
// is empty in this case, there is no way to verify unused/used helpers.
|
||||
if (!Context->Spec.OldHeader.empty()) {
|
||||
std::vector<const NamedDecl *> UnremovedDecls;
|
||||
for (const auto *D : UnremovedDeclsInOldHeader)
|
||||
UnremovedDecls.push_back(D);
|
||||
|
||||
auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), UnremovedDecls);
|
||||
|
||||
// We remove the helper declarations which are not used in the old.cc after
|
||||
// moving the given declarations.
|
||||
for (const auto *D : HelperDeclarations) {
|
||||
if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(D))) {
|
||||
DEBUG(llvm::dbgs() << "Helper removed in old.cc: "
|
||||
<< D->getNameAsString() << " " << D << "\n");
|
||||
RemovedDecls.push_back(D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto *RemovedDecl : RemovedDecls) {
|
||||
const auto &SM = RemovedDecl->getASTContext().getSourceManager();
|
||||
auto Range = getFullRange(RemovedDecl);
|
||||
|
@ -650,6 +711,22 @@ void ClangMoveTool::moveDeclsToNewFiles() {
|
|||
NewCCDecls.push_back(MovedDecl);
|
||||
}
|
||||
|
||||
auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), RemovedDecls);
|
||||
std::vector<const NamedDecl *> ActualNewCCDecls;
|
||||
|
||||
// Filter out all unused helpers in NewCCDecls.
|
||||
// We only move the used helpers (including transively used helpers) and the
|
||||
// given symbols being moved.
|
||||
for (const auto *D : NewCCDecls) {
|
||||
if (llvm::is_contained(HelperDeclarations, D) &&
|
||||
!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(D)))
|
||||
continue;
|
||||
|
||||
DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getNameAsString()
|
||||
<< " " << D << "\n");
|
||||
ActualNewCCDecls.push_back(D);
|
||||
}
|
||||
|
||||
if (!Context->Spec.NewHeader.empty()) {
|
||||
std::string OldHeaderInclude =
|
||||
Context->Spec.NewDependOnOld
|
||||
|
@ -662,7 +739,8 @@ void ClangMoveTool::moveDeclsToNewFiles() {
|
|||
}
|
||||
if (!Context->Spec.NewCC.empty())
|
||||
Context->FileToReplacements[Context->Spec.NewCC] =
|
||||
createInsertedReplacements(CCIncludes, NewCCDecls, Context->Spec.NewCC);
|
||||
createInsertedReplacements(CCIncludes, ActualNewCCDecls,
|
||||
Context->Spec.NewCC);
|
||||
}
|
||||
|
||||
// Move all contents from OldFile to NewFile.
|
||||
|
@ -737,8 +815,9 @@ void ClangMoveTool::onEndOfTranslationUnit() {
|
|||
moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
|
||||
return;
|
||||
}
|
||||
removeDeclsInOldFiles();
|
||||
DEBUG(RGBuilder.getGraph()->dump());
|
||||
moveDeclsToNewFiles();
|
||||
removeDeclsInOldFiles();
|
||||
}
|
||||
|
||||
} // namespace move
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
|
||||
|
||||
#include "HelperDeclRefGraph.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Tooling/Core/Replacement.h"
|
||||
|
@ -88,11 +89,18 @@ struct ClangMoveContext {
|
|||
};
|
||||
|
||||
// This tool is used to move class/function definitions from the given source
|
||||
// files (old.h/cc) to new files (new.h/cc). When moving a class, all its
|
||||
// members are also moved. In addition, all helper functions (anonymous
|
||||
// namespace declarations, static declarations, using declarations) in old.cc
|
||||
// and forward class declarations in old.h are copied to the new files.
|
||||
// The goal of this tool is to make the new files as compliable as possible.
|
||||
// files (old.h/cc) to new files (new.h/cc).
|
||||
// The goal of this tool is to make the new/old files as compilable as possible.
|
||||
//
|
||||
// When moving a symbol,all used helper declarations (e.g. static
|
||||
// functions/variables definitions in global/named namespace,
|
||||
// functions/variables/classes definitions in anonymous namespace) used by the
|
||||
// moved symbol in old.cc are moved to the new.cc. In addition, all
|
||||
// using-declarations in old.cc are also moved to new.cc; forward class
|
||||
// declarations in old.h are also moved to new.h.
|
||||
//
|
||||
// The remaining helper declarations which are unused by non-moved symbols in
|
||||
// old.cc will be removed.
|
||||
//
|
||||
// Note: When all declarations in old header are being moved, all code in
|
||||
// old.h/cc will be moved, which means old.h/cc are empty. This ignores symbols
|
||||
|
@ -148,8 +156,10 @@ private:
|
|||
// Stores all MatchCallbacks created by this tool.
|
||||
std::vector<std::unique_ptr<ast_matchers::MatchFinder::MatchCallback>>
|
||||
MatchCallbacks;
|
||||
// All declarations (the class decl being moved, forward decls) that need to
|
||||
// be moved/copy to the new files, saving in an AST-visited order.
|
||||
// Store all potential declarations (decls being moved, forward decls) that
|
||||
// might need to move to new.h/cc. It includes all helper declarations
|
||||
// (include unused ones) by default. The unused ones will be filtered out in
|
||||
// the last stage. Saving in an AST-visited order.
|
||||
std::vector<const NamedDecl *> MovedDecls;
|
||||
// The declarations that needs to be removed in old.cc/h.
|
||||
std::vector<const NamedDecl *> RemovedDecls;
|
||||
|
@ -157,6 +167,10 @@ private:
|
|||
std::vector<std::string> HeaderIncludes;
|
||||
// The #includes in old_cc.cc.
|
||||
std::vector<std::string> CCIncludes;
|
||||
// Records all helper declarations (function/variable/class definitions in
|
||||
// anonymous namespaces, static function/variable definitions in global/named
|
||||
// namespaces) in old.cc. saving in an AST-visited order.
|
||||
std::vector<const NamedDecl *> HelperDeclarations;
|
||||
// The unmoved named declarations in old header.
|
||||
llvm::SmallPtrSet<const NamedDecl*, 8> UnremovedDeclsInOldHeader;
|
||||
/// The source range for the written file name in #include (i.e. "old.h" for
|
||||
|
@ -170,6 +184,8 @@ private:
|
|||
ClangMoveContext *const Context;
|
||||
/// A reporter to report all declarations from old header. It is not owned.
|
||||
DeclarationReporter *const Reporter;
|
||||
/// Builder for helper declarations reference graph.
|
||||
HelperDeclRGBuilder RGBuilder;
|
||||
};
|
||||
|
||||
class ClangMoveAction : public clang::ASTFrontendAction {
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
//===-- UsedHelperDeclFinder.cpp - AST-based call graph for helper decls --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "HelperDeclRefGraph.h"
|
||||
#include "ClangMove.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace move {
|
||||
|
||||
void HelperDeclRefGraph::print(raw_ostream &OS) const {
|
||||
OS << " --- Call graph Dump --- \n";
|
||||
for (auto I = DeclMap.begin(); I != DeclMap.end(); ++I) {
|
||||
const CallGraphNode *N = (I->second).get();
|
||||
|
||||
OS << " Declarations: ";
|
||||
N->print(OS);
|
||||
OS << " (" << N << ") ";
|
||||
OS << " calls: ";
|
||||
for (auto CI = N->begin(), CE = N->end(); CI != CE; ++CI) {
|
||||
(*CI)->print(OS);
|
||||
OS << " (" << CI << ") ";
|
||||
}
|
||||
OS << '\n';
|
||||
}
|
||||
OS.flush();
|
||||
}
|
||||
|
||||
void HelperDeclRefGraph::addEdge(const Decl *Caller, const Decl *Callee) {
|
||||
assert(Caller);
|
||||
assert(Callee);
|
||||
|
||||
// Ignore the case where Caller equals Callee. This happens in the static
|
||||
// class member definitions in global namespace like "int CLASS::static_var =
|
||||
// 1;", its DC is a VarDel whose outmost enclosing declaration is the "CLASS"
|
||||
// CXXRecordDecl.
|
||||
if (Caller == Callee) return;
|
||||
|
||||
// Allocate a new node, mark it as root, and process it's calls.
|
||||
CallGraphNode *CallerNode = getOrInsertNode(const_cast<Decl *>(Caller));
|
||||
CallGraphNode *CalleeNode = getOrInsertNode(const_cast<Decl *>(Callee));
|
||||
CallerNode->addCallee(CalleeNode);
|
||||
}
|
||||
|
||||
void HelperDeclRefGraph::dump() const { print(llvm::errs()); }
|
||||
|
||||
CallGraphNode *HelperDeclRefGraph::getOrInsertNode(Decl *F) {
|
||||
F = F->getCanonicalDecl();
|
||||
std::unique_ptr<CallGraphNode> &Node = DeclMap[F];
|
||||
if (Node)
|
||||
return Node.get();
|
||||
|
||||
Node = llvm::make_unique<CallGraphNode>(F);
|
||||
return Node.get();
|
||||
}
|
||||
|
||||
CallGraphNode *HelperDeclRefGraph::getNode(const Decl *D) const {
|
||||
auto I = DeclMap.find(D->getCanonicalDecl());
|
||||
return I == DeclMap.end() ? nullptr : I->second.get();
|
||||
}
|
||||
|
||||
llvm::DenseSet<const CallGraphNode *>
|
||||
HelperDeclRefGraph::getReachableNodes(const Decl *Root) const {
|
||||
const auto *RootNode = getNode(Root);
|
||||
if (!RootNode)
|
||||
return {};
|
||||
llvm::DenseSet<const CallGraphNode *> ConnectedNodes;
|
||||
std::function<void(const CallGraphNode *)> VisitNode =
|
||||
[&](const CallGraphNode *Node) {
|
||||
if (ConnectedNodes.count(Node))
|
||||
return;
|
||||
ConnectedNodes.insert(Node);
|
||||
for (auto It = Node->begin(), End = Node->end(); It != End; ++It)
|
||||
VisitNode(*It);
|
||||
};
|
||||
|
||||
VisitNode(RootNode);
|
||||
return ConnectedNodes;
|
||||
}
|
||||
|
||||
const Decl *HelperDeclRGBuilder::getOutmostClassOrFunDecl(const Decl *D) {
|
||||
const auto *DC = D->getDeclContext();
|
||||
const auto *Result = D;
|
||||
while (DC) {
|
||||
if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
|
||||
Result = RD;
|
||||
else if (const auto *FD = dyn_cast<FunctionDecl>(DC))
|
||||
Result = FD;
|
||||
DC = DC->getParent();
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
void HelperDeclRGBuilder::run(
|
||||
const ast_matchers::MatchFinder::MatchResult &Result) {
|
||||
// Construct the graph by adding a directed edge from caller to callee.
|
||||
//
|
||||
// "dc" is the closest ancestor declaration of "func_ref" or "used_class", it
|
||||
// might be not the targetted Caller Decl, we always use the outmost enclosing
|
||||
// FunctionDecl/CXXRecordDecl of "dc". For example,
|
||||
//
|
||||
// int MoveClass::F() { int a = helper(); return a; }
|
||||
//
|
||||
// The matched "dc" of "helper" DeclRefExpr is a VarDecl, we traverse up AST
|
||||
// to find the outmost "MoveClass" CXXRecordDecl and use it as Caller.
|
||||
if (const auto *FuncRef = Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
|
||||
const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
|
||||
assert(DC);
|
||||
|
||||
RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()),
|
||||
getOutmostClassOrFunDecl(FuncRef->getDecl()));
|
||||
} else if (const auto *UsedClass =
|
||||
Result.Nodes.getNodeAs<CXXRecordDecl>("used_class")) {
|
||||
const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
|
||||
assert(DC);
|
||||
RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()), UsedClass);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace move
|
||||
} // namespace clang
|
|
@ -0,0 +1,99 @@
|
|||
//===-- UsedHelperDeclFinder.h - AST-based call graph for helper decls ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
|
||||
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/Analysis/CallGraph.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace move {
|
||||
|
||||
// A reference graph for finding used/unused helper declarations in a single
|
||||
// translation unit (e.g. old.cc). We don't reuse CallGraph in clang/Analysis
|
||||
// because that CallGraph only supports function declarations.
|
||||
//
|
||||
// Helper declarations include following types:
|
||||
// * function/variable/class definitions in an anonymous namespace.
|
||||
// * static function/variable definitions in a global/named namespace.
|
||||
//
|
||||
// The reference graph is a directed graph. Each node in the graph represents a
|
||||
// helper declaration in old.cc or a non-moved/moved declaration (e.g. class,
|
||||
// function) in old.h, which means each node is associated with a Decl.
|
||||
//
|
||||
// To construct the graph, we use AST matcher to find interesting Decls (usually
|
||||
// a pair of Caller and Callee), and add an edge from the Caller node to the
|
||||
// Callee node.
|
||||
//
|
||||
// Specially, for a class, it might have multiple declarations such methods
|
||||
// and member variables. We only use a single node to present this class, and
|
||||
// this node is associated with the class declaration (CXXRecordDecl).
|
||||
//
|
||||
// The graph has 3 types of edges:
|
||||
// 1. moved_decl => helper_decl
|
||||
// 2. non_moved_decl => helper_decl
|
||||
// 3. helper_decl => helper_decl
|
||||
class HelperDeclRefGraph {
|
||||
public:
|
||||
HelperDeclRefGraph() = default;
|
||||
~HelperDeclRefGraph() = default;
|
||||
|
||||
// Add a directed edge from the caller node to the callee node.
|
||||
// A new node will be created if the node for Caller/Callee doesn't exist.
|
||||
//
|
||||
// Note that, all class member declarations are represented by a single node
|
||||
// in the graph. The corresponding Decl of this node is the class declaration.
|
||||
void addEdge(const Decl *Caller, const Decl *Callee);
|
||||
CallGraphNode *getNode(const Decl *D) const;
|
||||
|
||||
// Get all reachable nodes in the graph from the given declaration D's node,
|
||||
// including D.
|
||||
llvm::DenseSet<const CallGraphNode *> getReachableNodes(const Decl *D) const;
|
||||
|
||||
// Dump the call graph for debug purpose.
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
void print(raw_ostream &OS) const;
|
||||
// Lookup a node for the given declaration D. If not found, insert a new
|
||||
// node into the graph.
|
||||
CallGraphNode *getOrInsertNode(Decl *D);
|
||||
|
||||
typedef llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>
|
||||
DeclMapTy;
|
||||
|
||||
// DeclMap owns all CallGraphNodes.
|
||||
DeclMapTy DeclMap;
|
||||
};
|
||||
|
||||
// A builder helps to construct a call graph of helper declarations.
|
||||
class HelperDeclRGBuilder : public ast_matchers::MatchFinder::MatchCallback {
|
||||
public:
|
||||
HelperDeclRGBuilder() : RG(new HelperDeclRefGraph) {}
|
||||
void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
const HelperDeclRefGraph *getGraph() const { return RG.get(); }
|
||||
|
||||
// Find out the outmost enclosing class/function declaration of a given D.
|
||||
// For a CXXMethodDecl, get its CXXRecordDecl; For a VarDecl/FunctionDecl, get
|
||||
// its outmost enclosing FunctionDecl or CXXRecordDecl.
|
||||
// Return D if not found.
|
||||
static const Decl *getOutmostClassOrFunDecl(const Decl *D);
|
||||
|
||||
private:
|
||||
std::unique_ptr<HelperDeclRefGraph> RG;
|
||||
};
|
||||
|
||||
} // namespace move
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
|
|
@ -0,0 +1,78 @@
|
|||
#include "helper_decls_test.h"
|
||||
|
||||
namespace {
|
||||
class HelperC1 {
|
||||
public:
|
||||
static int I;
|
||||
};
|
||||
|
||||
int HelperC1::I = 0;
|
||||
|
||||
class HelperC2 {};
|
||||
|
||||
class HelperC3 {
|
||||
public:
|
||||
static int I;
|
||||
};
|
||||
|
||||
int HelperC3::I = 0;
|
||||
|
||||
void HelperFun1() {}
|
||||
|
||||
void HelperFun2() { HelperFun1(); }
|
||||
|
||||
const int K1 = 1;
|
||||
} // namespace
|
||||
|
||||
static const int K2 = 2;
|
||||
static void HelperFun3() { K2; }
|
||||
|
||||
namespace a {
|
||||
|
||||
static const int K3 = 3;
|
||||
static const int K4 = HelperC3::I;
|
||||
static const int K5 = 5;
|
||||
static const int K6 = 6;
|
||||
|
||||
static void HelperFun4() {}
|
||||
static void HelperFun6() {}
|
||||
|
||||
void Class1::f() { HelperFun2(); }
|
||||
|
||||
void Class2::f() {
|
||||
HelperFun1();
|
||||
HelperFun3();
|
||||
}
|
||||
|
||||
void Class3::f() { HelperC1::I; }
|
||||
|
||||
void Class4::f() { HelperC2 c2; }
|
||||
|
||||
void Class5::f() {
|
||||
int Result = K1 + K2 + K3;
|
||||
HelperFun4();
|
||||
}
|
||||
|
||||
int Class6::f() {
|
||||
int R = K4;
|
||||
return R;
|
||||
}
|
||||
|
||||
int Class7::f() {
|
||||
int R = K6;
|
||||
return R;
|
||||
}
|
||||
|
||||
int Class7::g() {
|
||||
HelperFun6();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int HelperFun5() {
|
||||
int R = K5;
|
||||
return R;
|
||||
}
|
||||
|
||||
void Fun1() { HelperFun5(); }
|
||||
|
||||
} // namespace a
|
|
@ -0,0 +1,35 @@
|
|||
namespace a {
|
||||
class Class1 {
|
||||
void f();
|
||||
};
|
||||
|
||||
class Class2 {
|
||||
void f();
|
||||
};
|
||||
|
||||
class Class3 {
|
||||
void f();
|
||||
};
|
||||
|
||||
class Class4 {
|
||||
void f();
|
||||
};
|
||||
|
||||
class Class5 {
|
||||
void f();
|
||||
};
|
||||
|
||||
class Class6 {
|
||||
int f();
|
||||
};
|
||||
|
||||
class Class7 {
|
||||
int f();
|
||||
int g();
|
||||
};
|
||||
|
||||
void Fun1();
|
||||
|
||||
inline void Fun2() {}
|
||||
|
||||
} // namespace a
|
|
@ -15,7 +15,7 @@ namespace {
|
|||
using a::Move1;
|
||||
using namespace a;
|
||||
static int k = 0;
|
||||
} // anonymous namespace
|
||||
} // namespace
|
||||
|
||||
namespace b {
|
||||
using a::Move1;
|
||||
|
@ -34,19 +34,19 @@ int Move3::f() {
|
|||
}
|
||||
|
||||
int Move4::f() {
|
||||
return 0;
|
||||
return k;
|
||||
}
|
||||
|
||||
int EnclosingMove5::a = 1;
|
||||
|
||||
int EnclosingMove5::Nested::f() {
|
||||
return 0;
|
||||
return g;
|
||||
}
|
||||
|
||||
int EnclosingMove5::Nested::b = 1;
|
||||
|
||||
int NoMove::f() {
|
||||
static int F = 0;
|
||||
return 0;
|
||||
return g;
|
||||
}
|
||||
} // namespace c
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
// CHECK-OLD-TEST-CPP: namespace {
|
||||
// CHECK-OLD-TEST-CPP: using a::Move1;
|
||||
// CHECK-OLD-TEST-CPP: using namespace a;
|
||||
// CHECK-OLD-TEST-CPP: static int k = 0;
|
||||
// CHECK-OLD-TEST-CPP: } // anonymous namespace
|
||||
// CHECK-OLD-TEST-CPP: } // namespace
|
||||
// CHECK-OLD-TEST-CPP: namespace b {
|
||||
// CHECK-OLD-TEST-CPP: using a::Move1;
|
||||
// CHECK-OLD-TEST-CPP: using namespace a;
|
||||
|
@ -35,7 +34,7 @@
|
|||
// CHECK-OLD-TEST-CPP: namespace c {
|
||||
// CHECK-OLD-TEST-CPP: int NoMove::f() {
|
||||
// CHECK-OLD-TEST-CPP: static int F = 0;
|
||||
// CHECK-OLD-TEST-CPP: return 0;
|
||||
// CHECK-OLD-TEST-CPP: return g;
|
||||
// CHECK-OLD-TEST-CPP: }
|
||||
// CHECK-OLD-TEST-CPP: } // namespace c
|
||||
|
||||
|
@ -85,7 +84,7 @@
|
|||
// CHECK-NEW-TEST-CPP: using a::Move1;
|
||||
// CHECK-NEW-TEST-CPP: using namespace a;
|
||||
// CHECK-NEW-TEST-CPP: static int k = 0;
|
||||
// CHECK-NEW-TEST-CPP: } // anonymous namespace
|
||||
// CHECK-NEW-TEST-CPP: } // namespace
|
||||
// CHECK-NEW-TEST-CPP: namespace b {
|
||||
// CHECK-NEW-TEST-CPP: using a::Move1;
|
||||
// CHECK-NEW-TEST-CPP: using namespace a;
|
||||
|
@ -98,8 +97,8 @@
|
|||
// CHECK-NEW-TEST-CPP: using namespace b;
|
||||
// CHECK-NEW-TEST-CPP: return 0;
|
||||
// CHECK-NEW-TEST-CPP: }
|
||||
// CHECK-NEW-TEST-CPP: int Move4::f() { return 0; }
|
||||
// CHECK-NEW-TEST-CPP: int Move4::f() { return k; }
|
||||
// CHECK-NEW-TEST-CPP: int EnclosingMove5::a = 1;
|
||||
// CHECK-NEW-TEST-CPP: int EnclosingMove5::Nested::f() { return 0; }
|
||||
// CHECK-NEW-TEST-CPP: int EnclosingMove5::Nested::f() { return g; }
|
||||
// CHECK-NEW-TEST-CPP: int EnclosingMove5::Nested::b = 1;
|
||||
// CHECK-NEW-TEST-CPP: } // namespace c
|
||||
|
|
|
@ -0,0 +1,388 @@
|
|||
// RUN: mkdir -p %T/used-helper-decls
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: cd %T/used-helper-decls
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test moving used helper function and its transively used functions.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: clang-move -names="a::Class1" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS1-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS1-CPP %s
|
||||
|
||||
// CHECK-NEW-CLASS1-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS1-CPP-NEXT: namespace {
|
||||
// CHECK-NEW-CLASS1-CPP-NEXT: void HelperFun1() {}
|
||||
// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS1-CPP-NEXT: void HelperFun2() { HelperFun1(); }
|
||||
// CHECK-NEW-CLASS1-CPP-NEXT: } // namespace
|
||||
// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS1-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-CLASS1-CPP-NEXT: void Class1::f() { HelperFun2(); }
|
||||
// CHECK-NEW-CLASS1-CPP-NEXT: } // namespace a
|
||||
//
|
||||
// CHECK-OLD-CLASS1-CPP: void HelperFun1() {}
|
||||
// CHECK-OLD-CLASS1-CPP-NOT: void HelperFun2() { HelperFun1(); }
|
||||
// CHECK-OLD-CLASS1-CPP-NOT: void Class1::f() { HelperFun2(); }
|
||||
// CHECK-OLD-CLASS1-CPP: void Class2::f() {
|
||||
// CHECK-OLD-CLASS1-CPP: HelperFun1();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test moving used helper function and its transively used static variables.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Class2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS2-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS2-CPP %s
|
||||
|
||||
// CHECK-NEW-CLASS2-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: namespace {
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: void HelperFun1() {}
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: } // namespace
|
||||
// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: static const int K2 = 2;
|
||||
// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: static void HelperFun3() { K2; }
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: void Class2::f() {
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: HelperFun1();
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: HelperFun3();
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: }
|
||||
// CHECK-NEW-CLASS2-CPP-NEXT: } // namespace a
|
||||
|
||||
// CHECK-OLD-CLASS2-CPP: void HelperFun1() {}
|
||||
// CHECK-OLD-CLASS2-CPP: void HelperFun2() { HelperFun1(); }
|
||||
// CHECK-OLD-CLASS2-CPP: const int K1 = 1;
|
||||
// CHECK-OLD-CLASS2-CPP: static const int K2 = 2;
|
||||
// CHECK-OLD-CLASS2-CPP-NOT: static void HelperFun3() { K2; }
|
||||
// CHECK-OLD-CLASS2-CPP-NOT: void Class2::f() {
|
||||
// CHECK-OLD-CLASS2-CPP-NOT: HelperFun1();
|
||||
// CHECK-OLD-CLASS2-CPP-NOT: HelperFun3();
|
||||
// CHECK-OLD-CLASS2-CPP: void Class5::f() {
|
||||
// CHECK-OLD-CLASS2-CPP-NEXT: int Result = K1 + K2 + K3;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test using a static member variable of a helper class.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Class3" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS3-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS3-CPP %s
|
||||
|
||||
// CHECK-NEW-CLASS3-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: namespace {
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: class HelperC1 {
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: public:
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: static int I;
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: };
|
||||
// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: int HelperC1::I = 0;
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: } // namespace
|
||||
// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: void Class3::f() { HelperC1::I; }
|
||||
// CHECK-NEW-CLASS3-CPP-NEXT: } // namespace a
|
||||
|
||||
// CHECK-OLD-CLASS3-CPP: namespace {
|
||||
// CHECK-OLD-CLASS3-CPP-NOT: class HelperC1 {
|
||||
// CHECK-OLD-CLASS3-CPP-NOT: public:
|
||||
// CHECK-OLD-CLASS3-CPP-NOT: static int I;
|
||||
// CHECK-OLD-CLASS3-CPP-NOT: };
|
||||
// CHECK-OLD-CLASS3-CPP-NOT: int HelperC1::I = 0;
|
||||
// CHECK-OLD-CLASS3-CPP: class HelperC2 {};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test moving helper classes.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Class4" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS4-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS4-CPP %s
|
||||
|
||||
// CHECK-NEW-CLASS4-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-CLASS4-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS4-CPP-NEXT: namespace {
|
||||
// CHECK-NEW-CLASS4-CPP-NEXT: class HelperC2 {};
|
||||
// CHECK-NEW-CLASS4-CPP-NEXT: } // namespace
|
||||
// CHECK-NEW-CLASS4-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS4-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-CLASS4-CPP-NEXT: void Class4::f() { HelperC2 c2; }
|
||||
// CHECK-NEW-CLASS4-CPP-NEXT: } // namespace a
|
||||
|
||||
// CHECK-OLD-CLASS4-CPP-NOT: class HelperC2 {};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test moving helper variables and helper functions together.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Class5" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS5-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS5-CPP %s
|
||||
|
||||
// CHECK-NEW-CLASS5-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: namespace {
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: const int K1 = 1;
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: } // namespace
|
||||
// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: static const int K2 = 2;
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: static const int K3 = 3;
|
||||
// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: static void HelperFun4() {}
|
||||
// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: void Class5::f() {
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: int Result = K1 + K2 + K3;
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: HelperFun4();
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: }
|
||||
// CHECK-NEW-CLASS5-CPP-NEXT: } // namespace a
|
||||
|
||||
// CHECK-OLD-CLASS5-CPP-NOT: const int K1 = 1;
|
||||
// CHECK-OLD-CLASS5-CPP: static const int K2 = 2;
|
||||
// CHECK-OLD-CLASS5-CPP: static void HelperFun3() { K2; }
|
||||
// CHECK-OLD-CLASS5-CPP: static const int K4 = HelperC3::I;
|
||||
// CHECK-OLD-CLASS5-CPP-NOT: void Class5::f() {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test moving helper variables and their transively used helper classes.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Class6" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS6-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS6-CPP %s
|
||||
|
||||
// CHECK-NEW-CLASS6-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: namespace {
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: class HelperC3 {
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: public:
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: static int I;
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: };
|
||||
// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: int HelperC3::I = 0;
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: } // namespace
|
||||
// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: static const int K4 = HelperC3::I;
|
||||
// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: int Class6::f() {
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: int R = K4;
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: return R;
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: }
|
||||
// CHECK-NEW-CLASS6-CPP-NEXT: } // namespace a
|
||||
|
||||
// CHECK-OLD-CLASS6-CPP-NOT: class HelperC3 {
|
||||
// CHECK-OLD-CLASS6-CPP-NOT: int HelperC3::I = 0;
|
||||
// CHECK-OLD-CLASS6-CPP-NOT: static const int K4 = HelperC3::I;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test moving classes where its methods use helpers.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Class7" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS7-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS7-CPP %s
|
||||
|
||||
// CHECK-NEW-CLASS7-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: static const int K6 = 6;
|
||||
// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: static void HelperFun6() {}
|
||||
// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: int Class7::f() {
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: int R = K6;
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: return R;
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: }
|
||||
// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: int Class7::g() {
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: HelperFun6();
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: return 1;
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: }
|
||||
// CHECK-NEW-CLASS7-CPP-NEXT: } // namespace a
|
||||
//
|
||||
// CHECK-OLD-CLASS7-CPP-NOT: static const int K6 = 6;
|
||||
// CHECK-OLD-CLASS7-CPP-NOT: static void HelperFun6() {}
|
||||
// CHECK-OLD-CLASS7-CPP-NOT: int Class7::f() {
|
||||
// CHECK-OLD-CLASS7-CPP-NOT: int Class7::g() {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test moving helper function and its transively used helper variables.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Fun1" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN1-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-FUN1-CPP %s
|
||||
|
||||
// CHECK-NEW-FUN1-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-FUN1-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-FUN1-CPP-NEXT: static const int K5 = 5;
|
||||
// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-FUN1-CPP-NEXT: static int HelperFun5() {
|
||||
// CHECK-NEW-FUN1-CPP-NEXT: int R = K5;
|
||||
// CHECK-NEW-FUN1-CPP-NEXT: return R;
|
||||
// CHECK-NEW-FUN1-CPP-NEXT: }
|
||||
// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-FUN1-CPP-NEXT: void Fun1() { HelperFun5(); }
|
||||
// CHECK-NEW-FUN1-CPP-NEXT: } // namespace a
|
||||
|
||||
// CHECK-OLD-FUN1-CPP-NOT: static const int K5 = 5;
|
||||
// CHECK-OLD-FUN1-CPP-NOT: static int HelperFun5() {
|
||||
// CHECK-OLD-FUN1-CPP-NOT: void Fun1() { HelperFun5(); }
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test no moving helpers when moving inline functions in header.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Fun2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN2-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-FUN2-H %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.h -check-prefix=CHECK-OLD-FUN2-H %s
|
||||
|
||||
// CHECK-NEW-FUN2-H: namespace a {
|
||||
// CHECK-NEW-FUN2-H-NEXT: inline void Fun2() {}
|
||||
// CHECK-NEW-FUN2-H-NEXT: } // namespace a
|
||||
|
||||
// CHECK-NEW-FUN2-CPP: #include "{{.*}}new_helper_decls_test.h"
|
||||
// CHECK-NEW-FUN2-CPP-SAME: {{[[:space:]]}}
|
||||
|
||||
// CHECK-OLD-FUN2-H-NOT: inline void Fun2() {}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test moving all symbols in headers.
|
||||
// ----------------------------------------------------------------------------
|
||||
// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
|
||||
// RUN: clang-move -names="a::Class1, a::Class2, a::Class3, a::Class4, a::Class5, a::Class5, a::Class6, a::Class7, a::Fun1, a::Fun2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-H %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CPP %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.h -allow-empty -check-prefix=CHECK-EMPTY %s
|
||||
// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -allow-empty -check-prefix=CHECK-EMPTY %s
|
||||
|
||||
|
||||
// CHECK-NEW-H: namespace a {
|
||||
// CHECK-NEW-H-NEXT: class Class1 {
|
||||
// CHECK-NEW-H-NEXT: void f();
|
||||
// CHECK-NEW-H-NEXT: };
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: class Class2 {
|
||||
// CHECK-NEW-H-NEXT: void f();
|
||||
// CHECK-NEW-H-NEXT: };
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: class Class3 {
|
||||
// CHECK-NEW-H-NEXT: void f();
|
||||
// CHECK-NEW-H-NEXT: };
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: class Class4 {
|
||||
// CHECK-NEW-H-NEXT: void f();
|
||||
// CHECK-NEW-H-NEXT: };
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: class Class5 {
|
||||
// CHECK-NEW-H-NEXT: void f();
|
||||
// CHECK-NEW-H-NEXT: };
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: class Class6 {
|
||||
// CHECK-NEW-H-NEXT: int f();
|
||||
// CHECK-NEW-H-NEXT: };
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: class Class7 {
|
||||
// CHECK-NEW-H-NEXT: int f();
|
||||
// CHECK-NEW-H-NEXT: int g();
|
||||
// CHECK-NEW-H-NEXT: };
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: void Fun1();
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: inline void Fun2() {}
|
||||
// CHECK-NEW-H-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-H-NEXT: } // namespace a
|
||||
|
||||
|
||||
// CHECK-NEW-CPP: namespace {
|
||||
// CHECK-NEW-CPP-NEXT: class HelperC1 {
|
||||
// CHECK-NEW-CPP-NEXT: public:
|
||||
// CHECK-NEW-CPP-NEXT: static int I;
|
||||
// CHECK-NEW-CPP-NEXT: };
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: int HelperC1::I = 0;
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: class HelperC2 {};
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: class HelperC3 {
|
||||
// CHECK-NEW-CPP-NEXT: public:
|
||||
// CHECK-NEW-CPP-NEXT: static int I;
|
||||
// CHECK-NEW-CPP-NEXT: };
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: int HelperC3::I = 0;
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: void HelperFun1() {}
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: void HelperFun2() { HelperFun1(); }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: const int K1 = 1;
|
||||
// CHECK-NEW-CPP-NEXT: } // namespace
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: static const int K2 = 2;
|
||||
// CHECK-NEW-CPP-NEXT: static void HelperFun3() { K2; }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: namespace a {
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: static const int K3 = 3;
|
||||
// CHECK-NEW-CPP-NEXT: static const int K4 = HelperC3::I;
|
||||
// CHECK-NEW-CPP-NEXT: static const int K5 = 5;
|
||||
// CHECK-NEW-CPP-NEXT: static const int K6 = 6;
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: static void HelperFun4() {}
|
||||
// CHECK-NEW-CPP-NEXT: static void HelperFun6() {}
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: void Class1::f() { HelperFun2(); }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: void Class2::f() {
|
||||
// CHECK-NEW-CPP-NEXT: HelperFun1();
|
||||
// CHECK-NEW-CPP-NEXT: HelperFun3();
|
||||
// CHECK-NEW-CPP-NEXT: }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: void Class3::f() { HelperC1::I; }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: void Class4::f() { HelperC2 c2; }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: void Class5::f() {
|
||||
// CHECK-NEW-CPP-NEXT: int Result = K1 + K2 + K3;
|
||||
// CHECK-NEW-CPP-NEXT: HelperFun4();
|
||||
// CHECK-NEW-CPP-NEXT: }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: int Class6::f() {
|
||||
// CHECK-NEW-CPP-NEXT: int R = K4;
|
||||
// CHECK-NEW-CPP-NEXT: return R;
|
||||
// CHECK-NEW-CPP-NEXT: }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: int Class7::f() {
|
||||
// CHECK-NEW-CPP-NEXT: int R = K6;
|
||||
// CHECK-NEW-CPP-NEXT: return R;
|
||||
// CHECK-NEW-CPP-NEXT: }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: int Class7::g() {
|
||||
// CHECK-NEW-CPP-NEXT: HelperFun6();
|
||||
// CHECK-NEW-CPP-NEXT: return 1;
|
||||
// CHECK-NEW-CPP-NEXT: }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: static int HelperFun5() {
|
||||
// CHECK-NEW-CPP-NEXT: int R = K5;
|
||||
// CHECK-NEW-CPP-NEXT: return R;
|
||||
// CHECK-NEW-CPP-NEXT: }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: void Fun1() { HelperFun5(); }
|
||||
// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
|
||||
// CHECK-NEW-CPP-NEXT: } // namespace a
|
||||
|
||||
// CHECK-EMPTY: {{^}}{{$}}
|
|
@ -73,13 +73,21 @@ const char TestCC[] = "#include \"foo.h\"\n"
|
|||
"\n"
|
||||
"// comment5\n"
|
||||
"// comment5\n"
|
||||
"void Foo::f() { f1(); }\n"
|
||||
"void Foo::f() {\n"
|
||||
" f1();\n"
|
||||
" kConstInt1;\n"
|
||||
" kConstInt2;\n"
|
||||
" help();\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"/////////////\n"
|
||||
"// comment //\n"
|
||||
"/////////////\n"
|
||||
"int Foo::b = 2;\n"
|
||||
"int Foo2::f() {\n"
|
||||
" kConstInt1;\n"
|
||||
" kConstInt2;\n"
|
||||
" help();\n"
|
||||
" f1();\n"
|
||||
" return 1;\n"
|
||||
"}\n"
|
||||
|
@ -119,6 +127,9 @@ const char ExpectedTestCC[] = "#include \"foo.h\"\n"
|
|||
"}\n"
|
||||
"\n"
|
||||
"int Foo2::f() {\n"
|
||||
" kConstInt1;\n"
|
||||
" kConstInt2;\n"
|
||||
" help();\n"
|
||||
" f1();\n"
|
||||
" return 1;\n"
|
||||
"}\n"
|
||||
|
@ -154,6 +165,7 @@ const char ExpectedNewCC[] = "namespace a {\n"
|
|||
"namespace {\n"
|
||||
"// comment1.\n"
|
||||
"void f1() {}\n"
|
||||
"\n"
|
||||
"/// comment2.\n"
|
||||
"int kConstInt1 = 0;\n"
|
||||
"} // namespace\n"
|
||||
|
@ -170,7 +182,12 @@ const char ExpectedNewCC[] = "namespace a {\n"
|
|||
"\n"
|
||||
"// comment5\n"
|
||||
"// comment5\n"
|
||||
"void Foo::f() { f1(); }\n"
|
||||
"void Foo::f() {\n"
|
||||
" f1();\n"
|
||||
" kConstInt1;\n"
|
||||
" kConstInt2;\n"
|
||||
" help();\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"/////////////\n"
|
||||
"// comment //\n"
|
||||
|
|
Loading…
Reference in New Issue