[PATCH] D35012: [refactor] Add the AST source selection component

2017-08-24 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added a comment.

r311664


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-08-24 Thread Krasimir Georgiev via Phabricator via cfe-commits
krasimir added a comment.

The test `CursorAtStartOfFunction` is segfaulting.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-08-24 Thread Alex Lorenz via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL311655: [refactor] Add the AST source selection component 
(authored by arphaman).

Changed prior to commit:
  https://reviews.llvm.org/D35012?vs=108078=112550#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D35012

Files:
  cfe/trunk/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
  cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
  cfe/trunk/include/clang/Basic/SourceLocation.h
  cfe/trunk/include/clang/Basic/SourceManager.h
  cfe/trunk/include/clang/Tooling/Refactoring/ASTSelection.h
  cfe/trunk/lib/Tooling/Refactoring/ASTSelection.cpp
  cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt
  cfe/trunk/unittests/Tooling/ASTSelectionTest.cpp
  cfe/trunk/unittests/Tooling/CMakeLists.txt
  cfe/trunk/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp

Index: cfe/trunk/include/clang/Basic/SourceLocation.h
===
--- cfe/trunk/include/clang/Basic/SourceLocation.h
+++ cfe/trunk/include/clang/Basic/SourceLocation.h
@@ -172,6 +172,11 @@
 return getFromRawEncoding((unsigned)(uintptr_t)Encoding);
   }
 
+  static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End) {
+return Start.isValid() && Start.isFileID() && End.isValid() &&
+   End.isFileID();
+  }
+
   void print(raw_ostream , const SourceManager ) const;
   std::string printToString(const SourceManager ) const;
   void dump(const SourceManager ) const;
Index: cfe/trunk/include/clang/Basic/SourceManager.h
===
--- cfe/trunk/include/clang/Basic/SourceManager.h
+++ cfe/trunk/include/clang/Basic/SourceManager.h
@@ -1520,6 +1520,14 @@
 return LHSLoaded;
   }
 
+  /// Return true if the Point is within Start and End.
+  bool isPointWithin(SourceLocation Location, SourceLocation Start,
+ SourceLocation End) const {
+return Location == Start || Location == End ||
+   (isBeforeInTranslationUnit(Start, Location) &&
+isBeforeInTranslationUnit(Location, End));
+  }
+
   // Iterators over FileInfos.
   typedef llvm::DenseMap
   ::const_iterator fileinfo_iterator;
