forked from OSchip/llvm-project
Implement libclang support for using directives (cursor + visitation +
suppressing USRs). Also, fix up the source location information for using directives so that the declaration location refers to the namespace name. llvm-svn: 112693
This commit is contained in:
parent
110ed64fbb
commit
01a430134f
|
@ -996,8 +996,11 @@ enum CXCursorKind {
|
||||||
CXCursor_ClassTemplatePartialSpecialization = 32,
|
CXCursor_ClassTemplatePartialSpecialization = 32,
|
||||||
/** \brief A C++ namespace alias declaration. */
|
/** \brief A C++ namespace alias declaration. */
|
||||||
CXCursor_NamespaceAlias = 33,
|
CXCursor_NamespaceAlias = 33,
|
||||||
|
/** \brief A C++ using directive. */
|
||||||
|
CXCursor_UsingDirective = 34,
|
||||||
|
|
||||||
CXCursor_FirstDecl = CXCursor_UnexposedDecl,
|
CXCursor_FirstDecl = CXCursor_UnexposedDecl,
|
||||||
CXCursor_LastDecl = CXCursor_NamespaceAlias,
|
CXCursor_LastDecl = CXCursor_UsingDirective,
|
||||||
|
|
||||||
/* References */
|
/* References */
|
||||||
CXCursor_FirstRef = 40, /* Decl references */
|
CXCursor_FirstRef = 40, /* Decl references */
|
||||||
|
|
|
@ -1707,7 +1707,9 @@ public:
|
||||||
// artificial name, for all using-directives in order to store
|
// artificial name, for all using-directives in order to store
|
||||||
// them in DeclContext effectively.
|
// them in DeclContext effectively.
|
||||||
class UsingDirectiveDecl : public NamedDecl {
|
class UsingDirectiveDecl : public NamedDecl {
|
||||||
|
/// \brief The location of the "using" keyword.
|
||||||
|
SourceLocation UsingLoc;
|
||||||
|
|
||||||
/// SourceLocation - Location of 'namespace' token.
|
/// SourceLocation - Location of 'namespace' token.
|
||||||
SourceLocation NamespaceLoc;
|
SourceLocation NamespaceLoc;
|
||||||
|
|
||||||
|
@ -1719,10 +1721,6 @@ class UsingDirectiveDecl : public NamedDecl {
|
||||||
/// name, if any.
|
/// name, if any.
|
||||||
NestedNameSpecifier *Qualifier;
|
NestedNameSpecifier *Qualifier;
|
||||||
|
|
||||||
/// IdentLoc - Location of nominated namespace-name identifier.
|
|
||||||
// FIXME: We don't store location of scope specifier.
|
|
||||||
SourceLocation IdentLoc;
|
|
||||||
|
|
||||||
/// NominatedNamespace - Namespace nominated by using-directive.
|
/// NominatedNamespace - Namespace nominated by using-directive.
|
||||||
NamedDecl *NominatedNamespace;
|
NamedDecl *NominatedNamespace;
|
||||||
|
|
||||||
|
@ -1737,17 +1735,16 @@ class UsingDirectiveDecl : public NamedDecl {
|
||||||
return DeclarationName::getUsingDirectiveName();
|
return DeclarationName::getUsingDirectiveName();
|
||||||
}
|
}
|
||||||
|
|
||||||
UsingDirectiveDecl(DeclContext *DC, SourceLocation L,
|
UsingDirectiveDecl(DeclContext *DC, SourceLocation UsingLoc,
|
||||||
SourceLocation NamespcLoc,
|
SourceLocation NamespcLoc,
|
||||||
SourceRange QualifierRange,
|
SourceRange QualifierRange,
|
||||||
NestedNameSpecifier *Qualifier,
|
NestedNameSpecifier *Qualifier,
|
||||||
SourceLocation IdentLoc,
|
SourceLocation IdentLoc,
|
||||||
NamedDecl *Nominated,
|
NamedDecl *Nominated,
|
||||||
DeclContext *CommonAncestor)
|
DeclContext *CommonAncestor)
|
||||||
: NamedDecl(UsingDirective, DC, L, getName()),
|
: NamedDecl(UsingDirective, DC, IdentLoc, getName()), UsingLoc(UsingLoc),
|
||||||
NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange),
|
NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange),
|
||||||
Qualifier(Qualifier), IdentLoc(IdentLoc),
|
Qualifier(Qualifier), NominatedNamespace(Nominated),
|
||||||
NominatedNamespace(Nominated),
|
|
||||||
CommonAncestor(CommonAncestor) {
|
CommonAncestor(CommonAncestor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1756,18 +1753,10 @@ public:
|
||||||
/// that qualifies the namespace name.
|
/// that qualifies the namespace name.
|
||||||
SourceRange getQualifierRange() const { return QualifierRange; }
|
SourceRange getQualifierRange() const { return QualifierRange; }
|
||||||
|
|
||||||
/// \brief Set the source range of the nested-name-specifier that
|
|
||||||
/// qualifies the namespace name.
|
|
||||||
void setQualifierRange(SourceRange R) { QualifierRange = R; }
|
|
||||||
|
|
||||||
/// \brief Retrieve the nested-name-specifier that qualifies the
|
/// \brief Retrieve the nested-name-specifier that qualifies the
|
||||||
/// name of the namespace.
|
/// name of the namespace.
|
||||||
NestedNameSpecifier *getQualifier() const { return Qualifier; }
|
NestedNameSpecifier *getQualifier() const { return Qualifier; }
|
||||||
|
|
||||||
/// \brief Set the nested-name-specifier that qualifes the name of the
|
|
||||||
/// namespace.
|
|
||||||
void setQualifier(NestedNameSpecifier *NNS) { Qualifier = NNS; }
|
|
||||||
|
|
||||||
NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; }
|
NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; }
|
||||||
const NamedDecl *getNominatedNamespaceAsWritten() const {
|
const NamedDecl *getNominatedNamespaceAsWritten() const {
|
||||||
return NominatedNamespace;
|
return NominatedNamespace;
|
||||||
|
@ -1780,34 +1769,23 @@ public:
|
||||||
return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace();
|
return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// setNominatedNamespace - Set the namespace nominataed by the
|
|
||||||
/// using-directive.
|
|
||||||
void setNominatedNamespace(NamedDecl* NS);
|
|
||||||
|
|
||||||
/// \brief Returns the common ancestor context of this using-directive and
|
/// \brief Returns the common ancestor context of this using-directive and
|
||||||
/// its nominated namespace.
|
/// its nominated namespace.
|
||||||
DeclContext *getCommonAncestor() { return CommonAncestor; }
|
DeclContext *getCommonAncestor() { return CommonAncestor; }
|
||||||
const DeclContext *getCommonAncestor() const { return CommonAncestor; }
|
const DeclContext *getCommonAncestor() const { return CommonAncestor; }
|
||||||
|
|
||||||
/// \brief Set the common ancestor context of this using-directive and its
|
/// \brief Return the location of the "using" keyword.
|
||||||
/// nominated namespace.
|
SourceLocation getUsingLoc() const { return UsingLoc; }
|
||||||
void setCommonAncestor(DeclContext* Cxt) { CommonAncestor = Cxt; }
|
|
||||||
|
|
||||||
// FIXME: Could omit 'Key' in name.
|
// FIXME: Could omit 'Key' in name.
|
||||||
/// getNamespaceKeyLocation - Returns location of namespace keyword.
|
/// getNamespaceKeyLocation - Returns location of namespace keyword.
|
||||||
SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; }
|
SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; }
|
||||||
|
|
||||||
/// setNamespaceKeyLocation - Set the the location of the namespacekeyword.
|
|
||||||
void setNamespaceKeyLocation(SourceLocation L) { NamespaceLoc = L; }
|
|
||||||
|
|
||||||
/// getIdentLocation - Returns location of identifier.
|
/// getIdentLocation - Returns location of identifier.
|
||||||
SourceLocation getIdentLocation() const { return IdentLoc; }
|
SourceLocation getIdentLocation() const { return getLocation(); }
|
||||||
|
|
||||||
/// setIdentLocation - set the location of the identifier.
|
|
||||||
void setIdentLocation(SourceLocation L) { IdentLoc = L; }
|
|
||||||
|
|
||||||
static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC,
|
static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation L,
|
SourceLocation UsingLoc,
|
||||||
SourceLocation NamespaceLoc,
|
SourceLocation NamespaceLoc,
|
||||||
SourceRange QualifierRange,
|
SourceRange QualifierRange,
|
||||||
NestedNameSpecifier *Qualifier,
|
NestedNameSpecifier *Qualifier,
|
||||||
|
@ -1815,12 +1793,18 @@ public:
|
||||||
NamedDecl *Nominated,
|
NamedDecl *Nominated,
|
||||||
DeclContext *CommonAncestor);
|
DeclContext *CommonAncestor);
|
||||||
|
|
||||||
|
SourceRange getSourceRange() const {
|
||||||
|
return SourceRange(UsingLoc, getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
static bool classof(const UsingDirectiveDecl *D) { return true; }
|
static bool classof(const UsingDirectiveDecl *D) { return true; }
|
||||||
static bool classofKind(Kind K) { return K == UsingDirective; }
|
static bool classofKind(Kind K) { return K == UsingDirective; }
|
||||||
|
|
||||||
// Friend for getUsingDirectiveName.
|
// Friend for getUsingDirectiveName.
|
||||||
friend class DeclContext;
|
friend class DeclContext;
|
||||||
|
|
||||||
|
friend class ASTDeclReader;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// NamespaceAliasDecl - Represents a C++ namespace alias. For example:
|
/// NamespaceAliasDecl - Represents a C++ namespace alias. For example:
|
||||||
|
|
|
@ -989,14 +989,8 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
|
||||||
return cast_or_null<NamespaceDecl>(NominatedNamespace);
|
return cast_or_null<NamespaceDecl>(NominatedNamespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsingDirectiveDecl::setNominatedNamespace(NamedDecl* ND) {
|
|
||||||
assert((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) &&
|
|
||||||
"expected a NamespaceDecl or NamespaceAliasDecl");
|
|
||||||
NominatedNamespace = ND;
|
|
||||||
}
|
|
||||||
|
|
||||||
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
|
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation L,
|
SourceLocation UsingLoc,
|
||||||
SourceLocation AliasLoc,
|
SourceLocation AliasLoc,
|
||||||
IdentifierInfo *Alias,
|
IdentifierInfo *Alias,
|
||||||
SourceRange QualifierRange,
|
SourceRange QualifierRange,
|
||||||
|
@ -1005,7 +999,7 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
|
||||||
NamedDecl *Namespace) {
|
NamedDecl *Namespace) {
|
||||||
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
|
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
|
||||||
Namespace = NS->getOriginalNamespace();
|
Namespace = NS->getOriginalNamespace();
|
||||||
return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange,
|
return new (C) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias, QualifierRange,
|
||||||
Qualifier, IdentLoc, Namespace);
|
Qualifier, IdentLoc, Namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -676,13 +676,12 @@ void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
|
||||||
|
|
||||||
void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
|
void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
|
||||||
VisitNamedDecl(D);
|
VisitNamedDecl(D);
|
||||||
D->setNamespaceKeyLocation(Reader.ReadSourceLocation(Record, Idx));
|
D->UsingLoc = Reader.ReadSourceLocation(Record, Idx);
|
||||||
D->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
|
D->NamespaceLoc = Reader.ReadSourceLocation(Record, Idx);
|
||||||
D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
|
D->QualifierRange = Reader.ReadSourceRange(Record, Idx);
|
||||||
D->setIdentLocation(Reader.ReadSourceLocation(Record, Idx));
|
D->Qualifier = Reader.ReadNestedNameSpecifier(Record, Idx);
|
||||||
D->setNominatedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
|
D->NominatedNamespace = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
|
||||||
D->setCommonAncestor(cast_or_null<DeclContext>(
|
D->CommonAncestor = cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]));
|
||||||
Reader.GetDecl(Record[Idx++])));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
|
void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
|
||||||
|
|
|
@ -658,10 +658,10 @@ void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
|
||||||
|
|
||||||
void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
|
void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
|
||||||
VisitNamedDecl(D);
|
VisitNamedDecl(D);
|
||||||
|
Writer.AddSourceLocation(D->getUsingLoc(), Record);
|
||||||
Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record);
|
Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record);
|
||||||
Writer.AddSourceRange(D->getQualifierRange(), Record);
|
Writer.AddSourceRange(D->getQualifierRange(), Record);
|
||||||
Writer.AddNestedNameSpecifier(D->getQualifier(), Record);
|
Writer.AddNestedNameSpecifier(D->getQualifier(), Record);
|
||||||
Writer.AddSourceLocation(D->getIdentLocation(), Record);
|
|
||||||
Writer.AddDeclRef(D->getNominatedNamespace(), Record);
|
Writer.AddDeclRef(D->getNominatedNamespace(), Record);
|
||||||
Writer.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()), Record);
|
Writer.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()), Record);
|
||||||
Code = serialization::DECL_USING_DIRECTIVE;
|
Code = serialization::DECL_USING_DIRECTIVE;
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace std {
|
||||||
namespace std98 = std;
|
namespace std98 = std;
|
||||||
namespace std0x = std98;
|
namespace std0x = std98;
|
||||||
|
|
||||||
// FIXME: using directives
|
using namespace std0x;
|
||||||
|
|
||||||
// RUN: c-index-test -test-load-source all %s | FileCheck %s
|
// RUN: c-index-test -test-load-source all %s | FileCheck %s
|
||||||
// CHECK: load-namespaces.cpp:3:11: Namespace=std:3:11 (Definition) Extent=[3:11 - 7:2]
|
// CHECK: load-namespaces.cpp:3:11: Namespace=std:3:11 (Definition) Extent=[3:11 - 7:2]
|
||||||
|
@ -25,3 +25,5 @@ namespace std0x = std98;
|
||||||
// CHECK: load-namespaces.cpp:13:19: NamespaceRef=std:3:11 Extent=[13:19 - 13:22]
|
// CHECK: load-namespaces.cpp:13:19: NamespaceRef=std:3:11 Extent=[13:19 - 13:22]
|
||||||
// CHECK: load-namespaces.cpp:14:11: NamespaceAlias=std0x:14:11 Extent=[14:1 - 14:24]
|
// CHECK: load-namespaces.cpp:14:11: NamespaceAlias=std0x:14:11 Extent=[14:1 - 14:24]
|
||||||
// CHECK: load-namespaces.cpp:14:19: NamespaceRef=std98:13:11 Extent=[14:19 - 14:24]
|
// CHECK: load-namespaces.cpp:14:19: NamespaceRef=std98:13:11 Extent=[14:19 - 14:24]
|
||||||
|
// CHECK: load-namespaces.cpp:16:17: UsingDirective=:16:17 Extent=[16:1 - 16:22]
|
||||||
|
// CHECK: load-namespaces.cpp:16:17: NamespaceRef=std0x:14:11 Extent=[16:17 - 16:22]
|
||||||
|
|
|
@ -57,6 +57,8 @@ extern "C" {
|
||||||
|
|
||||||
namespace foo_alias = foo;
|
namespace foo_alias = foo;
|
||||||
|
|
||||||
|
using namespace foo;
|
||||||
|
|
||||||
// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s
|
// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s
|
||||||
// CHECK: usrs.cpp c:@N@foo Extent=[1:11 - 4:2]
|
// CHECK: usrs.cpp c:@N@foo Extent=[1:11 - 4:2]
|
||||||
// CHECK: usrs.cpp c:@N@foo@x Extent=[2:3 - 2:8]
|
// CHECK: usrs.cpp c:@N@foo@x Extent=[2:3 - 2:8]
|
||||||
|
|
|
@ -317,7 +317,8 @@ public:
|
||||||
bool VisitLinkageSpecDecl(LinkageSpecDecl *D);
|
bool VisitLinkageSpecDecl(LinkageSpecDecl *D);
|
||||||
bool VisitNamespaceDecl(NamespaceDecl *D);
|
bool VisitNamespaceDecl(NamespaceDecl *D);
|
||||||
bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
|
bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
|
||||||
|
bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
|
||||||
|
|
||||||
// Name visitor
|
// Name visitor
|
||||||
bool VisitDeclarationNameInfo(DeclarationNameInfo Name);
|
bool VisitDeclarationNameInfo(DeclarationNameInfo Name);
|
||||||
|
|
||||||
|
@ -871,6 +872,13 @@ bool CursorVisitor::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
|
||||||
D->getTargetNameLoc(), TU));
|
D->getTargetNameLoc(), TU));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CursorVisitor::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
|
||||||
|
// FIXME: Visit nested-name-specifier
|
||||||
|
|
||||||
|
return Visit(MakeCursorNamespaceRef(D->getNominatedNamespaceAsWritten(),
|
||||||
|
D->getIdentLocation(), TU));
|
||||||
|
}
|
||||||
|
|
||||||
bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
|
bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
|
||||||
switch (Name.getName().getNameKind()) {
|
switch (Name.getName().getNameKind()) {
|
||||||
case clang::DeclarationName::Identifier:
|
case clang::DeclarationName::Identifier:
|
||||||
|
@ -2022,6 +2030,9 @@ static CXString getDeclSpelling(Decl *D) {
|
||||||
// ObjCCategoryImplDecl returns the category name.
|
// ObjCCategoryImplDecl returns the category name.
|
||||||
return createCXString(CIMP->getIdentifier()->getNameStart());
|
return createCXString(CIMP->getIdentifier()->getNameStart());
|
||||||
|
|
||||||
|
if (isa<UsingDirectiveDecl>(D))
|
||||||
|
return createCXString("");
|
||||||
|
|
||||||
llvm::SmallString<1024> S;
|
llvm::SmallString<1024> S;
|
||||||
llvm::raw_svector_ostream os(S);
|
llvm::raw_svector_ostream os(S);
|
||||||
ND->printName(os);
|
ND->printName(os);
|
||||||
|
@ -2219,6 +2230,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
|
||||||
return createCXString("ClassTemplatePartialSpecialization");
|
return createCXString("ClassTemplatePartialSpecialization");
|
||||||
case CXCursor_NamespaceAlias:
|
case CXCursor_NamespaceAlias:
|
||||||
return createCXString("NamespaceAlias");
|
return createCXString("NamespaceAlias");
|
||||||
|
case CXCursor_UsingDirective:
|
||||||
|
return createCXString("UsingDirective");
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm_unreachable("Unhandled CXCursorKind");
|
llvm_unreachable("Unhandled CXCursorKind");
|
||||||
|
|
|
@ -82,9 +82,11 @@ public:
|
||||||
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
|
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
|
||||||
void VisitLinkageSpecDecl(LinkageSpecDecl *D) {
|
void VisitLinkageSpecDecl(LinkageSpecDecl *D) {
|
||||||
IgnoreResults = true;
|
IgnoreResults = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
|
||||||
|
IgnoreResults = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate the string component containing the location of the
|
/// Generate the string component containing the location of the
|
||||||
/// declaration.
|
/// declaration.
|
||||||
bool GenLoc(const Decl *D);
|
bool GenLoc(const Decl *D);
|
||||||
|
|
|
@ -69,6 +69,7 @@ static CXCursorKind GetCursorKind(Decl *D) {
|
||||||
case Decl::ClassTemplate: return CXCursor_ClassTemplate;
|
case Decl::ClassTemplate: return CXCursor_ClassTemplate;
|
||||||
case Decl::ClassTemplatePartialSpecialization:
|
case Decl::ClassTemplatePartialSpecialization:
|
||||||
return CXCursor_ClassTemplatePartialSpecialization;
|
return CXCursor_ClassTemplatePartialSpecialization;
|
||||||
|
case Decl::UsingDirective: return CXCursor_UsingDirective;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
||||||
|
|
Loading…
Reference in New Issue