Merge remote-tracking branch 'aosp/upstream' into update_kati

* aosp/upstream:
  Remove .KATI_SYMLINK_OUTPUTS
  Install a specific version of ninja in the dockerfile
  Enable ninja-validations.sh
  Fix CI

Change-Id: I4c01f8978cb76c56e23ac89cfdafd969810f5624
diff --git a/.github/workflows/cpp-ci.yml b/.github/workflows/cpp-ci.yml
index 7807a93..178d298 100644
--- a/.github/workflows/cpp-ci.yml
+++ b/.github/workflows/cpp-ci.yml
@@ -11,18 +11,18 @@
 jobs:
   build:
 
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-22.04
 
     env:
-      CXX: clang++-12
-      CLANG_FORMAT: clang-format-12
+      CXX: clang++-14
+      CLANG_FORMAT: clang-format-14
 
     steps:
     - uses: actions/checkout@v2
     - name: install ninja
       run: |
         mkdir -p ${GITHUB_WORKSPACE}/ninja-bin; cd ${GITHUB_WORKSPACE}/ninja-bin
-        wget https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-linux.zip
+        wget https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-linux.zip
         unzip ninja-linux.zip
         rm ninja-linux.zip
         echo "${GITHUB_WORKSPACE}/ninja-bin" >> "$GITHUB_PATH"
diff --git a/Dockerfile b/Dockerfile
index 834e6c0..da61f8e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
 FROM ubuntu:22.04
 
-RUN apt-get update && apt-get install -y make git-core build-essential curl ninja-build python3 wget
+RUN apt-get update && apt-get install -y make git-core build-essential curl python3 wget unzip
 
 # Install Go
 RUN \
@@ -18,10 +18,18 @@
   cd .. && \
   rm -rf tmp/
 
+# Install ninja, we need a newer version than is in apt
+RUN \
+  mkdir -p /ninja && \
+  cd /ninja && \
+  wget https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-linux.zip && \
+  unzip ninja-linux.zip && \
+  rm ninja-linux.zip
+
 # Set environment variables for Go and Make.
 ENV GOROOT /goroot
 ENV GOPATH /gopath
-ENV PATH $GOROOT/bin:$GOPATH/bin:/make:$PATH
+ENV PATH $GOROOT/bin:$GOPATH/bin:/make:/ninja:$PATH
 
 # Copy project code.
 COPY . /src
diff --git a/run_test.go b/run_test.go
index ffc3629..c8c12a5 100644
--- a/run_test.go
+++ b/run_test.go
@@ -240,10 +240,13 @@
 	}
 	args = append(args, "SHELL=/bin/bash")
 
+	var stderrb bytes.Buffer
 	cmd := exec.Command(args[0], args[1:]...)
 	cmd.Dir = dir
+	cmd.Stderr = &stderrb
 	output, _ := cmd.Output()
 	write("stdout", output)
+	write("stderr", stderrb.Bytes())
 	if isNinjaTest {
 		output = normalize(output, normalizeNinja)
 	}
diff --git a/src/dep.cc b/src/dep.cc
index e033711..5b6e5d0 100644
--- a/src/dep.cc
+++ b/src/dep.cc
@@ -141,7 +141,6 @@
 struct RuleMerger {
   std::vector<const Rule*> rules;
   std::vector<std::pair<Symbol, RuleMerger*>> implicit_outputs;
-  std::vector<Symbol> symlink_outputs;
   std::vector<Symbol> validations;
   const Rule* primary_rule;
   const RuleMerger* parent;
@@ -155,8 +154,6 @@
     implicit_outputs.push_back(std::make_pair(output, merger));
   }
 
-  void AddSymlinkOutput(Symbol output) { symlink_outputs.push_back(output); }
-
   void AddValidation(Symbol validation) { validations.push_back(validation); }
 
   void SetImplicitOutput(Symbol output, Symbol p, const RuleMerger* merger) {
@@ -262,14 +259,6 @@
       }
     }
 
