Tracks source location of the selector name within ObjCSelectorExpr (#211623)
Store selector name location alongside the existing @-sign and paren locations, exposed via getSelectorLoc(), so tools and diagnostics can reference the name rather than the @selector keyword. While here, rename things to disambiguate locations.
This commit is contained in:
parent
88d26e7196
commit
326d563cf7
7 changed files with 203 additions and 90 deletions
|
|
@ -485,13 +485,13 @@ public:
|
|||
/// ObjCSelectorExpr used for \@selector in Objective-C.
|
||||
class ObjCSelectorExpr : public Expr {
|
||||
Selector SelName;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
SourceLocation AtLoc, SelNameLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
ObjCSelectorExpr(QualType T, Selector selInfo, SourceLocation at,
|
||||
SourceLocation rp)
|
||||
SourceLocation selNameLoc, SourceLocation rp)
|
||||
: Expr(ObjCSelectorExprClass, T, VK_PRValue, OK_Ordinary),
|
||||
SelName(selInfo), AtLoc(at), RParenLoc(rp) {
|
||||
SelName(selInfo), AtLoc(at), SelNameLoc(selNameLoc), RParenLoc(rp) {
|
||||
setDependence(ExprDependence::None);
|
||||
}
|
||||
explicit ObjCSelectorExpr(EmptyShell Empty)
|
||||
|
|
@ -501,8 +501,10 @@ public:
|
|||
void setSelector(Selector S) { SelName = S; }
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getSelectorNameLoc() const { return SelNameLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
void setSelectorNameLoc(SourceLocation L) { SelNameLoc = L; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; }
|
||||
|
|
|
|||
|
|
@ -691,7 +691,8 @@ public:
|
|||
|
||||
/// ParseObjCSelectorExpression - Build selector expression for \@selector
|
||||
ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc,
|
||||
SourceLocation SelLoc,
|
||||
SourceLocation SelKWLoc,
|
||||
SourceLocation SelNameLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation RParenLoc,
|
||||
bool WarnMultipleSelectors);
|
||||
|
|
|
|||
|
|
@ -3199,13 +3199,13 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
|
|||
}
|
||||
|
||||
ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
|
||||
SourceLocation SelectorLoc = ConsumeToken();
|
||||
SourceLocation SelectorKeywordLoc = ConsumeToken();
|
||||
|
||||
if (Tok.isNot(tok::l_paren))
|
||||
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
|
||||
|
||||
SmallVector<const IdentifierInfo *, 12> KeyIdents;
|
||||
SourceLocation sLoc;
|
||||
SourceLocation SelectorNameLoc;
|
||||
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
T.consumeOpen();
|
||||
|
|
@ -3219,7 +3219,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
|
|||
return ExprError();
|
||||
}
|
||||
|
||||
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
|
||||
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelectorNameLoc);
|
||||
if (!SelIdent && // missing selector name.
|
||||
Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
|
||||
return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
|
||||
|
|
@ -3259,8 +3259,8 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
|
|||
T.consumeClose();
|
||||
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
|
||||
return Actions.ObjC().ParseObjCSelectorExpression(
|
||||
Sel, AtLoc, SelectorLoc, T.getOpenLocation(), T.getCloseLocation(),
|
||||
!HasOptionalParen);
|
||||
Sel, AtLoc, SelectorKeywordLoc, SelectorNameLoc, T.getOpenLocation(),
|
||||
T.getCloseLocation(), !HasOptionalParen);
|
||||
}
|
||||
|
||||
void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
|
||||
|
|
|
|||
|
|
@ -1416,12 +1416,10 @@ static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ExprResult SemaObjC::ParseObjCSelectorExpression(Selector Sel,
|
||||
SourceLocation AtLoc,
|
||||
SourceLocation SelLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation RParenLoc,
|
||||
bool WarnMultipleSelectors) {
|
||||
ExprResult SemaObjC::ParseObjCSelectorExpression(
|
||||
Selector Sel, SourceLocation AtLoc, SourceLocation SelKWLoc,
|
||||
SourceLocation SelNameLoc, SourceLocation LParenLoc,
|
||||
SourceLocation RParenLoc, bool WarnMultipleSelectors) {
|
||||
ASTContext &Context = getASTContext();
|
||||
ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
|
||||
SourceRange(LParenLoc, RParenLoc));
|
||||
|
|
@ -1433,12 +1431,13 @@ ExprResult SemaObjC::ParseObjCSelectorExpression(Selector Sel,
|
|||
Selector MatchedSel = OM->getSelector();
|
||||
SourceRange SelectorRange(LParenLoc.getLocWithOffset(1),
|
||||
RParenLoc.getLocWithOffset(-1));
|
||||
Diag(SelLoc, diag::warn_undeclared_selector_with_typo)
|
||||
<< Sel << MatchedSel
|
||||
<< FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
|
||||
Diag(SelKWLoc, diag::warn_undeclared_selector_with_typo)
|
||||
<< Sel << MatchedSel
|
||||
<< FixItHint::CreateReplacement(SelectorRange,
|
||||
MatchedSel.getAsString());
|
||||
|
||||
} else
|
||||
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
|
||||
Diag(SelKWLoc, diag::warn_undeclared_selector) << Sel;
|
||||
} else {
|
||||
DiagnoseMismatchedSelectors(SemaRef, AtLoc, Method, LParenLoc, RParenLoc,
|
||||
WarnMultipleSelectors);
|
||||
|
|
@ -1509,7 +1508,7 @@ ExprResult SemaObjC::ParseObjCSelectorExpression(Selector Sel,
|
|||
}
|
||||
}
|
||||
QualType Ty = Context.getObjCSelType();
|
||||
return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
|
||||
return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, SelNameLoc, RParenLoc);
|
||||
}
|
||||
|
||||
ExprResult SemaObjC::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
|
||||
|
|
|
|||
|
|
@ -1573,6 +1573,7 @@ void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
|
|||
VisitExpr(E);
|
||||
E->setSelector(Record.readSelector());
|
||||
E->setAtLoc(readSourceLocation());
|
||||
E->setSelectorNameLoc(readSourceLocation());
|
||||
E->setRParenLoc(readSourceLocation());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1536,6 +1536,7 @@ void ASTStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
|
|||
VisitExpr(E);
|
||||
Record.AddSelectorRef(E->getSelector());
|
||||
Record.AddSourceLocation(E->getAtLoc());
|
||||
Record.AddSourceLocation(E->getSelectorNameLoc());
|
||||
Record.AddSourceLocation(E->getRParenLoc());
|
||||
Code = serialization::EXPR_OBJC_SELECTOR_EXPR;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,17 +15,23 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "MatchVerifier.h"
|
||||
#include "clang/AST/ASTConcept.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTFwd.h"
|
||||
#include "clang/AST/ASTTypeTraits.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/ExprConcepts.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/ASTMatchers/ASTMatchersInternal.h"
|
||||
#include "clang/Testing/CommandLineArgs.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Testing/Annotations/Annotations.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <string>
|
||||
|
||||
using namespace clang;
|
||||
using namespace clang::ast_matchers;
|
||||
|
|
@ -177,7 +183,7 @@ TEST(MemberExpr, ImplicitMemberRange) {
|
|||
class MemberExprArrowLocVerifier : public RangeVerifier<MemberExpr> {
|
||||
protected:
|
||||
SourceRange getRange(const MemberExpr &Node) override {
|
||||
return Node.getOperatorLoc();
|
||||
return Node.getOperatorLoc();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -209,8 +215,7 @@ TEST(MemberExpr, ImplicitArrowRange) {
|
|||
TEST(VarDecl, VMTypeFixedVarDeclRange) {
|
||||
RangeVerifier<VarDecl> Verifier;
|
||||
Verifier.expectRange(1, 1, 1, 23);
|
||||
EXPECT_TRUE(Verifier.match("int a[(int)(void*)1234];",
|
||||
varDecl(), Lang_C89));
|
||||
EXPECT_TRUE(Verifier.match("int a[(int)(void*)1234];", varDecl(), Lang_C89));
|
||||
}
|
||||
|
||||
TEST(TypeLoc, IntRange) {
|
||||
|
|
@ -366,9 +371,10 @@ TEST(CXXConstructorDecl, DeletedCtorLocRange) {
|
|||
TEST(CompoundLiteralExpr, CompoundVectorLiteralRange) {
|
||||
RangeVerifier<CompoundLiteralExpr> Verifier;
|
||||
Verifier.expectRange(2, 11, 2, 22);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"typedef int int2 __attribute__((ext_vector_type(2)));\n"
|
||||
"int2 i2 = (int2){1, 2};", compoundLiteralExpr()));
|
||||
EXPECT_TRUE(
|
||||
Verifier.match("typedef int int2 __attribute__((ext_vector_type(2)));\n"
|
||||
"int2 i2 = (int2){1, 2};",
|
||||
compoundLiteralExpr()));
|
||||
}
|
||||
|
||||
TEST(CompoundLiteralExpr, ParensCompoundVectorLiteralRange) {
|
||||
|
|
@ -383,17 +389,19 @@ TEST(CompoundLiteralExpr, ParensCompoundVectorLiteralRange) {
|
|||
TEST(InitListExpr, VectorLiteralListBraceRange) {
|
||||
RangeVerifier<InitListExpr> Verifier;
|
||||
Verifier.expectRange(2, 17, 2, 22);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"typedef int int2 __attribute__((ext_vector_type(2)));\n"
|
||||
"int2 i2 = (int2){1, 2};", initListExpr()));
|
||||
EXPECT_TRUE(
|
||||
Verifier.match("typedef int int2 __attribute__((ext_vector_type(2)));\n"
|
||||
"int2 i2 = (int2){1, 2};",
|
||||
initListExpr()));
|
||||
}
|
||||
|
||||
TEST(InitListExpr, VectorLiteralInitListParens) {
|
||||
RangeVerifier<InitListExpr> Verifier;
|
||||
Verifier.expectRange(2, 26, 2, 31);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"typedef int int2 __attribute__((ext_vector_type(2)));\n"
|
||||
"constant int2 i2 = (int2)(1, 2);", initListExpr(), Lang_OpenCL));
|
||||
EXPECT_TRUE(
|
||||
Verifier.match("typedef int int2 __attribute__((ext_vector_type(2)));\n"
|
||||
"constant int2 i2 = (int2)(1, 2);",
|
||||
initListExpr(), Lang_OpenCL));
|
||||
}
|
||||
|
||||
class TemplateAngleBracketLocRangeVerifier : public RangeVerifier<TypeLoc> {
|
||||
|
|
@ -409,10 +417,10 @@ protected:
|
|||
TEST(TemplateSpecializationTypeLoc, AngleBracketLocations) {
|
||||
TemplateAngleBracketLocRangeVerifier Verifier;
|
||||
Verifier.expectRange(2, 8, 2, 10);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"template<typename T> struct A {}; struct B{}; void f(\n"
|
||||
"const A<B>&);",
|
||||
loc(templateSpecializationType())));
|
||||
EXPECT_TRUE(
|
||||
Verifier.match("template<typename T> struct A {}; struct B{}; void f(\n"
|
||||
"const A<B>&);",
|
||||
loc(templateSpecializationType())));
|
||||
}
|
||||
|
||||
TEST(CXXNewExpr, TypeParenRange) {
|
||||
|
|
@ -434,12 +442,11 @@ protected:
|
|||
TEST(UnaryTransformTypeLoc, ParensRange) {
|
||||
UnaryTransformTypeLocParensRangeVerifier Verifier;
|
||||
Verifier.expectRange(3, 26, 3, 28);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"template <typename T>\n"
|
||||
"struct S {\n"
|
||||
"typedef __underlying_type(T) type;\n"
|
||||
"};",
|
||||
loc(unaryTransformType())));
|
||||
EXPECT_TRUE(Verifier.match("template <typename T>\n"
|
||||
"struct S {\n"
|
||||
"typedef __underlying_type(T) type;\n"
|
||||
"};",
|
||||
loc(unaryTransformType())));
|
||||
}
|
||||
|
||||
TEST(PointerTypeLoc, StarLoc) {
|
||||
|
|
@ -451,11 +458,11 @@ TEST(PointerTypeLoc, StarLoc) {
|
|||
SourceManager &SM = AST->getSourceManager();
|
||||
auto &Ctx = AST->getASTContext();
|
||||
|
||||
auto *VD = selectFirst<VarDecl>("vd", match(varDecl(hasName("var")).bind("vd"), Ctx));
|
||||
auto *VD = selectFirst<VarDecl>(
|
||||
"vd", match(varDecl(hasName("var")).bind("vd"), Ctx));
|
||||
ASSERT_NE(VD, nullptr);
|
||||
|
||||
auto TL =
|
||||
VD->getTypeSourceInfo()->getTypeLoc().castAs<PointerTypeLoc>();
|
||||
auto TL = VD->getTypeSourceInfo()->getTypeLoc().castAs<PointerTypeLoc>();
|
||||
ASSERT_EQ(SM.getFileOffset(TL.getStarLoc()), Example.point("star"));
|
||||
}
|
||||
|
||||
|
|
@ -469,47 +476,49 @@ TEST(PointerTypeLoc, StarLocBehindSugar) {
|
|||
SourceManager &SM = AST->getSourceManager();
|
||||
auto &Ctx = AST->getASTContext();
|
||||
|
||||
auto *VD = selectFirst<VarDecl>("vd", match(varDecl(hasName("var")).bind("vd"), Ctx));
|
||||
auto *VD = selectFirst<VarDecl>(
|
||||
"vd", match(varDecl(hasName("var")).bind("vd"), Ctx));
|
||||
ASSERT_NE(VD, nullptr);
|
||||
|
||||
auto TL = VD->getTypeSourceInfo()->getTypeLoc().castAs<PointerTypeLoc>();
|
||||
EXPECT_EQ(SM.getFileOffset(TL.getStarLoc()), Example.point("2nd"));
|
||||
|
||||
// Cast intermediate TypeLoc to make sure the structure matches expectations.
|
||||
auto InnerPtrTL = TL.getPointeeLoc().castAs<AttributedTypeLoc>()
|
||||
.getNextTypeLoc().castAs<MacroQualifiedTypeLoc>()
|
||||
.getNextTypeLoc().castAs<AttributedTypeLoc>()
|
||||
.getNextTypeLoc().castAs<PointerTypeLoc>();
|
||||
auto InnerPtrTL = TL.getPointeeLoc()
|
||||
.castAs<AttributedTypeLoc>()
|
||||
.getNextTypeLoc()
|
||||
.castAs<MacroQualifiedTypeLoc>()
|
||||
.getNextTypeLoc()
|
||||
.castAs<AttributedTypeLoc>()
|
||||
.getNextTypeLoc()
|
||||
.castAs<PointerTypeLoc>();
|
||||
EXPECT_EQ(SM.getFileOffset(InnerPtrTL.getStarLoc()), Example.point("1st"));
|
||||
}
|
||||
|
||||
TEST(CXXFunctionalCastExpr, SourceRange) {
|
||||
RangeVerifier<CXXFunctionalCastExpr> Verifier;
|
||||
Verifier.expectRange(2, 10, 2, 14);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"int foo() {\n"
|
||||
" return int{};\n"
|
||||
"}",
|
||||
cxxFunctionalCastExpr(), Lang_CXX11));
|
||||
EXPECT_TRUE(Verifier.match("int foo() {\n"
|
||||
" return int{};\n"
|
||||
"}",
|
||||
cxxFunctionalCastExpr(), Lang_CXX11));
|
||||
}
|
||||
|
||||
TEST(CXXConstructExpr, SourceRange) {
|
||||
RangeVerifier<CXXConstructExpr> Verifier;
|
||||
Verifier.expectRange(3, 14, 3, 19);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"struct A { A(int, int); };\n"
|
||||
"void f(A a);\n"
|
||||
"void g() { f({0, 0}); }",
|
||||
cxxConstructExpr(), Lang_CXX11));
|
||||
EXPECT_TRUE(Verifier.match("struct A { A(int, int); };\n"
|
||||
"void f(A a);\n"
|
||||
"void g() { f({0, 0}); }",
|
||||
cxxConstructExpr(), Lang_CXX11));
|
||||
}
|
||||
|
||||
TEST(CXXTemporaryObjectExpr, SourceRange) {
|
||||
RangeVerifier<CXXTemporaryObjectExpr> Verifier;
|
||||
Verifier.expectRange(2, 6, 2, 12);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"struct A { A(int, int); };\n"
|
||||
"A a( A{0, 0} );",
|
||||
cxxTemporaryObjectExpr(), Lang_CXX11));
|
||||
EXPECT_TRUE(Verifier.match("struct A { A(int, int); };\n"
|
||||
"A a( A{0, 0} );",
|
||||
cxxTemporaryObjectExpr(), Lang_CXX11));
|
||||
}
|
||||
|
||||
TEST(CXXUnresolvedConstructExpr, SourceRange) {
|
||||
|
|
@ -517,32 +526,29 @@ TEST(CXXUnresolvedConstructExpr, SourceRange) {
|
|||
Verifier.expectRange(3, 10, 3, 12);
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back("-fno-delayed-template-parsing");
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"template <typename U>\n"
|
||||
"U foo() {\n"
|
||||
" return U{};\n"
|
||||
"}",
|
||||
cxxUnresolvedConstructExpr(), Args, Lang_CXX11));
|
||||
EXPECT_TRUE(Verifier.match("template <typename U>\n"
|
||||
"U foo() {\n"
|
||||
" return U{};\n"
|
||||
"}",
|
||||
cxxUnresolvedConstructExpr(), Args, Lang_CXX11));
|
||||
}
|
||||
|
||||
TEST(UsingDecl, SourceRange) {
|
||||
RangeVerifier<UsingDecl> Verifier;
|
||||
Verifier.expectRange(2, 22, 2, 25);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"class B { protected: int i; };\n"
|
||||
"class D : public B { B::i; };",
|
||||
usingDecl()));
|
||||
EXPECT_TRUE(Verifier.match("class B { protected: int i; };\n"
|
||||
"class D : public B { B::i; };",
|
||||
usingDecl()));
|
||||
}
|
||||
|
||||
TEST(UnresolvedUsingValueDecl, SourceRange) {
|
||||
RangeVerifier<UnresolvedUsingValueDecl> Verifier;
|
||||
Verifier.expectRange(3, 3, 3, 6);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"template <typename B>\n"
|
||||
"class D : public B {\n"
|
||||
" B::i;\n"
|
||||
"};",
|
||||
unresolvedUsingValueDecl()));
|
||||
EXPECT_TRUE(Verifier.match("template <typename B>\n"
|
||||
"class D : public B {\n"
|
||||
" B::i;\n"
|
||||
"};",
|
||||
unresolvedUsingValueDecl()));
|
||||
}
|
||||
|
||||
TEST(FriendDecl, FriendNonMemberFunctionLocation) {
|
||||
|
|
@ -782,9 +788,7 @@ TEST(ObjCMessageExpr, ParenExprRange) {
|
|||
TEST(FunctionDecl, FunctionDeclWithThrowSpecification) {
|
||||
RangeVerifier<FunctionDecl> Verifier;
|
||||
Verifier.expectRange(1, 1, 1, 16);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"void f() throw();\n",
|
||||
functionDecl()));
|
||||
EXPECT_TRUE(Verifier.match("void f() throw();\n", functionDecl()));
|
||||
}
|
||||
|
||||
TEST(FunctionDecl, FunctionDeclWithNoExceptSpecification) {
|
||||
|
|
@ -903,11 +907,10 @@ TEST(FunctionDeclParameters, FunctionDeclWithParamAttribute) {
|
|||
TEST(CXXMethodDecl, CXXMethodDeclWithThrowSpecification) {
|
||||
RangeVerifier<FunctionDecl> Verifier;
|
||||
Verifier.expectRange(2, 1, 2, 16);
|
||||
EXPECT_TRUE(Verifier.match(
|
||||
"class A {\n"
|
||||
"void f() throw();\n"
|
||||
"};\n",
|
||||
functionDecl()));
|
||||
EXPECT_TRUE(Verifier.match("class A {\n"
|
||||
"void f() throw();\n"
|
||||
"};\n",
|
||||
functionDecl()));
|
||||
}
|
||||
|
||||
TEST(CXXMethodDecl, CXXMethodDeclWithNoExceptSpecification) {
|
||||
|
|
@ -922,8 +925,7 @@ TEST(CXXMethodDecl, CXXMethodDeclWithNoExceptSpecification) {
|
|||
class ExceptionSpecRangeVerifier : public RangeVerifier<TypeLoc> {
|
||||
protected:
|
||||
SourceRange getRange(const TypeLoc &Node) override {
|
||||
auto T =
|
||||
Node.getUnqualifiedLoc().castAs<FunctionProtoTypeLoc>();
|
||||
auto T = Node.getUnqualifiedLoc().castAs<FunctionProtoTypeLoc>();
|
||||
assert(!T.isNull());
|
||||
return T.getExceptionSpecRange();
|
||||
}
|
||||
|
|
@ -1129,4 +1131,111 @@ template <int X> requires NS::CCC<X> int z = X;
|
|||
EXPECT_TRUE(Verifier.match(Code2, varTemplateDecl(hasName("z")), Lang_CXX20));
|
||||
}
|
||||
|
||||
class ObjCSelectorLocationVerifier : public MatchVerifier<ObjCSelectorExpr> {
|
||||
unsigned ExpectAtLine = 0, ExpectAtColumn = 0;
|
||||
unsigned ExpectNameLine = 0, ExpectNameColumn = 0;
|
||||
unsigned ExpectRParenLine = 0, ExpectRParenColumn = 0;
|
||||
|
||||
public:
|
||||
void expectLocations(unsigned AtLine, unsigned AtColumn, unsigned NameLine,
|
||||
unsigned NameColumn, unsigned RParenLine,
|
||||
unsigned RParenColumn) {
|
||||
ExpectAtLine = AtLine;
|
||||
ExpectAtColumn = AtColumn;
|
||||
ExpectNameLine = NameLine;
|
||||
ExpectNameColumn = NameColumn;
|
||||
ExpectRParenLine = RParenLine;
|
||||
ExpectRParenColumn = RParenColumn;
|
||||
}
|
||||
|
||||
protected:
|
||||
void verify(const MatchFinder::MatchResult &Result,
|
||||
const ObjCSelectorExpr &Node) override {
|
||||
SourceLocation AtLoc = Node.getAtLoc();
|
||||
SourceLocation NameLoc = Node.getSelectorNameLoc();
|
||||
SourceLocation RParenLoc = Node.getRParenLoc();
|
||||
|
||||
unsigned AtLine = Result.SourceManager->getSpellingLineNumber(AtLoc);
|
||||
unsigned AtColumn = Result.SourceManager->getSpellingColumnNumber(AtLoc);
|
||||
unsigned NameLine = Result.SourceManager->getSpellingLineNumber(NameLoc);
|
||||
unsigned NameColumn =
|
||||
Result.SourceManager->getSpellingColumnNumber(NameLoc);
|
||||
unsigned RParenLine =
|
||||
Result.SourceManager->getSpellingLineNumber(RParenLoc);
|
||||
unsigned RParenColumn =
|
||||
Result.SourceManager->getSpellingColumnNumber(RParenLoc);
|
||||
|
||||
if (AtLine != ExpectAtLine || AtColumn != ExpectAtColumn ||
|
||||
NameLine != ExpectNameLine || NameColumn != ExpectNameColumn ||
|
||||
RParenLine != ExpectRParenLine || RParenColumn != ExpectRParenColumn) {
|
||||
std::string MsgStr;
|
||||
llvm::raw_string_ostream Msg(MsgStr);
|
||||
Msg << "Expected At Location <" << ExpectAtLine << ":" << ExpectAtColumn
|
||||
<< ">, found <";
|
||||
AtLoc.print(Msg, *Result.SourceManager);
|
||||
Msg << ">\n";
|
||||
|
||||
Msg << "Expected Name Location <" << ExpectNameLine << ":"
|
||||
<< ExpectNameColumn << ">, found <";
|
||||
NameLoc.print(Msg, *Result.SourceManager);
|
||||
Msg << ">\n";
|
||||
|
||||
Msg << "Expected RParen Location <" << ExpectRParenLine << ":"
|
||||
<< ExpectRParenColumn << ">, found <";
|
||||
RParenLoc.print(Msg, *Result.SourceManager);
|
||||
Msg << ">";
|
||||
|
||||
this->setFailure(MsgStr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCSelectorExpr>
|
||||
objcSelectorExpr;
|
||||
|
||||
TEST(ObjCSelectorExpr, LocationsValidation) {
|
||||
ObjCSelectorLocationVerifier Verifier;
|
||||
|
||||
Verifier.expectLocations(
|
||||
/*At:*/ 2, 11,
|
||||
/*Name:*/ 2, 21,
|
||||
/*RParen:*/ 2, 28);
|
||||
|
||||
EXPECT_TRUE(Verifier.match("void foo() {\n"
|
||||
" SEL s = @selector(foobar:);\n"
|
||||
"}\n",
|
||||
traverse(TK_AsIs, objcSelectorExpr()), Lang_OBJC));
|
||||
}
|
||||
|
||||
TEST(ObjCSelectorExpr, LocationsValidationSpaces) {
|
||||
ObjCSelectorLocationVerifier Verifier;
|
||||
|
||||
Verifier.expectLocations(
|
||||
/*At:*/ 2, 13,
|
||||
/*Name:*/ 2, 27,
|
||||
/*RParen:*/ 2, 36);
|
||||
|
||||
EXPECT_TRUE(Verifier.match("void foo() {\n"
|
||||
" SEL s = @ selector( foobar );\n"
|
||||
"}\n",
|
||||
traverse(TK_AsIs, objcSelectorExpr()), Lang_OBJC));
|
||||
}
|
||||
|
||||
TEST(ObjCSelectorExpr, LocationsValidationBrokenLines) {
|
||||
ObjCSelectorLocationVerifier Verifier;
|
||||
|
||||
Verifier.expectLocations(
|
||||
/*At:*/ 3, 5,
|
||||
/*Name:*/ 4, 7,
|
||||
/*RParen:*/ 5, 5);
|
||||
|
||||
EXPECT_TRUE(Verifier.match("void foo() {\n"
|
||||
" SEL s =\n"
|
||||
" @selector(\n"
|
||||
" foobar\n"
|
||||
" );\n"
|
||||
"}\n",
|
||||
traverse(TK_AsIs, objcSelectorExpr()), Lang_OBJC));
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
|
|
|||
Loading…
Reference in a new issue