]> granicus.if.org Git - clang/commitdiff
[refactor][selection] canonicalize selected string literal to objc
authorAlex Lorenz <arphaman@gmail.com>
Thu, 2 Nov 2017 18:05:48 +0000 (18:05 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Thu, 2 Nov 2017 18:05:48 +0000 (18:05 +0000)
string literal when possible

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317224 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Tooling/Refactoring/ASTSelection.cpp
unittests/Tooling/ASTSelectionTest.cpp

index 71a0d44be1dc1a38f8092f00a5cb45002f139c44..ab2be1551219ca74df7aa42a2bb78e2421c6f540 100644 (file)
@@ -249,9 +249,30 @@ struct SelectedNodeWithParents {
   SelectedNodeWithParents &operator=(SelectedNodeWithParents &&) = default;
   SelectedASTNode::ReferenceType Node;
   llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents;
+
+  /// Canonicalizes the given selection by selecting different related AST nodes
+  /// when it makes sense to do so.
+  void canonicalize();
 };
 } // end anonymous namespace
 
+void SelectedNodeWithParents::canonicalize() {
+  const Stmt *S = Node.get().Node.get<Stmt>();
+  assert(S && "non statement selection!");
+  const Stmt *Parent = Parents[Parents.size() - 1].get().Node.get<Stmt>();
+  if (!Parent)
+    return;
+  // Select the parent expression when:
+  // - The string literal in ObjC string literal is selected, e.g.:
+  //     @"test"   becomes   @"test"
+  //      ~~~~~~             ~~~~~~~
+  if (isa<StringLiteral>(S) && isa<ObjCStringLiteral>(Parent))
+    Node = Parents.pop_back_val();
+  // FIXME: Syntactic form -> Entire pseudo-object expr.
+  // FIXME: Callee -> Call.
+  // FIXME: Callee member expr -> Call.
+}
+
 /// Finds the set of bottom-most selected AST nodes that are in the selection
 /// tree with the specified selection kind.
 ///
@@ -330,7 +351,7 @@ CodeRangeASTSelection::create(SourceRange SelectionRange,
     return None;
   const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<Stmt>();
   if (!isa<CompoundStmt>(CodeRangeStmt)) {
-    // FIXME (Alex L): Canonicalize.
+    Selected.canonicalize();
     return CodeRangeASTSelection(Selected.Node, Selected.Parents,
                                  /*AreChildrenSelected=*/false);
   }
index 1435334d6cc4817c17665f089e00c090310cff99..f10d899a0a73ce6e1ffcb98d446ae007f34d3394 100644 (file)
@@ -972,4 +972,36 @@ TEST(ASTSelectionFinder, SimpleCodeRangeASTSelectionInObjCMethod) {
       SelectionFinderVisitor::Lang_OBJC);
 }
 
+TEST(ASTSelectionFinder, CanonicalizeObjCStringLiteral) {
+  StringRef Source = R"(
+void foo() {
+  (void)@"test";
+}
+      )";
+  // Just '"test"':
+  findSelectedASTNodesWithRange(
+      Source, {3, 10}, FileRange{{3, 10}, {3, 16}},
+      [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+        EXPECT_TRUE(Node);
+        Optional<CodeRangeASTSelection> SelectedCode =
+            CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+        EXPECT_TRUE(SelectedCode);
+        EXPECT_EQ(SelectedCode->size(), 1u);
+        EXPECT_TRUE(isa<ObjCStringLiteral>((*SelectedCode)[0]));
+      },
+      SelectionFinderVisitor::Lang_OBJC);
+  // Just 'test':
+  findSelectedASTNodesWithRange(
+      Source, {3, 11}, FileRange{{3, 11}, {3, 15}},
+      [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+        EXPECT_TRUE(Node);
+        Optional<CodeRangeASTSelection> SelectedCode =
+            CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+        EXPECT_TRUE(SelectedCode);
+        EXPECT_EQ(SelectedCode->size(), 1u);
+        EXPECT_TRUE(isa<ObjCStringLiteral>((*SelectedCode)[0]));
+      },
+      SelectionFinderVisitor::Lang_OBJC);
+}
+
 } // end anonymous namespace