-    for (auto& symlink_output : symlink_outputs) {
-      if (!all_outputs.exists(symlink_output)) {
-        ERROR_LOC(primary_rule->cmd_loc(), "*** undeclared symlink output: %s",
-                  symlink_output.c_str());
-      }
-      n->symlink_outputs.push_back(symlink_output);
-    }
-
     for (auto& validation : validations) {
       n->actual_validations.push_back(validation);
     }
@@ -299,7 +288,6 @@
         implicit_rules_(new RuleTrie()),
         depfile_var_name_(Intern(".KATI_DEPFILE")),
         implicit_outputs_var_name_(Intern(".KATI_IMPLICIT_OUTPUTS")),
-        symlink_outputs_var_name_(Intern(".KATI_SYMLINK_OUTPUTS")),
         ninja_pool_var_name_(Intern(".KATI_NINJA_POOL")),
         validations_var_name_(Intern(".KATI_VALIDATIONS")),
         tags_var_name_(Intern(".KATI_TAGS")) {
@@ -456,17 +444,6 @@
           p.second.AddValidation(sym);
         }
       }
-
-      var = vars->Lookup(symlink_outputs_var_name_);
-      if (var->IsDefined()) {
-        std::string symlink_outputs;
-        var->Eval(ev_, &symlink_outputs);
-
-        for (std::string_view output : WordScanner(symlink_outputs)) {
-          Symbol sym = Intern(TrimLeadingCurdir(output));
-          p.second.AddSymlinkOutput(sym);
-        }
-      }
     }
   }
 
@@ -853,12 +830,6 @@
       n->validations.push_back({validation, c});
     }
 
