https://github.com/dmaclach updated https://github.com/llvm/llvm-project/pull/211623
>From cd3085ad07edf3df426f9a855ab49ee1ee457b4b Mon Sep 17 00:00:00 2001 From: Dave MacLachlan <[email protected]> Date: Thu, 23 Jul 2026 10:12:21 -0700 Subject: [PATCH 1/2] Adds tracking for the source location of the selector name within ObjCSelectorExpr. Simplifies some work I am doing in include-cleaner and could be used to improve diagnostics for selector locations that are currently pointing at `@selector` instead of the actual selector name. --- clang/include/clang/AST/ExprObjC.h | 8 +++++--- clang/include/clang/Sema/SemaObjC.h | 3 ++- clang/lib/Parse/ParseObjc.cpp | 8 ++++---- clang/lib/Sema/SemaExprObjC.cpp | 21 ++++++++++----------- clang/lib/Serialization/ASTReaderStmt.cpp | 1 + clang/lib/Serialization/ASTWriterStmt.cpp | 1 + 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index 00c9b44930bcc..571dfadea3e90 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -485,13 +485,13 @@ class ObjCEncodeExpr : public Expr { /// ObjCSelectorExpr used for \@selector in Objective-C. class ObjCSelectorExpr : public Expr { Selector SelName; - SourceLocation AtLoc, RParenLoc; + SourceLocation AtLoc, SelLoc, RParenLoc; public: ObjCSelectorExpr(QualType T, Selector selInfo, SourceLocation at, - SourceLocation rp) + SourceLocation sel, SourceLocation rp) : Expr(ObjCSelectorExprClass, T, VK_PRValue, OK_Ordinary), - SelName(selInfo), AtLoc(at), RParenLoc(rp) { + SelName(selInfo), AtLoc(at), SelLoc(sel), RParenLoc(rp) { setDependence(ExprDependence::None); } explicit ObjCSelectorExpr(EmptyShell Empty) @@ -501,8 +501,10 @@ class ObjCSelectorExpr : public Expr { void setSelector(Selector S) { SelName = S; } SourceLocation getAtLoc() const { return AtLoc; } + SourceLocation getSelectorLoc() const { return SelLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } + void setSelectorLoc(SourceLocation L) { SelLoc = L; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index f5cb8ea4b034a..89d450fb3ddd0 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -691,7 +691,8 @@ class SemaObjC : public SemaBase { /// ParseObjCSelectorExpression - Build selector expression for \@selector ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, - SourceLocation SelLoc, + SourceLocation SelectorLoc, + SourceLocation SelNameLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, bool WarnMultipleSelectors); diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index eb50b0e8546c6..a6fe60b43c984 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -3205,7 +3205,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { 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, SelectorLoc, SelectorNameLoc, T.getOpenLocation(), + T.getCloseLocation(), !HasOptionalParen); } void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index c166e0c9e7b72..935507f9c5589 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -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 SelectorLoc, + 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(SelectorLoc, diag::warn_undeclared_selector_with_typo) + << Sel << MatchedSel + << FixItHint::CreateReplacement(SelectorRange, + MatchedSel.getAsString()); } else - Diag(SelLoc, diag::warn_undeclared_selector) << Sel; + Diag(SelectorLoc, 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, diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 87cec16a76323..21ca0ec339df0 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1574,6 +1574,7 @@ void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { VisitExpr(E); E->setSelector(Record.readSelector()); E->setAtLoc(readSourceLocation()); + E->setSelectorLoc(readSourceLocation()); E->setRParenLoc(readSourceLocation()); } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 70477f4cf4001..97a17277759d0 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1536,6 +1536,7 @@ void ASTStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { VisitExpr(E); Record.AddSelectorRef(E->getSelector()); Record.AddSourceLocation(E->getAtLoc()); + Record.AddSourceLocation(E->getSelectorLoc()); Record.AddSourceLocation(E->getRParenLoc()); Code = serialization::EXPR_OBJC_SELECTOR_EXPR; } >From f6b73505e40dd3822a9a10432fc2e212c0084fe6 Mon Sep 17 00:00:00 2001 From: Dave MacLachlan <[email protected]> Date: Tue, 28 Jul 2026 06:59:05 -0700 Subject: [PATCH 2/2] Cleaned up some naming and added tests. --- clang/include/clang/AST/ExprObjC.h | 10 +- clang/include/clang/Sema/SemaObjC.h | 2 +- clang/lib/Parse/ParseObjc.cpp | 4 +- clang/lib/Sema/SemaExprObjC.cpp | 11 +- clang/lib/Serialization/ASTReaderStmt.cpp | 2 +- clang/lib/Serialization/ASTWriterStmt.cpp | 2 +- clang/unittests/AST/SourceLocationTest.cpp | 249 +++++++++++++++------ 7 files changed, 194 insertions(+), 86 deletions(-) diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index 571dfadea3e90..7f7b556f14329 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -485,13 +485,13 @@ class ObjCEncodeExpr : public Expr { /// ObjCSelectorExpr used for \@selector in Objective-C. class ObjCSelectorExpr : public Expr { Selector SelName; - SourceLocation AtLoc, SelLoc, RParenLoc; + SourceLocation AtLoc, SelNameLoc, RParenLoc; public: ObjCSelectorExpr(QualType T, Selector selInfo, SourceLocation at, - SourceLocation sel, SourceLocation rp) + SourceLocation selNameLoc, SourceLocation rp) : Expr(ObjCSelectorExprClass, T, VK_PRValue, OK_Ordinary), - SelName(selInfo), AtLoc(at), SelLoc(sel), RParenLoc(rp) { + SelName(selInfo), AtLoc(at), SelNameLoc(selNameLoc), RParenLoc(rp) { setDependence(ExprDependence::None); } explicit ObjCSelectorExpr(EmptyShell Empty) @@ -501,10 +501,10 @@ class ObjCSelectorExpr : public Expr { void setSelector(Selector S) { SelName = S; } SourceLocation getAtLoc() const { return AtLoc; } - SourceLocation getSelectorLoc() const { return SelLoc; } + SourceLocation getSelectorNameLoc() const { return SelNameLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } - void setSelectorLoc(SourceLocation L) { SelLoc = L; } + void setSelectorNameLoc(SourceLocation L) { SelNameLoc = L; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index 89d450fb3ddd0..e597e5845f035 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -691,7 +691,7 @@ class SemaObjC : public SemaBase { /// ParseObjCSelectorExpression - Build selector expression for \@selector ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, - SourceLocation SelectorLoc, + SourceLocation SelKWLoc, SourceLocation SelNameLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index a6fe60b43c984..d01b0abf917cb 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -3199,7 +3199,7 @@ 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"); @@ -3259,7 +3259,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { T.consumeClose(); Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]); return Actions.ObjC().ParseObjCSelectorExpression( - Sel, AtLoc, SelectorLoc, SelectorNameLoc, T.getOpenLocation(), + Sel, AtLoc, SelectorKeywordLoc, SelectorNameLoc, T.getOpenLocation(), T.getCloseLocation(), !HasOptionalParen); } diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 935507f9c5589..a8f080c02ccec 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1417,7 +1417,7 @@ static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) { } ExprResult SemaObjC::ParseObjCSelectorExpression( - Selector Sel, SourceLocation AtLoc, SourceLocation SelectorLoc, + Selector Sel, SourceLocation AtLoc, SourceLocation SelKWLoc, SourceLocation SelNameLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, bool WarnMultipleSelectors) { ASTContext &Context = getASTContext(); @@ -1431,13 +1431,12 @@ ExprResult SemaObjC::ParseObjCSelectorExpression( Selector MatchedSel = OM->getSelector(); SourceRange SelectorRange(LParenLoc.getLocWithOffset(1), RParenLoc.getLocWithOffset(-1)); - Diag(SelectorLoc, 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(SelectorLoc, diag::warn_undeclared_selector) << Sel; + Diag(SelKWLoc, diag::warn_undeclared_selector) << Sel; } else { DiagnoseMismatchedSelectors(SemaRef, AtLoc, Method, LParenLoc, RParenLoc, WarnMultipleSelectors); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 21ca0ec339df0..ae8de63c1bd6b 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1574,7 +1574,7 @@ void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { VisitExpr(E); E->setSelector(Record.readSelector()); E->setAtLoc(readSourceLocation()); - E->setSelectorLoc(readSourceLocation()); + E->setSelectorNameLoc(readSourceLocation()); E->setRParenLoc(readSourceLocation()); } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 97a17277759d0..10443d42df8c0 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1536,7 +1536,7 @@ void ASTStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { VisitExpr(E); Record.AddSelectorRef(E->getSelector()); Record.AddSourceLocation(E->getAtLoc()); - Record.AddSourceLocation(E->getSelectorLoc()); + Record.AddSourceLocation(E->getSelectorNameLoc()); Record.AddSourceLocation(E->getRParenLoc()); Code = serialization::EXPR_OBJC_SELECTOR_EXPR; } diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp index 7bd0de04b2582..507032053e0ae 100644 --- a/clang/unittests/AST/SourceLocationTest.cpp +++ b/clang/unittests/AST/SourceLocationTest.cpp @@ -19,13 +19,19 @@ #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/Basic/SourceLocation.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 @@ class TemplateAngleBracketLocRangeVerifier : public RangeVerifier<TypeLoc> { 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 @@ class UnaryTransformTypeLocParensRangeVerifier : public RangeVerifier<TypeLoc> { 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
