[PATCH] D81075: [ASTMatchers] Fix crash with HasName and HasAnyName

2020-06-03 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 268142.
njames93 added a comment.

Fix clang-format error.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81075/new/

https://reviews.llvm.org/D81075

Files:
  clang/include/clang/AST/PrettyPrinter.h
  clang/lib/AST/Decl.cpp
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1665,7 +1665,7 @@
   StringRef code =
   "namespace a { void F(int a) { struct S { int m; }; int i; } }";
   EXPECT_TRUE(matches(code, varDecl(hasName("i";
-  EXPECT_FALSE(matches(code, varDecl(hasName("F()::i";
+  EXPECT_FALSE(matches(code, varDecl(hasName("F(int)::i";
 
   EXPECT_TRUE(matches(code, fieldDecl(hasName("m";
   EXPECT_TRUE(matches(code, fieldDecl(hasName("S::m";
@@ -1674,6 +1674,31 @@
   EXPECT_TRUE(matches(code, fieldDecl(hasName("::a::F(int)::S::m";
 }
 
+TEST(Matcher, HasNameSupportsFunctionScopeRecordDecl) {
+  StringRef FuncCode = R"cc(
+void A() {
+  struct B {};
+})cc";
+  EXPECT_TRUE(matches(FuncCode, cxxRecordDecl(hasName("B";
+  EXPECT_TRUE(matches(FuncCode, cxxRecordDecl(hasName("A()::B";
+  EXPECT_TRUE(matches(FuncCode, cxxRecordDecl(hasName("::A()::B";
+  EXPECT_TRUE(notMatches(FuncCode, cxxRecordDecl(hasName("::B";
+
+  StringRef MethodCode = R"cc(
+struct A {
+  void B() {
+struct C {};
+  }
+};)cc";
+
+  EXPECT_TRUE(matches(MethodCode, cxxRecordDecl(hasName("C";
+  EXPECT_TRUE(matches(MethodCode, cxxRecordDecl(hasName("B()::C";
+  EXPECT_TRUE(matches(MethodCode, cxxRecordDecl(hasName("A::B()::C";
+  EXPECT_TRUE(matches(MethodCode, cxxRecordDecl(hasName("::A::B()::C";
+  EXPECT_TRUE(notMatches(MethodCode, cxxRecordDecl(hasName("::C";
+  EXPECT_TRUE(notMatches(MethodCode, cxxRecordDecl(hasName("::B()::C";
+}
+
 TEST(Matcher, HasNameQualifiedSupportsLinkage) {
   // https://bugs.llvm.org/show_bug.cgi?id=42193
   StringRef code = R"cpp(namespace foo { extern "C" void test(); })cpp";
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -571,7 +571,7 @@
   // We are allowed to skip anonymous and inline namespaces if they don't match.
   const DeclContext *Ctx = Node.getDeclContext();
 
-  if (Ctx->isFunctionOrMethod())
+  if (Ctx->isFunctionOrMethod() && !isa(Node))
 return Patterns.foundMatch(/*AllowFullyQualified=*/false);
 
   for (; Ctx; Ctx = Ctx->getParent()) {
@@ -616,13 +616,10 @@
 llvm::SmallString<128> NodeName = StringRef("::");
 llvm::raw_svector_ostream OS(NodeName);
 
-if (SkipUnwritten) {
-  PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
-  Policy.SuppressUnwrittenScope = true;
-  Node.printQualifiedName(OS, Policy);
-} else {
-  Node.printQualifiedName(OS);
-}
+PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
+Policy.PrintFunctionQualifiedRecords = true;
+Policy.SuppressUnwrittenScope = SkipUnwritten;
+Node.printQualifiedName(OS, Policy);
 
 const StringRef FullName = OS.str();
 
Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -1540,7 +1540,8 @@
 
 void NamedDecl::printQualifiedName(raw_ostream ,
const PrintingPolicy ) const {
-  if (getDeclContext()->isFunctionOrMethod()) {
+  if (getDeclContext()->isFunctionOrMethod() &&
+  !(P.PrintFunctionQualifiedRecords && isa(this))) {
 // We do not print '(anonymous)' for function parameters without name.
 printName(OS);
 return;
@@ -1583,7 +1584,8 @@
   Ctx = CI;
   }
 
-  if (Ctx->isFunctionOrMethod())
+  if (Ctx->isFunctionOrMethod() &&
+  !(P.PrintFunctionQualifiedRecords && isa(this)))
 return;
 
   using ContextsTy = SmallVector;
Index: clang/include/clang/AST/PrettyPrinter.h
===
--- clang/include/clang/AST/PrettyPrinter.h
+++ clang/include/clang/AST/PrettyPrinter.h
@@ -63,7 +63,8 @@
 MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true),
 MSVCFormatting(false), ConstantsAsWritten(false),
 SuppressImplicitBase(false), FullyQualifiedName(false),
-PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true) {}
+PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true),
+PrintFunctionQualifiedRecords(false) {}
 
   /// Adjust this printing policy for cases where it's known that we're
   

[PATCH] D81075: [ASTMatchers] Fix crash with HasName and HasAnyName

2020-06-03 Thread Nathan James via Phabricator via cfe-commits
njames93 created this revision.
njames93 added reviewers: klimek, sbenza.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Fixes crashes caused by matching fully qualified RecordDecls inside Function 
bodies.
See https://bugs.llvm.org/show_bug.cgi?id=43639.
I'm still unsure if this is the desired behaviour though.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81075

Files:
  clang/include/clang/AST/PrettyPrinter.h
  clang/lib/AST/Decl.cpp
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1665,7 +1665,7 @@
   StringRef code =
   "namespace a { void F(int a) { struct S { int m; }; int i; } }";
   EXPECT_TRUE(matches(code, varDecl(hasName("i";
-  EXPECT_FALSE(matches(code, varDecl(hasName("F()::i";
+  EXPECT_FALSE(matches(code, varDecl(hasName("F(int)::i";
 
   EXPECT_TRUE(matches(code, fieldDecl(hasName("m";
   EXPECT_TRUE(matches(code, fieldDecl(hasName("S::m";
@@ -1674,6 +1674,34 @@
   EXPECT_TRUE(matches(code, fieldDecl(hasName("::a::F(int)::S::m";
 }
 
+TEST(Matcher, HasNameSupportsFunctionScopeRecordDecl) {
+  StringRef FuncCode = R"cc(
+void A() {
+  struct B {};
+})cc";
+  EXPECT_TRUE(matches(FuncCode, cxxRecordDecl(hasName("B";
+  EXPECT_TRUE(matches(FuncCode, cxxRecordDecl(hasName("A()::B";
+  EXPECT_TRUE(matches(FuncCode, cxxRecordDecl(hasName("::A()::B";
+  EXPECT_TRUE(notMatches(FuncCode, cxxRecordDecl(hasName("::B";
+
+  StringRef MethodCode = R"cc(
+struct A {
+  void B() {
+struct C {};
+  }
+};)cc";
+
+  EXPECT_TRUE(matches(MethodCode, cxxRecordDecl(hasName("C";
+  EXPECT_TRUE(matches(MethodCode, cxxRecordDecl(hasName("B()::C";
+  EXPECT_TRUE(
+  matches(MethodCode, cxxRecordDecl(hasName("A::B()::C";
+  EXPECT_TRUE(
+  matches(MethodCode, cxxRecordDecl(hasName("::A::B()::C";
+  EXPECT_TRUE(notMatches(MethodCode, cxxRecordDecl(hasName("::C";
+  EXPECT_TRUE(
+  notMatches(MethodCode, cxxRecordDecl(hasName("::B()::C";
+}
+
 TEST(Matcher, HasNameQualifiedSupportsLinkage) {
   // https://bugs.llvm.org/show_bug.cgi?id=42193
   StringRef code = R"cpp(namespace foo { extern "C" void test(); })cpp";
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -571,7 +571,7 @@
   // We are allowed to skip anonymous and inline namespaces if they don't match.
   const DeclContext *Ctx = Node.getDeclContext();
 
-  if (Ctx->isFunctionOrMethod())
+  if (Ctx->isFunctionOrMethod() && !isa(Node))
 return Patterns.foundMatch(/*AllowFullyQualified=*/false);
 
   for (; Ctx; Ctx = Ctx->getParent()) {
@@ -616,13 +616,10 @@
 llvm::SmallString<128> NodeName = StringRef("::");
 llvm::raw_svector_ostream OS(NodeName);
 
-if (SkipUnwritten) {
-  PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
-  Policy.SuppressUnwrittenScope = true;
-  Node.printQualifiedName(OS, Policy);
-} else {
-  Node.printQualifiedName(OS);
-}
+PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
+Policy.PrintFunctionQualifiedRecords = true;
+Policy.SuppressUnwrittenScope = SkipUnwritten;
+Node.printQualifiedName(OS, Policy);
 
 const StringRef FullName = OS.str();
 
Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -1540,7 +1540,8 @@
 
 void NamedDecl::printQualifiedName(raw_ostream ,
const PrintingPolicy ) const {
-  if (getDeclContext()->isFunctionOrMethod()) {
+  if (getDeclContext()->isFunctionOrMethod() &&
+  !(P.PrintFunctionQualifiedRecords && isa(this))) {
 // We do not print '(anonymous)' for function parameters without name.
 printName(OS);
 return;
@@ -1583,7 +1584,8 @@
   Ctx = CI;
   }
 
-  if (Ctx->isFunctionOrMethod())
+  if (Ctx->isFunctionOrMethod() &&
+  !(P.PrintFunctionQualifiedRecords && isa(this)))
 return;
 
   using ContextsTy = SmallVector;
Index: clang/include/clang/AST/PrettyPrinter.h
===
--- clang/include/clang/AST/PrettyPrinter.h
+++ clang/include/clang/AST/PrettyPrinter.h
@@ -63,7 +63,8 @@
 MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true),
 MSVCFormatting(false), ConstantsAsWritten(false),
 SuppressImplicitBase(false), FullyQualifiedName(false),
-PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true) {}
+