diff options
| author | Benjamin Kramer <benny.kra@googlemail.com> | 2015-10-22 15:04:10 +0000 |
|---|---|---|
| committer | Benjamin Kramer <benny.kra@googlemail.com> | 2015-10-22 15:04:10 +0000 |
| commit | 9bccaa158a8424b7f74e75d7cb1878f2a4b6826a (patch) | |
| tree | 147810be8d24191ee0d3df68c339cfb63700fb3f /clang/unittests/Tooling | |
| parent | 8f9e44406165c1f57e0b28ba159cace972220921 (diff) | |
| download | bcm5719-llvm-9bccaa158a8424b7f74e75d7cb1878f2a4b6826a.tar.gz bcm5719-llvm-9bccaa158a8424b7f74e75d7cb1878f2a4b6826a.zip | |
[Tooling] Add a utility function to replace one nested name with another.
One problem in clang-tidy and other clang tools face is that there is no
way to lookup an arbitrary name in the AST, that's buried deep inside Sema
and might not even be what the user wants as the new name may be freshly
inserted and not available in the AST.
A common use case for lookups is replacing one nested name with another
while minimizing namespace qualifications, so replacing 'ns::foo' with
'ns::bar' will use just 'bar' if we happen to be inside the namespace 'ns'.
This adds a little helper utility for exactly that use case.
Differential Revision: http://reviews.llvm.org/D13931
llvm-svn: 251022
Diffstat (limited to 'clang/unittests/Tooling')
| -rw-r--r-- | clang/unittests/Tooling/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | clang/unittests/Tooling/LookupTest.cpp | 108 |
2 files changed, 109 insertions, 0 deletions
diff --git a/clang/unittests/Tooling/CMakeLists.txt b/clang/unittests/Tooling/CMakeLists.txt index 2ae3a3e31ed..33b2046ae92 100644 --- a/clang/unittests/Tooling/CMakeLists.txt +++ b/clang/unittests/Tooling/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_unittest(ToolingTests CommentHandlerTest.cpp CompilationDatabaseTest.cpp + LookupTest.cpp ToolingTest.cpp RecursiveASTVisitorTest.cpp RecursiveASTVisitorTestCallVisitor.cpp diff --git a/clang/unittests/Tooling/LookupTest.cpp b/clang/unittests/Tooling/LookupTest.cpp new file mode 100644 index 00000000000..d847a298fff --- /dev/null +++ b/clang/unittests/Tooling/LookupTest.cpp @@ -0,0 +1,108 @@ +//===- unittest/Tooling/LookupTest.cpp ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestVisitor.h" +#include "clang/Tooling/Core/Lookup.h" +using namespace clang; + +namespace { +struct GetDeclsVisitor : TestVisitor<GetDeclsVisitor> { + std::function<void(CallExpr *)> OnCall; + SmallVector<Decl *, 4> DeclStack; + + bool VisitCallExpr(CallExpr *Expr) { + OnCall(Expr); + return true; + } + + bool TraverseDecl(Decl *D) { + DeclStack.push_back(D); + bool Ret = TestVisitor::TraverseDecl(D); + DeclStack.pop_back(); + return Ret; + } +}; + +TEST(LookupTest, replaceNestedName) { + GetDeclsVisitor Visitor; + + auto replaceCallExpr = [&](const CallExpr *Expr, + StringRef ReplacementString) { + const auto *Callee = cast<DeclRefExpr>(Expr->getCallee()->IgnoreImplicit()); + const ValueDecl *FD = Callee->getDecl(); + return tooling::replaceNestedName( + Callee->getQualifier(), Visitor.DeclStack.back()->getDeclContext(), FD, + ReplacementString); + }; + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\n" + "namespace a { void f() { foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\n" + "namespace a { void f() { foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\n" + "namespace b { void f() { a::foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\n" + "namespace b { namespace a { void foo(); }\n" + "void f() { a::foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); + }; + Visitor.runOver("namespace a { namespace b { void foo(); }\n" + "void f() { b::foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { namespace b { void foo(); }\n" + "void f() { b::foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); + }; + Visitor.runOver("void foo(); void f() { foo(); }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("::bar", replaceCallExpr(Expr, "::bar")); + }; + Visitor.runOver("void foo(); void f() { ::foo(); }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\nvoid f() { a::foo(); }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { int foo(); }\nauto f = a::foo();\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver( + "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n"); +} + +} // end anonymous namespace |

