Disallow non-buildable sources in binary targets

When adding a file that's not a source, header, or object file to a source_set,
loadable_module, shared_library, executable, or static_library, gn will now
generate an error like the following:

ERROR at //third_party/protobuf/proto_library.gni:369:15: Only source, header,
and object files belong in the sources of a
source_set. //out/Test/pyproto/google_apis/gcm/protocol/mcs_pb2.py is not one of
the valid types.
    sources = get_target_outputs(":$action_name")
              ^---------------------------------
See //google_apis/gcm/BUILD.gn:78:1: whence it was called.
proto_library("proto") {
^-----------------------
See //BUILD.gn:89:7: which caused the file to be included.
      "//google_apis/gcm:gcm_unit_tests",
      ^---------------------------------

BUG=77
R=brettw

Change-Id: I4ed8da10c48e3e5d74f79e51d8222c998a7b883a
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/4980
Commit-Queue: Brett Wilson <brettw@google.com>
Reviewed-by: Brett Wilson <brettw@google.com>
diff --git a/tools/gn/binary_target_generator.cc b/tools/gn/binary_target_generator.cc
index 60af242..6d8cec9 100644
--- a/tools/gn/binary_target_generator.cc
+++ b/tools/gn/binary_target_generator.cc
@@ -68,6 +68,38 @@
     return;
 }
 
+bool BinaryTargetGenerator::FillSources() {
+  bool ret = TargetGenerator::FillSources();
+  for (std::size_t i = 0; i < target_->sources().size(); ++i) {
+    const auto& source = target_->sources()[i];
+    switch (source.type()) {
+      case SourceFile::SOURCE_CPP:
+      case SourceFile::SOURCE_H:
+      case SourceFile::SOURCE_C:
+      case SourceFile::SOURCE_M:
+      case SourceFile::SOURCE_MM:
+      case SourceFile::SOURCE_S:
+      case SourceFile::SOURCE_ASM:
+      case SourceFile::SOURCE_O:
+        // These are allowed.
+        break;
+      case SourceFile::SOURCE_RC:
+      case SourceFile::SOURCE_DEF:
+      case SourceFile::SOURCE_RS:
+      case SourceFile::SOURCE_GO:
+      case SourceFile::SOURCE_UNKNOWN:
+      case SourceFile::SOURCE_NUMTYPES:
+        *err_ =
+            Err(scope_->GetValue(variables::kSources, true)->list_value()[i],
+                std::string("Only source, header, and object files belong in "
+                            "the sources of a ") +
+                    Target::GetStringForOutputType(target_->output_type()) +
+                    ". " + source.value() + " is not one of the valid types.");
+    }
+  }
+  return ret;
+}
+
 bool BinaryTargetGenerator::FillCompleteStaticLib() {
   if (target_->output_type() == Target::STATIC_LIBRARY) {
     const Value* value = scope_->GetValue(variables::kCompleteStaticLib, true);
diff --git a/tools/gn/binary_target_generator.h b/tools/gn/binary_target_generator.h
index 40fc314..6cbd11e 100644
--- a/tools/gn/binary_target_generator.h
+++ b/tools/gn/binary_target_generator.h
@@ -22,6 +22,7 @@
 
  protected:
   void DoRun() override;
+  bool FillSources() override;
 
  private:
   bool FillCompleteStaticLib();
diff --git a/tools/gn/source_dir.cc b/tools/gn/source_dir.cc
index 0fd5c75..50b4517 100644
--- a/tools/gn/source_dir.cc
+++ b/tools/gn/source_dir.cc
@@ -98,10 +98,10 @@
     return ret;
 
   const std::string& input_string = p.string_value();
-  if (!ValidateResolveInput<std::string>(true, p, input_string, err)) {
+  if (!ValidateResolveInput<std::string>(true, p, input_string, err))
     return ret;
-  }
-  ret.value_ = ResolveRelative(input_string, value_, true, source_root);
+
+  ret.SetValue(ResolveRelative(input_string, value_, true, source_root));
   return ret;
 }
 
diff --git a/tools/gn/source_file.cc b/tools/gn/source_file.cc
index 7c860d4..2923227 100644
--- a/tools/gn/source_file.cc
+++ b/tools/gn/source_file.cc
@@ -55,18 +55,19 @@
 SourceFile::SourceFile() : type_(SOURCE_UNKNOWN) {}
 
 SourceFile::SourceFile(const base::StringPiece& p)
-    : value_(p.data(), p.size()), type_(GetSourceFileType(value_)) {
+    : value_(p.data(), p.size()) {
   DCHECK(!value_.empty());
   AssertValueSourceFileString(value_);
   NormalizePath(&value_);
+  type_ = GetSourceFileType(value_);
 }
 
-SourceFile::SourceFile(SwapIn, std::string* value)
-    : type_(GetSourceFileType(*value)) {
+SourceFile::SourceFile(SwapIn, std::string* value) {
   value_.swap(*value);
   DCHECK(!value_.empty());
   AssertValueSourceFileString(value_);
   NormalizePath(&value_);
+  type_ = GetSourceFileType(value_);
 }
 
 SourceFile::~SourceFile() = default;
@@ -92,3 +93,8 @@
 base::FilePath SourceFile::Resolve(const base::FilePath& source_root) const {
   return ResolvePath(value_, true, source_root);
 }
+
+void SourceFile::SetValue(const std::string& value) {
+  value_ = value;
+  type_ = GetSourceFileType(value_);
+}
diff --git a/tools/gn/source_file.h b/tools/gn/source_file.h
index bcf5f42..d42063d 100644
--- a/tools/gn/source_file.h
+++ b/tools/gn/source_file.h
@@ -97,11 +97,16 @@
     return value_ < other.value_;
   }
 
-  void swap(SourceFile& other) { value_.swap(other.value_); }
+  void swap(SourceFile& other) {
+    value_.swap(other.value_);
+    std::swap(type_, other.type_);
+  }
 
  private:
   friend class SourceDir;
 
+  void SetValue(const std::string& value);
+
   std::string value_;
   Type type_;
 
diff --git a/tools/gn/target_generator.h b/tools/gn/target_generator.h
index 627505d..8795cbf 100644
--- a/tools/gn/target_generator.h
+++ b/tools/gn/target_generator.h
@@ -47,7 +47,7 @@
 
   const BuildSettings* GetBuildSettings() const;
 
-  bool FillSources();
+  virtual bool FillSources();
   bool FillPublic();
   bool FillConfigs();
   bool FillOutputs(bool allow_substitutions);