Fix a crash on invalid on `not_needed(scope)` without a 2nd argument.

While here, also fix an accepts-invalid where GN would accept
and silently ignore a third argument if the first argument was
a string or a list.

Bug: gn:38
Change-Id: I552585a9467284095ea583ee0fce01e4dad09c0c
Reviewed-on: https://gn-review.googlesource.com/c/3600
Reviewed-by: Petr Hosek <phosek@google.com>
Commit-Queue: Petr Hosek <phosek@google.com>
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index 4c423cb..6abe758 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -700,6 +700,12 @@
   // Extract the source scope if different from current one.
   Scope* source = scope;
   if (value->type() == Value::SCOPE) {
+    if (args_cur == args_vector.end()) {
+      *err = Err(
+          function, "Wrong number of arguments.",
+          "The first argument is a scope, expecting two or three arguments.");
+      return Value();
+    }
     // Copy the scope value if it will be overridden.
     if (value == &result_value) {
       scope_value = Value(nullptr, value->scope_value()->MakeClosure());
@@ -712,6 +718,11 @@
       return Value();
     value = &result_value;
     args_cur++;
+  } else if (args_vector.size() > 2) {
+    *err = Err(
+        function, "Wrong number of arguments.",
+        "The first argument is not a scope, expecting one or two arguments.");
+    return Value();
   }
 
   // Extract the exclusion list if defined.
diff --git a/tools/gn/functions_target_unittest.cc b/tools/gn/functions_target_unittest.cc
index 3edd77d..642b8ce 100644
--- a/tools/gn/functions_target_unittest.cc
+++ b/tools/gn/functions_target_unittest.cc
@@ -89,6 +89,37 @@
   ASSERT_TRUE(err.has_error());
   EXPECT_EQ("Not supported with a variable list.", err.message());
 
+  TestParseInput argcount_error_input(
+      "source_set(\"foo\") {\n"
+      "  not_needed()\n"
+      "}\n");
+  ASSERT_FALSE(argcount_error_input.has_error());
+  err = Err();
+  argcount_error_input.parsed()->Execute(setup.scope(), &err);
+  ASSERT_TRUE(err.has_error());
+  EXPECT_EQ("Wrong number of arguments.", err.message());
+
+  TestParseInput scope_error_input(
+      "source_set(\"foo\") {\n"
+      "  a = {x = 1 y = 2}\n"
+      "  not_needed(a)\n"
+      "}\n");
+  ASSERT_FALSE(scope_error_input.has_error());
+  err = Err();
+  scope_error_input.parsed()->Execute(setup.scope(), &err);
+  ASSERT_TRUE(err.has_error());
+  EXPECT_EQ("Wrong number of arguments.", err.message());
+
+  TestParseInput string_error_input(
+      "source_set(\"foo\") {\n"
+      "  not_needed(\"*\", {}, \"*\")\n"
+      "}\n");
+  ASSERT_FALSE(string_error_input.has_error());
+  err = Err();
+  string_error_input.parsed()->Execute(setup.scope(), &err);
+  ASSERT_TRUE(err.has_error());
+  EXPECT_EQ("Wrong number of arguments.", err.message());
+
   TestParseInput template_input(
       R"(# Test that not_needed() propagates through templates correctly;
       # no error should arise from not using "a".