[tools] repurpose generate_compile_commands.py to generate_idefiles.py

and let it generate a configuration file for the c++ analyzers and the Dart analyzer

Workaround for: https://github.com/Dart-Code/Dart-Code/issues/1295
Change-Id: I6d1d8100649116c2fc8325cf73c4bfc11f9eacb3
Reviewed-on: https://dart-review.googlesource.com/c/88061
Reviewed-by: Stevie Strickland <sstrickl@google.com>
diff --git a/.gitignore b/.gitignore
index 8045eb3..3e23d6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,10 @@
 .vscode
 .history
 
+# analysis server files
+analysis_options.yaml
+compile_commands.json
+
 # GDB files
 .gdb_history
 
@@ -86,4 +90,3 @@
 /outline.dill
 /generated/
 /crash_logs/
-compile_commands.json
diff --git a/tools/generate_compile_commands.py b/tools/generate_compile_commands.py
deleted file mode 100755
index c8a1506..0000000
--- a/tools/generate_compile_commands.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-import argparse
-import generate_buildfiles
-import json
-import subprocess
-import sys
-import utils
-import os
-
-# Python script to generate compile_commands.json which is used by the clang
-# and intellij language analysis servers used in IDEs such as Visual Studio
-# Code and Emacs.
-
-HOST_OS = utils.GuessOS()
-
-
-def GenerateCompileCommands(options):
-  gn_result = generate_buildfiles.RunGn(options)
-  if (gn_result != 0):
-    return gn_result
-
-  out_folder = utils.GetBuildRoot(HOST_OS, mode="debug", arch="x64")
-
-  if (not os.path.isdir(out_folder)):
-    return 1
-
-  command_set = json.loads(
-      subprocess.check_output(
-          ["ninja", "-C", out_folder, "-t", "compdb", "cxx", "cc", "h"]
-      )
-  )
-
-  commands = []
-  for obj in command_set:
-    command = obj["command"]
-
-    # Skip precompiled mode, a lot of code is commented out in precompiled mode
-    if ("-DDART_PRECOMPILED_RUNTIME" in command):
-      continue
-
-    # Remove warnings
-    command = command.replace("-Werror", "")
-
-    obj["command"] = command
-    commands += [obj]
-
-  json.dump(commands, open("compile_commands.json", "w"), indent=4)
-
-  return 0
-
-
-def ParseArgs(args):
-  args = args[1:]
-  parser = argparse.ArgumentParser(
-      description="A script to generate compile_commands.json which is used by"
-      + "the clang and intellij language analysis servers used in IDEs such as"
-      + "Visual Studio Code and Emacs")
-
-  parser.add_argument("-v", "--verbose",
-                      help='Verbose output.',
-                      default=False,
-                      action="store_true")
-
-  return parser.parse_args(args)
-
-
-def main(argv):
-  options = ParseArgs(argv)
-  return GenerateCompileCommands(options)
-
-
-if __name__ == '__main__':
-  sys.exit(main(sys.argv))
diff --git a/tools/generate_idefiles.py b/tools/generate_idefiles.py
new file mode 100755
index 0000000..51b41e6
--- /dev/null
+++ b/tools/generate_idefiles.py
@@ -0,0 +1,145 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+"""Script to generate configuration files for analysis servers of C++ and Dart.
+
+It generates compile_commands.json for C++ clang and intellij and
+analysis_options.yaml for the Dart analyzer.
+"""
+
+import argparse
+import json
+import os
+import subprocess
+import sys
+
+import generate_buildfiles
+import utils
+
+HOST_OS = utils.GuessOS()
+
+
+def GenerateIdeFiles(options):
+  GenerateCompileCommands(options)
+  GenerateAnalysisOptions(options)
+
+
+def GenerateCompileCommands(options):
+  """Generate compile_commands.json for the C++ analysis servers.
+
+  compile_commands.json is used by the c++ clang and intellij language analysis
+  servers used in IDEs such as Visual Studio Code and Emacs.
+
+  Args:
+    options: supported options include: verbose, force, dir
+
+  Returns:
+    success (0) or failure (non zero)
+  """
+
+  fname = os.path.join(options.dir, "compile_commands.json")
+
+  if os.path.isfile(fname) and not options.force:
+    print fname + " already exists, use --force to override"
+    return
+
+  gn_result = generate_buildfiles.RunGn(options)
+  if gn_result != 0:
+    return gn_result
+
+  out_folder = utils.GetBuildRoot(HOST_OS, mode="debug", arch="x64")
+
+  if not os.path.isdir(out_folder):
+    return 1
+
+  command_set = json.loads(
+      subprocess.check_output(
+          ["ninja", "-C", out_folder, "-t", "compdb", "cxx", "cc", "h"]))
+
+  commands = []
+  for obj in command_set:
+    command = obj["command"]
+
+    # Skip precompiled mode, a lot of code is commented out in precompiled mode
+    if "-DDART_PRECOMPILED_RUNTIME" in command:
+      continue
+
+    # Remove warnings
+    command = command.replace("-Werror", "")
+
+    obj["command"] = command
+    commands += [obj]
+
+  with open(fname, "w") as f:
+    json.dump(commands, f, indent=4)
+
+  return 0
+
+
+def GenerateAnalysisOptions(options):
+  """Generate analysis_optioms.yaml for the Dart analyzer.
+
+  To prevent dartanalyzer from tripping on the non-Dart files when it is
+  started from the root dart-sdk directory.
+  https://github.com/Dart-Code/Dart-Code/issues/1295
+
+  Args:
+    options: supported options include: force, dir
+  """
+  contents = """analyzer:
+  exclude:
+    - docs/newsletter/20171103/**
+    - out/**
+    - runtime/**
+    - samples-dev/swarm/**
+    - sdk/lib/**
+    - tests/**
+    - third_party/observatory_pub_packages/**
+    - third_party/pkg/**
+    - third_party/pkg_tested/dart_style/**
+    - third_party/tcmalloc/**
+    - tools/apps/update_homebrew/**
+    - tools/dart2js/**
+    - tools/dom/**
+    - tools/sdks/dart-sdk/lib/**
+    - tools/status_clean.dart
+    - xcodebuild / **"""
+
+  fname = os.path.join(options.dir, "analysis_options.yaml")
+
+  if os.path.isfile(fname) and not options.force:
+    print fname + " already exists, use --force to override"
+    return
+
+  with open(fname, "w") as f:
+    f.write(contents)
+
+
+def main(argv):
+  parser = argparse.ArgumentParser(
+      description="Python script to generate compile_commands.json and "
+      "analysis_options.yaml which are used by the analysis servers for "
+      "c++ and Dart.")
+
+  parser.add_argument("-v", "--verbose",
+                      help="Verbose output.",
+                      action="store_true")
+
+  parser.add_argument("-f", "--force",
+                      help="Override files.",
+                      action="store_true")
+
+  parser.add_argument("-d", "--dir",
+                      help="Target directory.",
+                      default=utils.DART_DIR)
+
+  options = parser.parse_args(argv[1:])
+
+  return GenerateIdeFiles(options)
+
+
+if __name__ == "__main__":
+  sys.exit(main(sys.argv))