1d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// Protocol Buffers - Google's data interchange format
2d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// Copyright 2008 Google Inc.  All rights reserved.
3d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// http://code.google.com/p/protobuf/
4d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville//
5d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// Redistribution and use in source and binary forms, with or without
6d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// modification, are permitted provided that the following conditions are
7d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// met:
8d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville//
9d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville//     * Redistributions of source code must retain the above copyright
10d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// notice, this list of conditions and the following disclaimer.
11d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville//     * Redistributions in binary form must reproduce the above
12d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// copyright notice, this list of conditions and the following disclaimer
13d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// in the documentation and/or other materials provided with the
14d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// distribution.
15d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville//     * Neither the name of Google Inc. nor the names of its
16d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// contributors may be used to endorse or promote products derived from
17d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// this software without specific prior written permission.
18d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville//
19d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
31d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// Author: kenton@google.com (Kenton Varda)
32d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
33d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <google/protobuf/compiler/mock_code_generator.h>
34d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
35d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <google/protobuf/testing/file.h>
36d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <google/protobuf/descriptor.h>
37d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <google/protobuf/io/zero_copy_stream.h>
38d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <google/protobuf/io/printer.h>
39d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <google/protobuf/stubs/strutil.h>
40d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <google/protobuf/stubs/substitute.h>
41d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <gtest/gtest.h>
42d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#include <google/protobuf/stubs/stl_util-inl.h>
43d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
44d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillenamespace google {
45d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillenamespace protobuf {
46d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillenamespace compiler {
47d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
48d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestatic const char* kFirstInsertionPointName = "first_mock_insertion_point";
49d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestatic const char* kSecondInsertionPointName = "second_mock_insertion_point";
50d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestatic const char* kFirstInsertionPoint =
51d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    "# @@protoc_insertion_point(first_mock_insertion_point) is here\n";
52d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestatic const char* kSecondInsertionPoint =
53d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    "  # @@protoc_insertion_point(second_mock_insertion_point) is here\n";
54d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
55d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink SavilleMockCodeGenerator::MockCodeGenerator(const string& name)
56d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    : name_(name) {}
57d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
58d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink SavilleMockCodeGenerator::~MockCodeGenerator() {}
59d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
60d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillevoid MockCodeGenerator::ExpectGenerated(
61d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& name,
62d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& parameter,
63d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& insertions,
64d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& file,
65d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& first_message_name,
66d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& output_directory) {
67d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  string content;
68d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  ASSERT_TRUE(File::ReadFileToString(
69d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      output_directory + "/" + GetOutputFileName(name, file), &content));
70d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
71d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  vector<string> lines;
72d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  SplitStringUsing(content, "\n", &lines);
73d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
74d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  while (!lines.empty() && lines.back().empty()) {
75d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    lines.pop_back();
76d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  }
77d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  for (int i = 0; i < lines.size(); i++) {
78d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    lines[i] += "\n";
79d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  }
80d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
81d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  vector<string> insertion_list;
82d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  if (!insertions.empty()) {
83d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    SplitStringUsing(insertions, ",", &insertion_list);
84d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  }
85d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
86d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  ASSERT_EQ(lines.size(), 3 + insertion_list.size() * 2);
87d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  EXPECT_EQ(GetOutputFileContent(name, parameter, file, first_message_name),
88d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville            lines[0]);
89d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
90d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
91d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]);
92d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
93d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  for (int i = 0; i < insertion_list.size(); i++) {
94d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
95d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                                   file, first_message_name),
96d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              lines[1 + i]);
97d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    // Second insertion point is indented, so the inserted text should
98d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    // automatically be indented too.
99d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    EXPECT_EQ("  " + GetOutputFileContent(insertion_list[i], "second_insert",
100d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                                          file, first_message_name),
101d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              lines[2 + insertion_list.size() + i]);
102d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  }
103d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}
104d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
105d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillebool MockCodeGenerator::Generate(
106d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const FileDescriptor* file,
107d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& parameter,
108d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    OutputDirectory* output_directory,
109d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    string* error) const {
110d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  for (int i = 0; i < file->message_type_count(); i++) {
111d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) {
112d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      string command = StripPrefixString(file->message_type(i)->name(),
113d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                                         "MockCodeGenerator_");
114d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      if (command == "Error") {
115d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        *error = "Saw message type MockCodeGenerator_Error.";
116d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        return false;
117d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      } else if (command == "Exit") {
118d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        cerr << "Saw message type MockCodeGenerator_Exit." << endl;
119d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        exit(123);
120d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      } else if (command == "Abort") {
121d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        cerr << "Saw message type MockCodeGenerator_Abort." << endl;
122d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        abort();
123d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      } else {
124d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
125d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      }
126d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    }
127d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  }
128d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
129d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  if (HasPrefixString(parameter, "insert=")) {
130d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    vector<string> insert_into;
131d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    SplitStringUsing(StripPrefixString(parameter, "insert="),
132d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                     ",", &insert_into);
133d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
134d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    for (int i = 0; i < insert_into.size(); i++) {
135d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      {
136d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        scoped_ptr<io::ZeroCopyOutputStream> output(
137d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville            output_directory->OpenForInsert(
138d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              GetOutputFileName(insert_into[i], file),
139d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              kFirstInsertionPointName));
140d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        io::Printer printer(output.get(), '$');
141d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        printer.PrintRaw(GetOutputFileContent(name_, "first_insert", file));
142d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        if (printer.failed()) {
143d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          *error = "MockCodeGenerator detected write error.";
144d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          return false;
145d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        }
146d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      }
147d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
148d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      {
149d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        scoped_ptr<io::ZeroCopyOutputStream> output(
150d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville            output_directory->OpenForInsert(
151d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              GetOutputFileName(insert_into[i], file),
152d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              kSecondInsertionPointName));
153d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        io::Printer printer(output.get(), '$');
154d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        printer.PrintRaw(GetOutputFileContent(name_, "second_insert", file));
155d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        if (printer.failed()) {
156d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          *error = "MockCodeGenerator detected write error.";
157d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          return false;
158d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        }
159d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      }
160d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    }
161d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  } else {
162d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    scoped_ptr<io::ZeroCopyOutputStream> output(
163d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        output_directory->Open(GetOutputFileName(name_, file)));
164d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
165d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    io::Printer printer(output.get(), '$');
166d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    printer.PrintRaw(GetOutputFileContent(name_, parameter, file));
167d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    printer.PrintRaw(kFirstInsertionPoint);
168d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    printer.PrintRaw(kSecondInsertionPoint);
169d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
170d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    if (printer.failed()) {
171d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      *error = "MockCodeGenerator detected write error.";
172d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      return false;
173d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    }
174d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  }
175d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
176d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  return true;
177d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}
178d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
179d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestring MockCodeGenerator::GetOutputFileName(const string& generator_name,
180d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                                            const FileDescriptor* file) {
181d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  return GetOutputFileName(generator_name, file->name());
182d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}
183d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
184d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestring MockCodeGenerator::GetOutputFileName(const string& generator_name,
185d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                                            const string& file) {
186d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  return file + ".MockCodeGenerator." + generator_name;
187d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}
188d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
189d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestring MockCodeGenerator::GetOutputFileContent(const string& generator_name,
190d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                                               const string& parameter,
191d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                                               const FileDescriptor* file) {
192d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  return GetOutputFileContent(
193d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      generator_name, parameter, file->name(),
194d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      file->message_type_count() > 0 ?
195d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          file->message_type(0)->name() : "(none)");
196d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}
197d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
198d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestring MockCodeGenerator::GetOutputFileContent(
199d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& generator_name,
200d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& parameter,
201d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& file,
202d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    const string& first_message_name) {
203d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  return strings::Substitute("$0: $1, $2, $3\n",
204d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      generator_name, parameter, file, first_message_name);
205d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}
206d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
207d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}  // namespace compiler
208d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}  // namespace protobuf
209d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}  // namespace google
210