140 lines
4.5 KiB
C++
140 lines
4.5 KiB
C++
|
//===- unittest/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp ------------===//
|
||
|
//
|
||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "TestVisitor.h"
|
||
|
|
||
|
using namespace clang;
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
|
||
|
public:
|
||
|
bool VisitVarDecl(VarDecl *Variable) {
|
||
|
Match(Variable->getNameAsString(), Variable->getBeginLoc());
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
|
||
|
VarDeclVisitor Visitor;
|
||
|
Visitor.ExpectMatch("i", 2, 17);
|
||
|
EXPECT_TRUE(Visitor.runOver(
|
||
|
"int x[5];\n"
|
||
|
"void f() { for (int i : x) {} }",
|
||
|
VarDeclVisitor::Lang_CXX11));
|
||
|
}
|
||
|
|
||
|
class ParmVarDeclVisitorForImplicitCode :
|
||
|
public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> {
|
||
|
public:
|
||
|
bool shouldVisitImplicitCode() const { return true; }
|
||
|
|
||
|
bool VisitParmVarDecl(ParmVarDecl *ParamVar) {
|
||
|
Match(ParamVar->getNameAsString(), ParamVar->getBeginLoc());
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Test RAV visits parameter variable declaration of the implicit
|
||
|
// copy assignment operator and implicit copy constructor.
|
||
|
TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) {
|
||
|
ParmVarDeclVisitorForImplicitCode Visitor;
|
||
|
// Match parameter variable name of implicit copy assignment operator and
|
||
|
// implicit copy constructor.
|
||
|
// This parameter name does not have a valid IdentifierInfo, and shares
|
||
|
// same SourceLocation with its class declaration, so we match an empty name
|
||
|
// with the class' source location.
|
||
|
Visitor.ExpectMatch("", 1, 7);
|
||
|
Visitor.ExpectMatch("", 3, 7);
|
||
|
EXPECT_TRUE(Visitor.runOver(
|
||
|
"class X {};\n"
|
||
|
"void foo(X a, X b) {a = b;}\n"
|
||
|
"class Y {};\n"
|
||
|
"void bar(Y a) {Y b = a;}"));
|
||
|
}
|
||
|
|
||
|
class NamedDeclVisitor
|
||
|
: public ExpectedLocationVisitor<NamedDeclVisitor> {
|
||
|
public:
|
||
|
bool VisitNamedDecl(NamedDecl *Decl) {
|
||
|
std::string NameWithTemplateArgs;
|
||
|
llvm::raw_string_ostream OS(NameWithTemplateArgs);
|
||
|
Decl->getNameForDiagnostic(OS,
|
||
|
Decl->getASTContext().getPrintingPolicy(),
|
||
|
true);
|
||
|
Match(OS.str(), Decl->getLocation());
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) {
|
||
|
// From cfe-commits/Week-of-Mon-20100830/033998.html
|
||
|
// Contrary to the approach suggested in that email, we visit all
|
||
|
// specializations when we visit the primary template. Visiting them when we
|
||
|
// visit the associated specialization is problematic for specializations of
|
||
|
// template members of class templates.
|
||
|
NamedDeclVisitor Visitor;
|
||
|
Visitor.ExpectMatch("A<bool>", 1, 26);
|
||
|
Visitor.ExpectMatch("A<char *>", 2, 26);
|
||
|
EXPECT_TRUE(Visitor.runOver(
|
||
|
"template <class T> class A {};\n"
|
||
|
"template <class T> class A<T*> {};\n"
|
||
|
"A<bool> ab;\n"
|
||
|
"A<char*> acp;\n"));
|
||
|
}
|
||
|
|
||
|
TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) {
|
||
|
NamedDeclVisitor Visitor;
|
||
|
Visitor.ExpectMatch("A<int>", 1, 29);
|
||
|
EXPECT_TRUE(Visitor.runOver(
|
||
|
"template<typename T> struct A;\n"
|
||
|
"A<int> *p;\n"));
|
||
|
}
|
||
|
|
||
|
TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) {
|
||
|
NamedDeclVisitor Visitor;
|
||
|
Visitor.ExpectMatch("A<int>::B<char>", 2, 31);
|
||
|
EXPECT_TRUE(Visitor.runOver(
|
||
|
"template<typename T> struct A {\n"
|
||
|
" template<typename U> struct B;\n"
|
||
|
"};\n"
|
||
|
"A<int>::B<char> *p;\n"));
|
||
|
}
|
||
|
|
||
|
TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) {
|
||
|
NamedDeclVisitor Visitor;
|
||
|
Visitor.ExpectMatch("A<int>", 1, 26);
|
||
|
EXPECT_TRUE(Visitor.runOver(
|
||
|
"template<typename T> int A();\n"
|
||
|
"int k = A<int>();\n"));
|
||
|
}
|
||
|
|
||
|
TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) {
|
||
|
NamedDeclVisitor Visitor;
|
||
|
Visitor.ExpectMatch("A<int>::B<char>", 2, 35);
|
||
|
EXPECT_TRUE(Visitor.runOver(
|
||
|
"template<typename T> struct A {\n"
|
||
|
" template<typename U> static int B();\n"
|
||
|
"};\n"
|
||
|
"int k = A<int>::B<char>();\n"));
|
||
|
}
|
||
|
|
||
|
TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) {
|
||
|
// From cfe-commits/Week-of-Mon-20100830/033977.html
|
||
|
NamedDeclVisitor Visitor;
|
||
|
Visitor.ExpectMatch("vector_iterator<int>", 2, 7);
|
||
|
EXPECT_TRUE(Visitor.runOver(
|
||
|
"template<typename Container>\n"
|
||
|
"class vector_iterator {\n"
|
||
|
" template <typename C> friend class vector_iterator;\n"
|
||
|
"};\n"
|
||
|
"vector_iterator<int> it_int;\n"));
|
||
|
}
|
||
|
|
||
|
} // end anonymous namespace
|