teak-llvm/clang/unittests/AST/DeclMatcher.h
Gabor Marton 9581c331d2 Fix duplicate class template definitions problem
Summary:
We fail to import a `ClassTemplateDecl` if the "To" context already
contains a definition and then a forward decl.  This is because
`localUncachedLookup` does not find the definition.  This is not a
lookup error, the parser behaves differently than assumed in the
importer code.  A `DeclContext` contains one DenseMap (`LookupPtr`)
which maps names to lists.  The list is a special list `StoredDeclsList`
which is optimized to have one element.  During building the initial
AST, the parser first adds the definition to the `DeclContext`.  Then
during parsing the second declaration (the forward decl) the parser
again calls `DeclContext::addDecl` but that will not add a new element
to the `StoredDeclsList` rarther it simply overwrites the old element
with the most recent one.  This patch fixes the error by finding the
definition in the redecl chain.  Added tests for the same issue with
`CXXRecordDecl` and with `ClassTemplateSpecializationDecl`.  These tests
pass and they pass because in `VisitRecordDecl` and in
`VisitClassTemplateSpecializationDecl` we already use
`D->getDefinition()` after the lookup.

Reviewers: a.sidorin, xazax.hun, szepet

Subscribers: rnkovacs, dkrupp, cfe-commits

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

llvm-svn: 333082
2018-05-23 13:53:36 +00:00

80 lines
2.6 KiB
C++

//===- unittest/AST/DeclMatcher.h - AST unit test support ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_UNITTESTS_AST_DECLMATCHER_H
#define LLVM_CLANG_UNITTESTS_AST_DECLMATCHER_H
#include "clang/ASTMatchers/ASTMatchFinder.h"
namespace clang {
namespace ast_matchers {
enum class DeclMatcherKind { First, Last };
// Matcher class to retrieve the first/last matched node under a given AST.
template <typename NodeType, DeclMatcherKind MatcherKind>
class DeclMatcher : public MatchFinder::MatchCallback {
NodeType *Node = nullptr;
void run(const MatchFinder::MatchResult &Result) override {
if ((MatcherKind == DeclMatcherKind::First && Node == nullptr) ||
MatcherKind == DeclMatcherKind::Last) {
Node = const_cast<NodeType *>(Result.Nodes.getNodeAs<NodeType>(""));
}
}
public:
// Returns the first/last matched node under the tree rooted in `D`.
template <typename MatcherType>
NodeType *match(const Decl *D, const MatcherType &AMatcher) {
MatchFinder Finder;
Finder.addMatcher(AMatcher.bind(""), this);
Finder.matchAST(D->getASTContext());
assert(Node);
return Node;
}
};
template <typename NodeType>
using LastDeclMatcher = DeclMatcher<NodeType, DeclMatcherKind::Last>;
template <typename NodeType>
using FirstDeclMatcher = DeclMatcher<NodeType, DeclMatcherKind::First>;
template <typename NodeType>
class DeclCounterWithPredicate : public MatchFinder::MatchCallback {
using UnaryPredicate = std::function<bool(const NodeType *)>;
UnaryPredicate Predicate;
unsigned Count = 0;
void run(const MatchFinder::MatchResult &Result) override {
if (auto N = Result.Nodes.getNodeAs<NodeType>("")) {
if (Predicate(N))
++Count;
}
}
public:
DeclCounterWithPredicate()
: Predicate([](const NodeType *) { return true; }) {}
DeclCounterWithPredicate(UnaryPredicate P) : Predicate(P) {}
// Returns the number of matched nodes which satisfy the predicate under the
// tree rooted in `D`.
template <typename MatcherType>
unsigned match(const Decl *D, const MatcherType &AMatcher) {
MatchFinder Finder;
Finder.addMatcher(AMatcher.bind(""), this);
Finder.matchAST(D->getASTContext());
return Count;
}
};
template <typename NodeType>
using DeclCounter = DeclCounterWithPredicate<NodeType>;
} // end namespace ast_matchers
} // end namespace clang
#endif