forked from OSchip/llvm-project
Fix the source range for a member access expression that includes a
nested-name-specifier and improve the detection of implicit 'this' bases. Fixes <rdar://problem/8750392>. llvm-svn: 126880
This commit is contained in:
parent
fb55f851a5
commit
25b7e05b72
|
@ -536,6 +536,9 @@ public:
|
||||||
/// temporary object of the given class type.
|
/// temporary object of the given class type.
|
||||||
bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const;
|
bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const;
|
||||||
|
|
||||||
|
/// \brief Whether this expression is an implicit reference to 'this' in C++.
|
||||||
|
bool isImplicitCXXThis() const;
|
||||||
|
|
||||||
const Expr *IgnoreParens() const {
|
const Expr *IgnoreParens() const {
|
||||||
return const_cast<Expr*>(this)->IgnoreParens();
|
return const_cast<Expr*>(this)->IgnoreParens();
|
||||||
}
|
}
|
||||||
|
@ -2070,21 +2073,15 @@ public:
|
||||||
SourceLocation getMemberLoc() const { return MemberLoc; }
|
SourceLocation getMemberLoc() const { return MemberLoc; }
|
||||||
void setMemberLoc(SourceLocation L) { MemberLoc = L; }
|
void setMemberLoc(SourceLocation L) { MemberLoc = L; }
|
||||||
|
|
||||||
SourceRange getSourceRange() const {
|
SourceRange getSourceRange() const;
|
||||||
// If we have an implicit base (like a C++ implicit this),
|
|
||||||
// make sure not to return its location
|
|
||||||
// FIXME: This isn't the way to do the above.
|
|
||||||
SourceLocation EndLoc = (HasExplicitTemplateArgumentList)
|
|
||||||
? getRAngleLoc() : getMemberNameInfo().getEndLoc();
|
|
||||||
|
|
||||||
SourceLocation BaseLoc = getBase()->getLocStart();
|
|
||||||
if (BaseLoc.isInvalid())
|
|
||||||
return SourceRange(MemberLoc, EndLoc);
|
|
||||||
return SourceRange(BaseLoc, EndLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation getExprLoc() const { return MemberLoc; }
|
SourceLocation getExprLoc() const { return MemberLoc; }
|
||||||
|
|
||||||
|
/// \brief Determine whether the base of this explicit is implicit.
|
||||||
|
bool isImplicitAccess() const {
|
||||||
|
return getBase() && getBase()->isImplicitCXXThis();
|
||||||
|
}
|
||||||
|
|
||||||
static bool classof(const Stmt *T) {
|
static bool classof(const Stmt *T) {
|
||||||
return T->getStmtClass() == MemberExprClass;
|
return T->getStmtClass() == MemberExprClass;
|
||||||
}
|
}
|
||||||
|
|
|
@ -943,6 +943,28 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceRange MemberExpr::getSourceRange() const {
|
||||||
|
SourceLocation StartLoc;
|
||||||
|
if (isImplicitAccess()) {
|
||||||
|
if (hasQualifier())
|
||||||
|
StartLoc = getQualifierLoc().getBeginLoc();
|
||||||
|
else
|
||||||
|
StartLoc = MemberLoc;
|
||||||
|
} else {
|
||||||
|
// FIXME: We don't want this to happen. Rather, we should be able to
|
||||||
|
// detect all kinds of implicit accesses more cleanly.
|
||||||
|
StartLoc = getBase()->getLocStart();
|
||||||
|
if (StartLoc.isInvalid())
|
||||||
|
StartLoc = MemberLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLocation EndLoc =
|
||||||
|
HasExplicitTemplateArgumentList? getRAngleLoc()
|
||||||
|
: getMemberNameInfo().getEndLoc();
|
||||||
|
|
||||||
|
return SourceRange(StartLoc, EndLoc);
|
||||||
|
}
|
||||||
|
|
||||||
const char *CastExpr::getCastKindName() const {
|
const char *CastExpr::getCastKindName() const {
|
||||||
switch (getCastKind()) {
|
switch (getCastKind()) {
|
||||||
case CK_Dependent:
|
case CK_Dependent:
|
||||||
|
@ -2017,6 +2039,42 @@ bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Expr::isImplicitCXXThis() const {
|
||||||
|
const Expr *E = this;
|
||||||
|
|
||||||
|
// Strip away parentheses and casts we don't care about.
|
||||||
|
while (true) {
|
||||||
|
if (const ParenExpr *Paren = dyn_cast<ParenExpr>(E)) {
|
||||||
|
E = Paren->getSubExpr();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
|
||||||
|
if (ICE->getCastKind() == CK_NoOp ||
|
||||||
|
ICE->getCastKind() == CK_LValueToRValue ||
|
||||||
|
ICE->getCastKind() == CK_DerivedToBase ||
|
||||||
|
ICE->getCastKind() == CK_UncheckedDerivedToBase) {
|
||||||
|
E = ICE->getSubExpr();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const UnaryOperator* UnOp = dyn_cast<UnaryOperator>(E)) {
|
||||||
|
if (UnOp->getOpcode() == UO_Extension) {
|
||||||
|
E = UnOp->getSubExpr();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const CXXThisExpr *This = dyn_cast<CXXThisExpr>(E))
|
||||||
|
return This->isImplicit();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// hasAnyTypeDependentArguments - Determines if any of the expressions
|
/// hasAnyTypeDependentArguments - Determines if any of the expressions
|
||||||
/// in Exprs is type-dependent.
|
/// in Exprs is type-dependent.
|
||||||
bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) {
|
bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) {
|
||||||
|
|
|
@ -783,46 +783,11 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determine whether this expression is an implicit C++ 'this'.
|
|
||||||
static bool isImplicitThis(const Expr *E) {
|
|
||||||
// Strip away parentheses and casts we don't care about.
|
|
||||||
while (true) {
|
|
||||||
if (const ParenExpr *Paren = dyn_cast<ParenExpr>(E)) {
|
|
||||||
E = Paren->getSubExpr();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
|
|
||||||
if (ICE->getCastKind() == CK_NoOp ||
|
|
||||||
ICE->getCastKind() == CK_LValueToRValue ||
|
|
||||||
ICE->getCastKind() == CK_DerivedToBase ||
|
|
||||||
ICE->getCastKind() == CK_UncheckedDerivedToBase) {
|
|
||||||
E = ICE->getSubExpr();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const UnaryOperator* UnOp = dyn_cast<UnaryOperator>(E)) {
|
|
||||||
if (UnOp->getOpcode() == UO_Extension) {
|
|
||||||
E = UnOp->getSubExpr();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const CXXThisExpr *This = dyn_cast<CXXThisExpr>(E))
|
|
||||||
return This->isImplicit();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CXXDependentScopeMemberExpr::isImplicitAccess() const {
|
bool CXXDependentScopeMemberExpr::isImplicitAccess() const {
|
||||||
if (Base == 0)
|
if (Base == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return isImplicitThis(cast<Expr>(Base));
|
return cast<Expr>(Base)->isImplicitCXXThis();
|
||||||
}
|
}
|
||||||
|
|
||||||
UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
|
UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
|
||||||
|
@ -851,7 +816,7 @@ bool UnresolvedMemberExpr::isImplicitAccess() const {
|
||||||
if (Base == 0)
|
if (Base == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return isImplicitThis(cast<Expr>(Base));
|
return cast<Expr>(Base)->isImplicitCXXThis();
|
||||||
}
|
}
|
||||||
|
|
||||||
UnresolvedMemberExpr *
|
UnresolvedMemberExpr *
|
||||||
|
|
|
@ -126,7 +126,18 @@ struct X7 {
|
||||||
typedef outer_alias::inner::apply_meta<T_type, U_type::template apply> type;
|
typedef outer_alias::inner::apply_meta<T_type, U_type::template apply> type;
|
||||||
};
|
};
|
||||||
|
|
||||||
// RUN: c-index-test -test-annotate-tokens=%s:13:1:128:1 %s | FileCheck %s
|
struct X8 {
|
||||||
|
void f();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X9 : X8 {
|
||||||
|
typedef X8 inherited;
|
||||||
|
void f() {
|
||||||
|
inherited::f();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// RUN: c-index-test -test-annotate-tokens=%s:13:1:137:1 %s | FileCheck %s
|
||||||
|
|
||||||
// CHECK: Keyword: "using" [14:1 - 14:6] UsingDeclaration=vector[4:12]
|
// CHECK: Keyword: "using" [14:1 - 14:6] UsingDeclaration=vector[4:12]
|
||||||
// CHECK: Identifier: "outer_alias" [14:7 - 14:18] NamespaceRef=outer_alias:10:11
|
// CHECK: Identifier: "outer_alias" [14:7 - 14:18] NamespaceRef=outer_alias:10:11
|
||||||
|
@ -449,3 +460,7 @@ struct X7 {
|
||||||
// CHECK: Punctuation: ">" [126:72 - 126:73] TypedefDecl=type:126:74 (Definition)
|
// CHECK: Punctuation: ">" [126:72 - 126:73] TypedefDecl=type:126:74 (Definition)
|
||||||
// CHECK: Identifier: "type" [126:74 - 126:78] TypedefDecl=type:126:74 (Definition)
|
// CHECK: Identifier: "type" [126:74 - 126:78] TypedefDecl=type:126:74 (Definition)
|
||||||
|
|
||||||
|
// Member access expressions
|
||||||
|
// CHECK: Identifier: "inherited" [136:5 - 136:14] TypeRef=inherited:134:14
|
||||||
|
// CHECK: Punctuation: "::" [136:14 - 136:16] MemberRefExpr=f:130:8
|
||||||
|
// CHECK: Identifier: "f" [136:16 - 136:17] MemberRefExpr=f:130:8
|
||||||
|
|
|
@ -1979,11 +1979,7 @@ void EnqueueVisitor::VisitMemberExpr(MemberExpr *M) {
|
||||||
// visit it.
|
// visit it.
|
||||||
// FIXME: If we ever want to show these implicit accesses, this will be
|
// FIXME: If we ever want to show these implicit accesses, this will be
|
||||||
// unfortunate. However, clang_getCursor() relies on this behavior.
|
// unfortunate. However, clang_getCursor() relies on this behavior.
|
||||||
if (CXXThisExpr *This
|
if (!M->isImplicitAccess())
|
||||||
= llvm::dyn_cast<CXXThisExpr>(M->getBase()->IgnoreParenImpCasts()))
|
|
||||||
if (This->isImplicit())
|
|
||||||
return;
|
|
||||||
|
|
||||||
AddStmt(M->getBase());
|
AddStmt(M->getBase());
|
||||||
}
|
}
|
||||||
void EnqueueVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
|
void EnqueueVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
|
||||||
|
|
Loading…
Reference in New Issue