Treat explicit template instantiations as full uses
Teach IsFowardDecl() to not confuse an explicit template instantiation with a forward declaration. Also make sure to report explicit instantiations (declaration or definition) as full uses during visitation. Fixes #558
This commit is contained in:
parent
2132e43fd1
commit
0d0832fee7
11
iwyu.cc
11
iwyu.cc
|
@ -3732,11 +3732,20 @@ class IwyuAstConsumer
|
|||
// template <class T> struct Foo;
|
||||
// template<> struct Foo<int> { ... };
|
||||
// we don't want iwyu to recommend removing the 'forward declare' of Foo.
|
||||
//
|
||||
// Additionally, this type of decl is also used to represent explicit template
|
||||
// instantiations, in which case we want the full type, not only a forward
|
||||
// declaration.
|
||||
bool VisitClassTemplateSpecializationDecl(
|
||||
clang::ClassTemplateSpecializationDecl* decl) {
|
||||
if (CanIgnoreCurrentASTNode()) return true;
|
||||
ClassTemplateDecl* specialized_decl = decl->getSpecializedTemplate();
|
||||
ReportDeclForwardDeclareUse(CurrentLoc(), specialized_decl);
|
||||
|
||||
if (IsExplicitInstantiation(decl))
|
||||
ReportDeclUse(CurrentLoc(), specialized_decl);
|
||||
else
|
||||
ReportDeclForwardDeclareUse(CurrentLoc(), specialized_decl);
|
||||
|
||||
return Base::VisitClassTemplateSpecializationDecl(decl);
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ using clang::TemplateArgumentLoc;
|
|||
using clang::TemplateDecl;
|
||||
using clang::TemplateName;
|
||||
using clang::TemplateParameterList;
|
||||
using clang::TemplateSpecializationKind;
|
||||
using clang::TemplateSpecializationType;
|
||||
using clang::TranslationUnitDecl;
|
||||
using clang::Type;
|
||||
|
@ -155,6 +156,13 @@ void DumpASTNode(llvm::raw_ostream& ostream, const ASTNode* node) {
|
|||
}
|
||||
}
|
||||
|
||||
TemplateSpecializationKind GetTemplateSpecializationKind(const Decl* decl) {
|
||||
if (const auto* record = dyn_cast<CXXRecordDecl>(decl)) {
|
||||
return record->getTemplateSpecializationKind();
|
||||
}
|
||||
return clang::TSK_Undeclared;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
@ -942,12 +950,20 @@ bool IsFriendDecl(const Decl* decl) {
|
|||
return decl->getFriendObjectKind() != Decl::FOK_None;
|
||||
}
|
||||
|
||||
bool IsExplicitInstantiation(const clang::Decl* decl) {
|
||||
TemplateSpecializationKind kind = GetTemplateSpecializationKind(decl);
|
||||
return kind == clang::TSK_ExplicitInstantiationDeclaration ||
|
||||
kind == clang::TSK_ExplicitInstantiationDefinition;
|
||||
}
|
||||
|
||||
bool IsForwardDecl(const NamedDecl* decl) {
|
||||
if (const auto* record_decl = dyn_cast<RecordDecl>(decl)) {
|
||||
if (const auto* record_decl = dyn_cast<CXXRecordDecl>(decl)) {
|
||||
|
||||
return (!record_decl->getName().empty() &&
|
||||
!record_decl->isCompleteDefinition() &&
|
||||
!record_decl->isEmbeddedInDeclarator() &&
|
||||
!IsFriendDecl(record_decl));
|
||||
!IsFriendDecl(record_decl) &&
|
||||
!IsExplicitInstantiation(record_decl));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -594,6 +594,10 @@ bool IsDefaultNewOrDelete(const clang::FunctionDecl* decl,
|
|||
// Returns true if this decl is part of a friend decl.
|
||||
bool IsFriendDecl(const clang::Decl* decl);
|
||||
|
||||
// Returns true if this decl is an explicit template instantiation declaration
|
||||
// or definition.
|
||||
bool IsExplicitInstantiation(const clang::Decl* decl);
|
||||
|
||||
// Returns true if a named decl looks like a forward-declaration of a
|
||||
// class (rather than a definition, a friend declaration, or an 'in
|
||||
// place' declaration like 'struct Foo' in 'void MyFunc(struct Foo*);'
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
//===---- explicit_instantiation-template.h - test input file for iwyu ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_H_
|
||||
#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_H_
|
||||
|
||||
template<typename T> class Template {};
|
||||
|
||||
#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_H_
|
|
@ -0,0 +1,14 @@
|
|||
//===- explicit_instantiation-template_direct.h - test input file for iwyu ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_DIRECT_H_
|
||||
#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_DIRECT_H_
|
||||
|
||||
#include "explicit_instantiation-template.h"
|
||||
|
||||
#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_DIRECT_H_
|
|
@ -0,0 +1,48 @@
|
|||
//===-------- explicit_instantiation.cc - test input file for iwyu --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "explicit_instantiation-template_direct.h"
|
||||
|
||||
// Test that all explicit instantiations variants of the base template
|
||||
// require the full type:
|
||||
|
||||
// - Declaration and definition
|
||||
// IWYU: Template is...*explicit_instantiation-template.h
|
||||
extern template class Template<int>;
|
||||
// IWYU: Template is...*explicit_instantiation-template.h
|
||||
template class Template<int>;
|
||||
|
||||
// - Only declaration
|
||||
// IWYU: Template is...*explicit_instantiation-template.h
|
||||
extern template class Template<short>;
|
||||
|
||||
// - Only definition
|
||||
// IWYU: Template is...*explicit_instantiation-template.h
|
||||
template class Template<double>;
|
||||
|
||||
|
||||
// The explicit instantiation of a specialization only needs a declaration
|
||||
// of the base template
|
||||
// IWYU: Template needs a declaration
|
||||
template<> class Template<char> {};
|
||||
extern template class Template<char>;
|
||||
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/explicit_instantiation.cc should add these lines:
|
||||
#include "explicit_instantiation-template.h"
|
||||
|
||||
tests/cxx/explicit_instantiation.cc should remove these lines:
|
||||
- #include "explicit_instantiation-template_direct.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/explicit_instantiation.cc:
|
||||
#include "explicit_instantiation-template.h" // for Template
|
||||
|
||||
***** IWYU_SUMMARY */
|
Loading…
Reference in New Issue