Index: cfe/trunk/include/clang/Tooling/Refactoring/ASTSelection.h
===
--- cfe/trunk/include/clang/Tooling/Refactoring/ASTSelection.h
+++ cfe/trunk/include/clang/Tooling/Refactoring/ASTSelection.h
@@ -0,0 +1,74 @@
+//===--- ASTSelection.h - Clang refactoring library ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include 
+
+namespace clang {
+
+class ASTContext;
+
+namespace tooling {
+
+enum class SourceSelectionKind {
+  /// A node that's not selected.
+  None,
+
+  /// A node that's considered to be selected because the whole selection range
+  /// is inside of its source range.
+  ContainsSelection,
+  /// A node that's considered to be selected because the start of the selection
+  /// range is inside its source range.
+  ContainsSelectionStart,
+  /// A node that's considered to be selected because the end of the selection
+  /// range is inside its source range.
+  ContainsSelectionEnd,
+
+  /// A node that's considered to be selected because the node is entirely in
+  /// the selection range.
+  InsideSelection,
+};
+
+/// Represents a selected AST node.
+///
+/// AST selection is represented using a tree of \c SelectedASTNode. The tree
+/// follows the top-down shape of the actual AST. Each selected node has
+/// a selection kind. The kind might be none as the node itself might not
+/// actually be selected, e.g. a statement in macro whose child is in a macro
+/// argument.
+struct SelectedASTNode {
+  ast_type_traits::DynTypedNode Node;
+  SourceSelectionKind SelectionKind;
+  std::vector Children;
+
+  SelectedASTNode(const ast_type_traits::DynTypedNode ,
+  SourceSelectionKind SelectionKind)
+  : Node(Node), SelectionKind(SelectionKind) {}
+  SelectedASTNode(SelectedASTNode &&) = default;
+  SelectedASTNode =(SelectedASTNode &&) = default;
+
+  void dump(llvm::raw_ostream  = llvm::errs()) const;
+};
+
+/// Traverses the given ASTContext and creates a tree of selected AST nodes.
+///
+/// \returns None if no nodes are selected in the AST, or a selected AST node
+/// that corresponds to the TranslationUnitDecl otherwise.
+Optional findSelectedASTNodes(const ASTContext ,
+   SourceRange 

[PATCH] D35012: [refactor] Add the AST source selection component

2017-08-01 Thread Eric Liu via Phabricator via cfe-commits
ioeric accepted this revision.
ioeric added a comment.
This revision is now accepted and ready to land.

Yep. Lgtm!


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-08-01 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added a comment.

Apart from nits, looks OK to me - Eric, are all your concerns addressed?




Comment at: include/clang/Tooling/Refactoring/ASTSelection.h:51-53
+  ast_type_traits::DynTypedNode Node;
+  SourceSelectionKind SelectionKind;
+  std::vector Children;

As this is a public interface, perhaps we should make them const?


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-08-01 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added a comment.

Ping.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-25 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman updated this revision to Diff 108078.
arphaman added a comment.

Simplified the implementation of `LexicallyOrderedRecursiveASTVisitor` and 
removed redundant DenseMap checks.
Ping.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012

Files:
  include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/Basic/SourceLocation.h
  include/clang/Basic/SourceManager.h
  include/clang/Tooling/Refactoring/ASTSelection.h
  lib/Tooling/Refactoring/ASTSelection.cpp
  lib/Tooling/Refactoring/CMakeLists.txt
  unittests/Tooling/ASTSelectionTest.cpp
  unittests/Tooling/CMakeLists.txt
  unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp

Index: unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
===
--- /dev/null
+++ unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
@@ -0,0 +1,141 @@
+//===- unittest/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "TestVisitor.h"
+#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
+#include 
+
+using namespace clang;
+
+namespace {
+
+class DummyMatchVisitor;
+
+class LexicallyOrderedDeclVisitor
+: public LexicallyOrderedRecursiveASTVisitor {
+public:
+  LexicallyOrderedDeclVisitor(DummyMatchVisitor ,
+  const SourceManager )
+  : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher) {}
+
+  bool TraverseDecl(Decl *D) {
+TraversalStack.push_back(D);
+LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
+TraversalStack.pop_back();
+return true;
+  }
+
+  bool VisitNamedDecl(const NamedDecl *D);
+
+private:
+  DummyMatchVisitor 
+  llvm::SmallVector TraversalStack;
+};
+
+class DummyMatchVisitor : public ExpectedLocationVisitor {
+public:
+  bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+const ASTContext  = TU->getASTContext();
+const SourceManager  = Context.getSourceManager();
+LexicallyOrderedDeclVisitor SubVisitor(*this, SM);
+SubVisitor.TraverseDecl(TU);
+return false;
+  }
+
+  void match(StringRef Path, const Decl *D) { Match(Path, D->getLocStart()); }
+};
+
+bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
+  std::string Path;
+  llvm::raw_string_ostream OS(Path);
+  assert(TraversalStack.back() == D);
+  for (const Decl *D : TraversalStack) {
+if (isa(D)) {
+  OS << "/";
+  continue;
+}
+if (const auto *ND = dyn_cast(D))
+  OS << ND->getNameAsString();
+else
+  OS << "???";
+if (isa(D))
+  OS << "/";
+  }
+  Matcher.match(OS.str(), D);
+  return true;
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitDeclsInImplementation) {
+  StringRef Source = R"(
+@interface I
+@end
+@implementation I
+
+int nestedFunction() { }
+
+- (void) method{ }
+
+int anotherNestedFunction(int x) {
+  return x;
+}
+
+int innerVariable = 0;
+
+@end
+
+int outerVariable = 0;
+
+@implementation I(Cat)
+
+void catF() { }
+
+@end
+
+void outerFunction() { }
+)";
+  DummyMatchVisitor Visitor;
+  Visitor.DisallowMatch("/nestedFunction/", 6, 1);
+  Visitor.ExpectMatch("/I/nestedFunction/", 6, 1);
+  Visitor.ExpectMatch("/I/method/", 8, 1);
+  Visitor.DisallowMatch("/anotherNestedFunction/", 10, 1);
+  Visitor.ExpectMatch("/I/anotherNestedFunction/", 10, 1);
+  Visitor.DisallowMatch("/innerVariable", 14, 1);
+  Visitor.ExpectMatch("/I/innerVariable", 14, 1);
+  Visitor.ExpectMatch("/outerVariable", 18, 1);
+  Visitor.DisallowMatch("/catF/", 22, 1);
+  Visitor.ExpectMatch("/Cat/catF/", 22, 1);
+  Visitor.ExpectMatch("/outerFunction/", 26, 1);
+  EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitMacroDeclsInImplementation) {
+  StringRef Source = R"(
+@interface I
+@end
+
+void outerFunction() { }
+
+#define MACRO_F(x) void nestedFunction##x() { }
+
+@implementation I
+
+MACRO_F(1)
+
+@end
+
+MACRO_F(2)
+)";
+  DummyMatchVisitor Visitor;
+  Visitor.ExpectMatch("/outerFunction/", 5, 1);
+  Visitor.ExpectMatch("/I/nestedFunction1/", 7, 20);
+  Visitor.ExpectMatch("/nestedFunction2/", 7, 20);
+  EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
+}
+
+} // end anonymous namespace
Index: unittests/Tooling/CMakeLists.txt
===
--- unittests/Tooling/CMakeLists.txt
+++ unittests/Tooling/CMakeLists.txt
@@ -11,11 +11,13 @@
 endif()
 
 add_clang_unittest(ToolingTests
+  ASTSelectionTest.cpp
   CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
   DiagnosticsYamlTest.cpp
   FixItTest.cpp
+  LexicallyOrderedRecursiveASTVisitorTest.cpp
   

[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman updated this revision to Diff 107138.
arphaman added a comment.

rm early exit bug


Repository:
  rL LLVM

https://reviews.llvm.org/D35012

Files:
  include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
  include/clang/Basic/SourceLocation.h
  include/clang/Basic/SourceManager.h
  include/clang/Tooling/Refactoring/ASTSelection.h
  lib/Tooling/Refactoring/ASTSelection.cpp
  lib/Tooling/Refactoring/CMakeLists.txt
  unittests/Tooling/ASTSelectionTest.cpp
  unittests/Tooling/CMakeLists.txt
  unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp

Index: unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
===
--- /dev/null
+++ unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
@@ -0,0 +1,141 @@
+//===- unittest/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "TestVisitor.h"
+#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
+#include 
+
+using namespace clang;
+
+namespace {
+
+class DummyMatchVisitor;
+
+class LexicallyOrderedDeclVisitor
+: public LexicallyOrderedRecursiveASTVisitor {
+public:
+  LexicallyOrderedDeclVisitor(DummyMatchVisitor ,
+  const SourceManager )
+  : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher) {}
+
+  bool TraverseDecl(Decl *D) {
+TraversalStack.push_back(D);
+LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
+TraversalStack.pop_back();
+return true;
+  }
+
+  bool VisitNamedDecl(const NamedDecl *D);
+
+private:
+  DummyMatchVisitor 
+  llvm::SmallVector TraversalStack;
+};
+
+class DummyMatchVisitor : public ExpectedLocationVisitor {
+public:
+  bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+const ASTContext  = TU->getASTContext();
+const SourceManager  = Context.getSourceManager();
+LexicallyOrderedDeclVisitor SubVisitor(*this, SM);
+SubVisitor.TraverseDecl(TU);
+return false;
+  }
+
+  void match(StringRef Path, const Decl *D) { Match(Path, D->getLocStart()); }
+};
+
+bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
+  std::string Path;
+  llvm::raw_string_ostream OS(Path);
+  assert(TraversalStack.back() == D);
+  for (const Decl *D : TraversalStack) {
+if (isa(D)) {
+  OS << "/";
+  continue;
+}
+if (const auto *ND = dyn_cast(D))
+  OS << ND->getNameAsString();
+else
+  OS << "???";
+if (isa(D))
+  OS << "/";
+  }
+  Matcher.match(OS.str(), D);
+  return true;
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitDeclsInImplementation) {
+  StringRef Source = R"(
+@interface I
+@end
+@implementation I
+
+int nestedFunction() { }
+
+- (void) method{ }
+
+int anotherNestedFunction(int x) {
+  return x;
+}
+
+int innerVariable = 0;
+
+@end
+
+int outerVariable = 0;
+
+@implementation I(Cat)
+
+void catF() { }
+
+@end
+
+void outerFunction() { }
+)";
+  DummyMatchVisitor Visitor;
+  Visitor.DisallowMatch("/nestedFunction/", 6, 1);
+  Visitor.ExpectMatch("/I/nestedFunction/", 6, 1);
+  Visitor.ExpectMatch("/I/method/", 8, 1);
+  Visitor.DisallowMatch("/anotherNestedFunction/", 10, 1);
+  Visitor.ExpectMatch("/I/anotherNestedFunction/", 10, 1);
+  Visitor.DisallowMatch("/innerVariable", 14, 1);
+  Visitor.ExpectMatch("/I/innerVariable", 14, 1);
+  Visitor.ExpectMatch("/outerVariable", 18, 1);
+  Visitor.DisallowMatch("/catF/", 22, 1);
+  Visitor.ExpectMatch("/Cat/catF/", 22, 1);
+  Visitor.ExpectMatch("/outerFunction/", 26, 1);
+  EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitMacroDeclsInImplementation) {
+  StringRef Source = R"(
+@interface I
+@end
+
+void outerFunction() { }
+
+#define MACRO_F(x) void nestedFunction##x() { }
+
+@implementation I
+
+MACRO_F(1)
+
+@end
+
+MACRO_F(2)
+)";
+  DummyMatchVisitor Visitor;
+  Visitor.ExpectMatch("/outerFunction/", 5, 1);
+  Visitor.ExpectMatch("/I/nestedFunction1/", 7, 20);
+  Visitor.ExpectMatch("/nestedFunction2/", 7, 20);
+  EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
+}
+
+} // end anonymous namespace
Index: unittests/Tooling/CMakeLists.txt
===
--- unittests/Tooling/CMakeLists.txt
+++ unittests/Tooling/CMakeLists.txt
@@ -11,11 +11,13 @@
 endif()
 
 add_clang_unittest(ToolingTests
+  ASTSelectionTest.cpp
   CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
   DiagnosticsYamlTest.cpp
   FixItTest.cpp
+  LexicallyOrderedRecursiveASTVisitorTest.cpp
   LookupTest.cpp
   QualTypeNamesTest.cpp
   RecursiveASTVisitorTest.cpp
Index: unittests/Tooling/ASTSelectionTest.cpp

[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added a comment.

Oops, I just realised that now there's a small bug with early exits. Since we 
don't actually have true lexical order for declarations in the @implementation 
we might exit early after visiting a method in the @implementation before a 
function that's actually written before that method. I will probably constraint 
early exits to avoid this case.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman updated this revision to Diff 107121.
arphaman added a comment.

Factor out the lexical ordering code into a new visitor and simplify the 
implementation of the ast selection visitor


Repository:
  rL LLVM

https://reviews.llvm.org/D35012

Files:
  include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
  include/clang/Basic/SourceLocation.h
  include/clang/Basic/SourceManager.h
  include/clang/Tooling/Refactoring/ASTSelection.h
  lib/Tooling/Refactoring/ASTSelection.cpp
  lib/Tooling/Refactoring/CMakeLists.txt
  unittests/Tooling/ASTSelectionTest.cpp
  unittests/Tooling/CMakeLists.txt
  unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp

Index: unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
===
--- /dev/null
+++ unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
@@ -0,0 +1,141 @@
+//===- unittest/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "TestVisitor.h"
+#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
+#include 
+
+using namespace clang;
+
+namespace {
+
+class DummyMatchVisitor;
+
+class LexicallyOrderedDeclVisitor
+: public LexicallyOrderedRecursiveASTVisitor {
+public:
+  LexicallyOrderedDeclVisitor(DummyMatchVisitor ,
+  const SourceManager )
+  : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher) {}
+
+  bool TraverseDecl(Decl *D) {
+TraversalStack.push_back(D);
+LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
+TraversalStack.pop_back();
+return true;
+  }
+
+  bool VisitNamedDecl(const NamedDecl *D);
+
+private:
+  DummyMatchVisitor 
+  llvm::SmallVector TraversalStack;
+};
+
+class DummyMatchVisitor : public ExpectedLocationVisitor {
+public:
+  bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+const ASTContext  = TU->getASTContext();
+const SourceManager  = Context.getSourceManager();
+LexicallyOrderedDeclVisitor SubVisitor(*this, SM);
+SubVisitor.TraverseDecl(TU);
+return false;
+  }
+
+  void match(StringRef Path, const Decl *D) { Match(Path, D->getLocStart()); }
+};
+
+bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
+  std::string Path;
+  llvm::raw_string_ostream OS(Path);
+  assert(TraversalStack.back() == D);
+  for (const Decl *D : TraversalStack) {
+if (isa(D)) {
+  OS << "/";
+  continue;
+}
+if (const auto *ND = dyn_cast(D))
+  OS << ND->getNameAsString();
+else
+  OS << "???";
+if (isa(D))
+  OS << "/";
+  }
+  Matcher.match(OS.str(), D);
+  return true;
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitDeclsInImplementation) {
+  StringRef Source = R"(
+@interface I
+@end
+@implementation I
+
+int nestedFunction() { }
+
+- (void) method{ }
+
+int anotherNestedFunction(int x) {
+  return x;
+}
+
+int innerVariable = 0;
+
+@end
+
+int outerVariable = 0;
+
+@implementation I(Cat)
+
+void catF() { }
+
+@end
+
+void outerFunction() { }
+)";
+  DummyMatchVisitor Visitor;
+  Visitor.DisallowMatch("/nestedFunction/", 6, 1);
+  Visitor.ExpectMatch("/I/nestedFunction/", 6, 1);
+  Visitor.ExpectMatch("/I/method/", 8, 1);
+  Visitor.DisallowMatch("/anotherNestedFunction/", 10, 1);
+  Visitor.ExpectMatch("/I/anotherNestedFunction/", 10, 1);
+  Visitor.DisallowMatch("/innerVariable", 14, 1);
+  Visitor.ExpectMatch("/I/innerVariable", 14, 1);
+  Visitor.ExpectMatch("/outerVariable", 18, 1);
+  Visitor.DisallowMatch("/catF/", 22, 1);
+  Visitor.ExpectMatch("/Cat/catF/", 22, 1);
+  Visitor.ExpectMatch("/outerFunction/", 26, 1);
+  EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitMacroDeclsInImplementation) {
+  StringRef Source = R"(
+@interface I
+@end
+
+void outerFunction() { }
+
+#define MACRO_F(x) void nestedFunction##x() { }
+
+@implementation I
+
+MACRO_F(1)
+
+@end
+
+MACRO_F(2)
+)";
+  DummyMatchVisitor Visitor;
+  Visitor.ExpectMatch("/outerFunction/", 5, 1);
+  Visitor.ExpectMatch("/I/nestedFunction1/", 7, 20);
+  Visitor.ExpectMatch("/nestedFunction2/", 7, 20);
+  EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
+}
+
+} // end anonymous namespace
Index: unittests/Tooling/CMakeLists.txt
===
--- unittests/Tooling/CMakeLists.txt
+++ unittests/Tooling/CMakeLists.txt
@@ -11,11 +11,13 @@
 endif()
 
 add_clang_unittest(ToolingTests
+  ASTSelectionTest.cpp
   CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
   DiagnosticsYamlTest.cpp
   FixItTest.cpp
+  LexicallyOrderedRecursiveASTVisitorTest.cpp
   LookupTest.cpp
   QualTypeNamesTest.cpp
   

[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added inline comments.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:164
+  unsigned NumMatches = 0;
+  for (Decl *D : Context.getTranslationUnitDecl()->decls()) {
+if (ObjCImplEndLoc.isValid() &&

arphaman wrote:
> klimek wrote:
> > arphaman wrote:
> > > klimek wrote:
> > > > Why don't we do this as part of TraverseDecl() in the visitor?
> > > I think it's easier to handle the Objective-C `@implementation` logic 
> > > here, unless there's some better way that I can't see ATM.
> > Ok, in that case, can you write a comment at the start of the loop 
> > explaining that we basically only do that for the Objective-C 
> > @implementation? (I'd also like to understand that better in general, as I 
> > have no clue about Obj-C :)
> Hmm, maybe it would be better to move this logic to another layer. Like a 
> wrapper around `RecursiveASTVisitor` that ensures that iteration occurs in a 
> lexical order. It can then be used by other things that might need this, this 
> code will get simpler and I will be able to test it better.
Great idea! That would be useful in a bunch of use cases.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added inline comments.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:164
+  unsigned NumMatches = 0;
+  for (Decl *D : Context.getTranslationUnitDecl()->decls()) {
+if (ObjCImplEndLoc.isValid() &&

klimek wrote:
> arphaman wrote:
> > klimek wrote:
> > > Why don't we do this as part of TraverseDecl() in the visitor?
> > I think it's easier to handle the Objective-C `@implementation` logic here, 
> > unless there's some better way that I can't see ATM.
> Ok, in that case, can you write a comment at the start of the loop explaining 
> that we basically only do that for the Objective-C @implementation? (I'd also 
> like to understand that better in general, as I have no clue about Obj-C :)
Hmm, maybe it would be better to move this logic to another layer. Like a 
wrapper around `RecursiveASTVisitor` that ensures that iteration occurs in a 
lexical order. It can then be used by other things that might need this, this 
code will get simpler and I will be able to test it better.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added inline comments.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:164
+  unsigned NumMatches = 0;
+  for (Decl *D : Context.getTranslationUnitDecl()->decls()) {
+if (ObjCImplEndLoc.isValid() &&

arphaman wrote:
> klimek wrote:
> > Why don't we do this as part of TraverseDecl() in the visitor?
> I think it's easier to handle the Objective-C `@implementation` logic here, 
> unless there's some better way that I can't see ATM.
Ok, in that case, can you write a comment at the start of the loop explaining 
that we basically only do that for the Objective-C @implementation? (I'd also 
like to understand that better in general, as I have no clue about Obj-C :)


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added inline comments.



Comment at: include/clang/Tooling/Refactoring/ASTSelection.h:68-74
+/// Traverses the given ASTContext and creates a tree of selected AST nodes.
+///
+/// \returns None if no nodes are selected in the AST, or a selected AST node
+/// that corresponds to the TranslationUnitDecl otherwise.
+Optional findSelectedASTNodes(const ASTContext ,
+   SourceLocation Location,
+   SourceRange SelectionRange);

arphaman wrote:
> klimek wrote:
> > Any reason not to do multiple ranges?
> > 
> > Also, it's not clear from reading the description here why we need the 
> > Location.
> I guess multiple ranges can be supported in follow-up patches to keep this 
> one simpler.
> 
> I'll add it to the comment, but the idea is that the location corresponds to 
> the cursor/right click position in the editor. That means that location 
> doesn't have to be identical to the selection, since you can select something 
> and then right click anywhere in the editor. 
I've decided to get rid of `Location` and `ContainsSelectionPoint` at this 
level. I will instead handle this editor specific thing at a higher-level and 
make selection search range only to simplify things at this level.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:100
+  SelectionStack.back().Children.push_back(std::move(Node));
+return true;
+  }

klimek wrote:
> arphaman wrote:
> > klimek wrote:
> > > Why do we always stop traversal?
> > False stops traversal, true is the default return value.
> Ah, right.  Generally, I'd have expected us to stop traversal once we're past 
> the range?
We already do stop traversal early in `findSelectedASTNodes` once we match 
everything that's possible (although if the selection doesn't overlap with 
anything we will traverse all top level nodes). I see the point though, we 
might as stop after the range as well. I added the check to do that in the 
updated patch.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:164
+  unsigned NumMatches = 0;
+  for (Decl *D : Context.getTranslationUnitDecl()->decls()) {
+if (ObjCImplEndLoc.isValid() &&

klimek wrote:
> Why don't we do this as part of TraverseDecl() in the visitor?
I think it's easier to handle the Objective-C `@implementation` logic here, 
unless there's some better way that I can't see ATM.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman updated this revision to Diff 107067.
arphaman marked 7 inline comments as done.
arphaman added a comment.

- Address review comments.
- Remove the `Location` parameter and `ContainsSelectionPoint` enum value.
- Stop traversing early when a declaration that ends after the selection range 
was reached.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012

Files:
  include/clang/Basic/SourceLocation.h
  include/clang/Basic/SourceManager.h
  include/clang/Tooling/Refactoring/ASTSelection.h
  lib/Tooling/Refactoring/ASTSelection.cpp
  lib/Tooling/Refactoring/CMakeLists.txt
  unittests/Tooling/ASTSelectionTest.cpp
  unittests/Tooling/CMakeLists.txt

Index: unittests/Tooling/CMakeLists.txt
===
--- unittests/Tooling/CMakeLists.txt
+++ unittests/Tooling/CMakeLists.txt
@@ -11,6 +11,7 @@
 endif()
 
 add_clang_unittest(ToolingTests
+  ASTSelectionTest.cpp
   CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
Index: unittests/Tooling/ASTSelectionTest.cpp
===
--- /dev/null
+++ unittests/Tooling/ASTSelectionTest.cpp
@@ -0,0 +1,456 @@
+//===- unittest/Tooling/ASTSelectionTest.cpp --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "TestVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+struct FileLocation {
+  unsigned Line, Column;
+
+  SourceLocation translate(const SourceManager ) {
+return SM.translateLineCol(SM.getMainFileID(), Line, Column);
+  }
+};
+
+using FileRange = std::pair;
+
+class SelectionFinderVisitor : public TestVisitor {
+  FileLocation Location;
+  Optional SelectionRange;
+
+public:
+  Optional Selection;
+
+  SelectionFinderVisitor(FileLocation Location,
+ Optional SelectionRange)
+  : Location(Location), SelectionRange(SelectionRange) {}
+
+  bool VisitTranslationUnitDecl(const TranslationUnitDecl *TU) {
+const ASTContext  = TU->getASTContext();
+const SourceManager  = Context.getSourceManager();
+
+SourceRange SelRange;
+if (SelectionRange) {
+  SelRange = SourceRange(SelectionRange->first.translate(SM),
+ SelectionRange->second.translate(SM));
+} else {
+  SourceLocation Loc = Location.translate(SM);
+  SelRange = SourceRange(Loc, Loc);
+}
+Selection = findSelectedASTNodes(Context, SelRange);
+return false;
+  }
+};
+
+Optional
+findSelectedASTNodes(StringRef Source, FileLocation Location,
+ Optional SelectionRange,
+ SelectionFinderVisitor::Language Language =
+ SelectionFinderVisitor::Lang_CXX11) {
+  SelectionFinderVisitor Visitor(Location, SelectionRange);
+  EXPECT_TRUE(Visitor.runOver(Source, Language));
+  return std::move(Visitor.Selection);
+}
+
+void checkNodeImpl(bool IsTypeMatched, const SelectedASTNode ,
+   SourceSelectionKind SelectionKind, unsigned NumChildren) {
+  ASSERT_TRUE(IsTypeMatched);
+  EXPECT_EQ(Node.Children.size(), NumChildren);
+  ASSERT_EQ(Node.SelectionKind, SelectionKind);
+}
+
+void checkDeclName(const SelectedASTNode , StringRef Name) {
+  const auto *ND = Node.Node.get();
+  EXPECT_TRUE(!!ND);
+  ASSERT_EQ(ND->getName(), Name);
+}
+
+template 
+const SelectedASTNode &
+checkNode(const SelectedASTNode , SourceSelectionKind SelectionKind,
+  unsigned NumChildren = 0,
+  typename std::enable_if::value, T>::type
+  *StmtOverloadChecker = nullptr) {
+  checkNodeImpl(isa(StmtNode.Node.get()), StmtNode, SelectionKind,
+NumChildren);
+  return StmtNode;
+}
+
+template 
+const SelectedASTNode &
+checkNode(const SelectedASTNode , SourceSelectionKind SelectionKind,
+  unsigned NumChildren = 0, StringRef Name = "",
+  typename std::enable_if::value, T>::type
+  *DeclOverloadChecker = nullptr) {
+  checkNodeImpl(isa(DeclNode.Node.get()), DeclNode, SelectionKind,
+NumChildren);
+  if (!Name.empty())
+checkDeclName(DeclNode, Name);
+  return DeclNode;
+}
+
+struct ForAllChildrenOf {
+  const SelectedASTNode 
+
+  static void childKindVerifier(const SelectedASTNode ,
+SourceSelectionKind SelectionKind) {
+for (const SelectedASTNode  : Node.Children) {
+  ASSERT_EQ(Node.SelectionKind, SelectionKind);
+  childKindVerifier(Child, SelectionKind);
+}
+  }
+
+public:
+  ForAllChildrenOf(const SelectedASTNode ) : Node(Node) {}
+
+  void 

[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-18 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added inline comments.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:100
+  SelectionStack.back().Children.push_back(std::move(Node));
+return true;
+  }

arphaman wrote:
> klimek wrote:
> > Why do we always stop traversal?
> False stops traversal, true is the default return value.
Ah, right.  Generally, I'd have expected us to stop traversal once we're past 
the range?


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-17 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added inline comments.



Comment at: include/clang/Tooling/Refactoring/ASTSelection.h:68-74
+/// Traverses the given ASTContext and creates a tree of selected AST nodes.
+///
+/// \returns None if no nodes are selected in the AST, or a selected AST node
+/// that corresponds to the TranslationUnitDecl otherwise.
+Optional findSelectedASTNodes(const ASTContext ,
+   SourceLocation Location,
+   SourceRange SelectionRange);

klimek wrote:
> Any reason not to do multiple ranges?
> 
> Also, it's not clear from reading the description here why we need the 
> Location.
I guess multiple ranges can be supported in follow-up patches to keep this one 
simpler.

I'll add it to the comment, but the idea is that the location corresponds to 
the cursor/right click position in the editor. That means that location doesn't 
have to be identical to the selection, since you can select something and then 
right click anywhere in the editor. 



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:100
+  SelectionStack.back().Children.push_back(std::move(Node));
+return true;
+  }

klimek wrote:
> Why do we always stop traversal?
False stops traversal, true is the default return value.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-17 Thread Eric Liu via Phabricator via cfe-commits
ioeric added a comment.

Some nits.




Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:23
+/// of the cursor or overlap with the selection range.
+class ASTSelectionFinder : public RecursiveASTVisitor {
+  const SourceLocation Location;

In LLVM, we use the following class layout:

```
class X {
public:
  void f();

private:
  void g();

  int member;
}
```



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:76
+
+  Optional getResult() {
+assert(SelectionStack.size() == 1 && "stack was not popped");

I think `getSelectedASTNode` would be clearer.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:90
+  return RecursiveASTVisitor::TraverseDecl(D);
+// TODO (Alex): Add location adjustment for ObjCImplDecls.
+SourceSelectionKind SelectionKind =

Use FIXME() instead of TODO in LLVM. Here and elsewhere.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:126-129
+SelectedASTNode Node = std::move(SelectionStack.back());
+SelectionStack.pop_back();
+if (SelectionKind != SourceSelectionKind::None || !Node.Children.empty())
+  SelectionStack.back().Children.push_back(std::move(Node));

This seems to be a recurring pattern. Maybe pull into a function?


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-17 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added inline comments.



Comment at: include/clang/Tooling/Refactoring/ASTSelection.h:30
+  /// inside of its source range.
+  ContainsSelectionPoint,
+

It's unclear what a selection point is. I'd have expected this to mean 
"overlaps" when first reading it.



Comment at: include/clang/Tooling/Refactoring/ASTSelection.h:68-74
+/// Traverses the given ASTContext and creates a tree of selected AST nodes.
+///
+/// \returns None if no nodes are selected in the AST, or a selected AST node
+/// that corresponds to the TranslationUnitDecl otherwise.
+Optional findSelectedASTNodes(const ASTContext ,
+   SourceLocation Location,
+   SourceRange SelectionRange);

Any reason not to do multiple ranges?

Also, it's not clear from reading the description here why we need the Location.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:100
+  SelectionStack.back().Children.push_back(std::move(Node));
+return true;
+  }

Why do we always stop traversal?



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:103
+
+  void TraverseDeclInPrevious(Decl *D) {
+assert(!SelectionStack.back().Children.empty() &&

A short comment explaining when this happens would help understand this.



Comment at: lib/Tooling/Refactoring/ASTSelection.cpp:164
+  unsigned NumMatches = 0;
+  for (Decl *D : Context.getTranslationUnitDecl()->decls()) {
+if (ObjCImplEndLoc.isValid() &&

Why don't we do this as part of TraverseDecl() in the visitor?



Comment at: lib/Tooling/Refactoring/SourceLocationUtils.h:1
+//===--- SourceLocationUtils.h - Source location helper functions 
-===//
+//

I'm somewhat opposed to files having "utils" in the name, as they tend to 
accumulate too much stuff.
Can we implement those in SourceLocation and SourceManager respectively?


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-17 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added a comment.

Ping.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-05 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman updated this revision to Diff 105269.
arphaman added a comment.

A a test-case for implicit declarations.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012

Files:
  include/clang/Tooling/Refactoring/ASTSelection.h
  lib/Tooling/Refactoring/ASTSelection.cpp
  lib/Tooling/Refactoring/CMakeLists.txt
  lib/Tooling/Refactoring/SourceLocationUtils.h
  unittests/Tooling/ASTSelectionTest.cpp
  unittests/Tooling/CMakeLists.txt

Index: unittests/Tooling/CMakeLists.txt
===
--- unittests/Tooling/CMakeLists.txt
+++ unittests/Tooling/CMakeLists.txt
@@ -11,6 +11,7 @@
 endif()
 
 add_clang_unittest(ToolingTests
+  ASTSelectionTest.cpp
   CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
Index: unittests/Tooling/ASTSelectionTest.cpp
===
--- /dev/null
+++ unittests/Tooling/ASTSelectionTest.cpp
@@ -0,0 +1,453 @@
+//===- unittest/Tooling/ASTSelectionTest.cpp --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "TestVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+struct FileLocation {
+  unsigned Line, Column;
+
+  SourceLocation translate(const SourceManager ) {
+return SM.translateLineCol(SM.getMainFileID(), Line, Column);
+  }
+};
+
+using FileRange = std::pair;
+
+class SelectionFinderVisitor : public TestVisitor {
+  FileLocation Location;
+  Optional SelectionRange;
+
+public:
+  Optional Selection;
+
+  SelectionFinderVisitor(FileLocation Location,
+ Optional SelectionRange)
+  : Location(Location), SelectionRange(SelectionRange) {}
+
+  bool VisitTranslationUnitDecl(const TranslationUnitDecl *TU) {
+const ASTContext  = TU->getASTContext();
+const SourceManager  = Context.getSourceManager();
+
+SourceRange SelRange;
+if (SelectionRange) {
+  SelRange = SourceRange(SelectionRange->first.translate(SM),
+ SelectionRange->second.translate(SM));
+}
+Selection = findSelectedASTNodes(Context, Location.translate(SM), SelRange);
+return false;
+  }
+};
+
+Optional
+findSelectedASTNodes(StringRef Source, FileLocation Location,
+ Optional SelectionRange,
+ SelectionFinderVisitor::Language Language =
+ SelectionFinderVisitor::Lang_CXX11) {
+  SelectionFinderVisitor Visitor(Location, SelectionRange);
+  EXPECT_TRUE(Visitor.runOver(Source, Language));
+  return std::move(Visitor.Selection);
+}
+
+void checkNodeImpl(bool IsTypeMatched, const SelectedASTNode ,
+   SourceSelectionKind SelectionKind, unsigned NumChildren) {
+  ASSERT_TRUE(IsTypeMatched);
+  EXPECT_EQ(Node.Children.size(), NumChildren);
+  ASSERT_EQ(Node.SelectionKind, SelectionKind);
+}
+
+void checkDeclName(const SelectedASTNode , StringRef Name) {
+  const auto *ND = Node.Node.get();
+  EXPECT_TRUE(!!ND);
+  ASSERT_EQ(ND->getName(), Name);
+}
+
+template 
+const SelectedASTNode &
+checkNode(const SelectedASTNode , SourceSelectionKind SelectionKind,
+  unsigned NumChildren = 0,
+  typename std::enable_if::value, T>::type
+  *StmtOverloadChecker = nullptr) {
+  checkNodeImpl(isa(StmtNode.Node.get()), StmtNode, SelectionKind,
+NumChildren);
+  return StmtNode;
+}
+
+template 
+const SelectedASTNode &
+checkNode(const SelectedASTNode , SourceSelectionKind SelectionKind,
+  unsigned NumChildren = 0, StringRef Name = "",
+  typename std::enable_if::value, T>::type
+  *DeclOverloadChecker = nullptr) {
+  checkNodeImpl(isa(DeclNode.Node.get()), DeclNode, SelectionKind,
+NumChildren);
+  if (!Name.empty())
+checkDeclName(DeclNode, Name);
+  return DeclNode;
+}
+
+struct ForAllChildrenOf {
+  const SelectedASTNode 
+
+  static void childKindVerifier(const SelectedASTNode ,
+SourceSelectionKind SelectionKind) {
+for (const SelectedASTNode  : Node.Children) {
+  ASSERT_EQ(Node.SelectionKind, SelectionKind);
+  childKindVerifier(Child, SelectionKind);
+}
+  }
+
+public:
+  ForAllChildrenOf(const SelectedASTNode ) : Node(Node) {}
+
+  void shouldHaveSelectionKind(SourceSelectionKind Kind) {
+childKindVerifier(Node, Kind);
+  }
+};
+
+ForAllChildrenOf allChildrenOf(const SelectedASTNode ) {
+  return ForAllChildrenOf(Node);
+}
+
+TEST(ASTSelectionFinder, CursorNoSelection) {
+  Optional Node =
+  findSelectedASTNodes(" void f() { }", {1, 1}, 

[PATCH] D35012: [refactor] Add the AST source selection component

2017-07-05 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman created this revision.
Herald added a subscriber: mgorny.

This patch adds the base AST source selection component to the refactoring 
library. AST selection is represented using a tree of `SelectedASTNode` values. 
Each selected node gets its own selection kind, which can actually be `None` 
even in the middle of tree (e.g. statement in a macro whose child is in a macro 
argument). The initial version constructs a "raw" selection tree, without 
applying filters and canonicalisation operations to the nodes.


Repository:
  rL LLVM

https://reviews.llvm.org/D35012

Files:
  include/clang/Tooling/Refactoring/ASTSelection.h
  lib/Tooling/Refactoring/ASTSelection.cpp
  lib/Tooling/Refactoring/CMakeLists.txt
  lib/Tooling/Refactoring/SourceLocationUtils.h
  unittests/Tooling/ASTSelectionTest.cpp
  unittests/Tooling/CMakeLists.txt

Index: unittests/Tooling/CMakeLists.txt
===
--- unittests/Tooling/CMakeLists.txt
+++ unittests/Tooling/CMakeLists.txt
@@ -11,6 +11,7 @@
 endif()
 
 add_clang_unittest(ToolingTests
+  ASTSelectionTest.cpp
   CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
Index: unittests/Tooling/ASTSelectionTest.cpp
===
--- /dev/null
+++ unittests/Tooling/ASTSelectionTest.cpp
@@ -0,0 +1,432 @@
+//===- unittest/Tooling/ASTSelectionTest.cpp --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "TestVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+struct FileLocation {
+  unsigned Line, Column;
+
+  SourceLocation translate(const SourceManager ) {
+return SM.translateLineCol(SM.getMainFileID(), Line, Column);
+  }
+};
+
+using FileRange = std::pair;
+
+class SelectionFinderVisitor : public TestVisitor {
+  FileLocation Location;
+  Optional SelectionRange;
+
+public:
+  Optional Selection;
+
+  SelectionFinderVisitor(FileLocation Location,
+ Optional SelectionRange)
+  : Location(Location), SelectionRange(SelectionRange) {}
+
+  bool VisitTranslationUnitDecl(const TranslationUnitDecl *TU) {
+const ASTContext  = TU->getASTContext();
+const SourceManager  = Context.getSourceManager();
+
+SourceRange SelRange;
+if (SelectionRange) {
+  SelRange = SourceRange(SelectionRange->first.translate(SM),
+ SelectionRange->second.translate(SM));
+}
+Selection = findSelectedASTNodes(Context, Location.translate(SM), SelRange);
+return false;
+  }
+};
+
+Optional
+findSelectedASTNodes(StringRef Source, FileLocation Location,
+ Optional SelectionRange,
+ SelectionFinderVisitor::Language Language =
+ SelectionFinderVisitor::Lang_CXX11) {
+  SelectionFinderVisitor Visitor(Location, SelectionRange);
+  EXPECT_TRUE(Visitor.runOver(Source, Language));
+  return std::move(Visitor.Selection);
+}
+
+void checkNodeImpl(bool IsTypeMatched, const SelectedASTNode ,
+   SourceSelectionKind SelectionKind, unsigned NumChildren) {
+  ASSERT_TRUE(IsTypeMatched);
+  EXPECT_EQ(Node.Children.size(), NumChildren);
+  ASSERT_EQ(Node.SelectionKind, SelectionKind);
+}
+
+void checkDeclName(const SelectedASTNode , StringRef Name) {
+  const auto *ND = Node.Node.get();
+  EXPECT_TRUE(!!ND);
+  ASSERT_EQ(ND->getName(), Name);
+}
+
+template 
+const SelectedASTNode &
+checkNode(const SelectedASTNode , SourceSelectionKind SelectionKind,
+  unsigned NumChildren = 0,
+  typename std::enable_if::value, T>::type
+  *StmtOverloadChecker = nullptr) {
+  checkNodeImpl(isa(StmtNode.Node.get()), StmtNode, SelectionKind,
+NumChildren);
+  return StmtNode;
+}
+
+template 
+const SelectedASTNode &
+checkNode(const SelectedASTNode , SourceSelectionKind SelectionKind,
+  unsigned NumChildren = 0, StringRef Name = "",
+  typename std::enable_if::value, T>::type
+  *DeclOverloadChecker = nullptr) {
+  checkNodeImpl(isa(DeclNode.Node.get()), DeclNode, SelectionKind,
+NumChildren);
+  if (!Name.empty())
+checkDeclName(DeclNode, Name);
+  return DeclNode;
+}
+
+struct ForAllChildrenOf {
+  const SelectedASTNode 
+
+  static void childKindVerifier(const SelectedASTNode ,
+SourceSelectionKind SelectionKind) {
+for (const SelectedASTNode  : Node.Children) {
+  ASSERT_EQ(Node.SelectionKind, SelectionKind);
+  childKindVerifier(Child, SelectionKind);
+