llvm-project/clang/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
Alex Lorenz a844f396ce [refactor] Add the AST source selection component
This commit adds the base AST source selection component to the refactoring
library. AST selection is represented using a tree of SelectedASTNode values.
Each selected node gets its own selection kind, which can actually be None even
in the middle of tree (e.g. statement in a macro whose child is in a macro
argument). The initial version constructs a "raw" selection tree, without
applying filters and canonicalisation operations to the nodes.

Differential Revision: https://reviews.llvm.org/D35012

llvm-svn: 311655
2017-08-24 13:51:09 +00:00

142 lines
3.5 KiB
C++

//===- unittest/Tooling/LexicallyOrderedRecursiveASTVisitorTest.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/AST/LexicallyOrderedRecursiveASTVisitor.h"
#include <stack>
using namespace clang;
namespace {
class DummyMatchVisitor;
class LexicallyOrderedDeclVisitor
: public LexicallyOrderedRecursiveASTVisitor<LexicallyOrderedDeclVisitor> {
public:
LexicallyOrderedDeclVisitor(DummyMatchVisitor &Matcher,
const SourceManager &SM)
: LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher) {}
bool TraverseDecl(Decl *D) {
TraversalStack.push_back(D);
LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
TraversalStack.pop_back();
return true;
}
bool VisitNamedDecl(const NamedDecl *D);
private:
DummyMatchVisitor &Matcher;
llvm::SmallVector<Decl *, 8> TraversalStack;
};
class DummyMatchVisitor : public ExpectedLocationVisitor<DummyMatchVisitor> {
public:
bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
const ASTContext &Context = TU->getASTContext();
const SourceManager &SM = Context.getSourceManager();
LexicallyOrderedDeclVisitor SubVisitor(*this, SM);
SubVisitor.TraverseDecl(TU);
return false;
}
void match(StringRef Path, const Decl *D) { Match(Path, D->getLocStart()); }
};
bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
std::string Path;
llvm::raw_string_ostream OS(Path);
assert(TraversalStack.back() == D);
for (const Decl *D : TraversalStack) {
if (isa<TranslationUnitDecl>(D)) {
OS << "/";
continue;
}
if (const auto *ND = dyn_cast<NamedDecl>(D))
OS << ND->getNameAsString();
else
OS << "???";
if (isa<DeclContext>(D))
OS << "/";
}
Matcher.match(OS.str(), D);
return true;
}
TEST(LexicallyOrderedRecursiveASTVisitor, VisitDeclsInImplementation) {
StringRef Source = R"(
@interface I
@end
@implementation I
int nestedFunction() { }
- (void) method{ }
int anotherNestedFunction(int x) {
return x;
}
int innerVariable = 0;
@end
int outerVariable = 0;
@implementation I(Cat)
void catF() { }
@end
void outerFunction() { }
)";
DummyMatchVisitor Visitor;
Visitor.DisallowMatch("/nestedFunction/", 6, 1);
Visitor.ExpectMatch("/I/nestedFunction/", 6, 1);
Visitor.ExpectMatch("/I/method/", 8, 1);
Visitor.DisallowMatch("/anotherNestedFunction/", 10, 1);
Visitor.ExpectMatch("/I/anotherNestedFunction/", 10, 1);
Visitor.DisallowMatch("/innerVariable", 14, 1);
Visitor.ExpectMatch("/I/innerVariable", 14, 1);
Visitor.ExpectMatch("/outerVariable", 18, 1);
Visitor.DisallowMatch("/catF/", 22, 1);
Visitor.ExpectMatch("/Cat/catF/", 22, 1);
Visitor.ExpectMatch("/outerFunction/", 26, 1);
EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
}
TEST(LexicallyOrderedRecursiveASTVisitor, VisitMacroDeclsInImplementation) {
StringRef Source = R"(
@interface I
@end
void outerFunction() { }
#define MACRO_F(x) void nestedFunction##x() { }
@implementation I
MACRO_F(1)
@end
MACRO_F(2)
)";
DummyMatchVisitor Visitor;
Visitor.ExpectMatch("/outerFunction/", 5, 1);
Visitor.ExpectMatch("/I/nestedFunction1/", 7, 20);
Visitor.ExpectMatch("/nestedFunction2/", 7, 20);
EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
}
} // end anonymous namespace