-    if (!g_flags.use_ninja_symlink_outputs && !n->symlink_outputs.empty()) {
-      ERROR_LOC(n->loc,
-                ".KATI_SYMLINK_OUTPUTS not allowed without "
-                "--use_ninja_symlink_outputs");
-    }
-
     // Block on werror_writable/werror_phony_looks_real, because otherwise we
     // can't rely on is_phony being valid for this check.
     if (!n->is_phony && n->cmds.empty() && g_flags.werror_writable &&
@@ -942,7 +913,6 @@
   SymbolSet restat_;
   Symbol depfile_var_name_;
   Symbol implicit_outputs_var_name_;
-  Symbol symlink_outputs_var_name_;
   Symbol ninja_pool_var_name_;
   Symbol validations_var_name_;
   Symbol tags_var_name_;
diff --git a/src/dep.h b/src/dep.h
index a3a365b..594674c 100644
--- a/src/dep.h
+++ b/src/dep.h
@@ -46,7 +46,6 @@
   bool is_phony;
   bool is_restat;
   std::vector<Symbol> implicit_outputs;
-  std::vector<Symbol> symlink_outputs;
   std::vector<Symbol> actual_inputs;
   std::vector<Symbol> actual_order_only_inputs;
   std::vector<Symbol> actual_validations;
diff --git a/src/file_cache.h b/src/file_cache.h
index ce3be6a..a17c861 100644
--- a/src/file_cache.h
+++ b/src/file_cache.h
@@ -18,7 +18,7 @@
 #include <string>
 #include <unordered_set>
 
-class Makefile;
+#include "file.h"
 
 class MakefileCacheManager {
  public:
diff --git a/src/flags.cc b/src/flags.cc
index 37f08f4..64a4af2 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -109,8 +109,6 @@
       no_ninja_prelude = true;
     } else if (!strcmp(arg, "--use_ninja_phony_output")) {
       use_ninja_phony_output = true;
-    } else if (!strcmp(arg, "--use_ninja_symlink_outputs")) {
-      use_ninja_symlink_outputs = true;
     } else if (!strcmp(arg, "--use_ninja_validations")) {
       use_ninja_validations = true;
     } else if (!strcmp(arg, "--werror_find_emulator")) {
diff --git a/src/flags.h b/src/flags.h
index 5b36518..223116b 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -45,7 +45,6 @@
   bool no_builtin_rules;
   bool no_ninja_prelude;
   bool use_ninja_phony_output;
-  bool use_ninja_symlink_outputs;
   bool use_ninja_validations;
   bool werror_find_emulator;
   bool werror_overriding_commands;
diff --git a/src/func.cc b/src/func.cc
index b7e1b24..75a7cb6 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -1086,7 +1086,9 @@
 
 #define ENTRY(name, args...) \
   {                          \
-    name, { name, args }     \
+    name, {                  \
+      name, args             \
+    }                        \
   }
 
 static const std::unordered_map<std::string_view, FuncInfo> g_func_info_map = {
diff --git a/src/ninja.cc b/src/ninja.cc
index ff3582a..d030c2d 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -579,14 +579,6 @@
 
     out << "\n";
 
-    if (!node->symlink_outputs.empty()) {
-      out << " symlink_outputs =";
-      for (auto const& s : node->symlink_outputs) {
-        out << " " << EscapeBuildTarget(s);
-      }
-      out << "\n";
-    }
-
     std::string pool;
     if (node->ninja_pool_var) {
       node->ninja_pool_var->Eval(ev_, &pool);
diff --git a/testcase/ninja_symlink_outputs.sh b/testcase/ninja_symlink_outputs.sh
deleted file mode 100644
index ed0502f..0000000
--- a/testcase/ninja_symlink_outputs.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2020 Google Inc. All rights reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http:#www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -e
-
-mk="$@"
-
-cat <<EOF >Makefile
-dangling_symlink:
-	ln -sf nil dangling_symlink
-dangling_symlink: .KATI_SYMLINK_OUTPUTS := dangling_symlink
-
-file:
-	touch file
-
-resolved_symlink: file
-	ln -sf file resolved_symlink
-resolved_symlink: .KATI_SYMLINK_OUTPUTS := resolved_symlink
-
-incorrectly_declared_symlink:
-	ln -sf nil incorrectly_declared_symlink
-incorrectly_declared_symlink: .KATI_SYMLINK_OUTPUTS := something_else
-
-foo bar: file
-	ln -sf file foo && cp foo bar
-foo: .KATI_SYMLINK_OUTPUTS := foo
-bar: .KATI_SYMLINK_OUTPUTS := bar
-EOF
-
-all="dangling_symlink resolved_symlink foo bar"
-if echo "${mk}" | grep kati > /dev/null; then
-  mk="${mk} --use_ninja_symlink_outputs"
-fi
-${mk} -j1 $all
-
-if [ -e ninja.sh ]; then
-  ./ninja.sh -j1 $all
-
-  if ! grep -A1 "build dangling_symlink:" build.ninja | grep -q "symlink_outputs = dangling_symlink"; then
-    echo "symlink_outputs not present for dangling_symlink in build.ninja"
-  fi
-  if ! grep -A1 "build resolved_symlink:" build.ninja | grep -q "symlink_outputs = resolved_symlink"; then
-    echo "symlink_outputs not present for resolved_symlink in build.ninja"
-  fi
-  if grep -A1 "build file:" build.ninja | grep -q "symlink_outputs ="; then
-    echo "unexpected symlink_outputs present for file in build.ninja"
-  fi
-
-  # Even though this was a multi-output Make rule, Kati generates individual build
-  # statements for each of the outputs, therefore the symlink_outputs list is a singleton.
-  if ! grep -A1 "build foo: rule" build.ninja | grep -q "symlink_outputs = foo"; then
-    echo "symlink_outputs not present for foo in build.ninja"
-  fi
-  if ! grep -A1 "build bar: rule" build.ninja | grep -q "symlink_outputs = bar"; then
-    echo "symlink_outputs not present for bar in build.ninja"
-  fi
-
-  ${mk} -j1 "incorrectly_declared_symlink" 2> kati.err
-  # The actual error message contains the line number in the Makefile.
-  if ! grep "Makefile:" kati.err | grep "undeclared symlink output: something_else"; then
-    echo "did not get undeclared symlink out error message"
-  fi
-fi
\ No newline at end of file
diff --git a/testcase/ninja_validations.sh b/testcase/ninja_validations.sh
index cd77a01..33e9e7f 100644
--- a/testcase/ninja_validations.sh
+++ b/testcase/ninja_validations.sh
@@ -1,5 +1,4 @@
 #!/bin/bash
-# TODO(ninja): enable once upstream ninja supports validations
 #
 # Copyright 2015 Google Inc. All rights reserved
 #