mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-28 08:16:09 +03:00
176 lines
6.1 KiB
C++
176 lines
6.1 KiB
C++
// Copyright 2014 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "tools/gn/c_include_iterator.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "base/macros.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "tools/gn/input_file.h"
|
|
#include "tools/gn/location.h"
|
|
|
|
namespace {
|
|
|
|
enum IncludeType {
|
|
INCLUDE_NONE,
|
|
INCLUDE_SYSTEM, // #include <...>
|
|
INCLUDE_USER // #include "..."
|
|
};
|
|
|
|
// Returns a new string piece referencing the same buffer as the argument, but
|
|
// with leading space trimmed. This only checks for space and tab characters
|
|
// since we're dealing with lines in C source files.
|
|
base::StringPiece TrimLeadingWhitespace(const base::StringPiece& str) {
|
|
size_t new_begin = 0;
|
|
while (new_begin < str.size() &&
|
|
(str[new_begin] == ' ' || str[new_begin] == '\t'))
|
|
new_begin++;
|
|
return str.substr(new_begin);
|
|
}
|
|
|
|
// We don't want to count comment lines and preprocessor lines toward our
|
|
// "max lines to look at before giving up" since the beginnings of some files
|
|
// may have a lot of comments.
|
|
//
|
|
// We only handle C-style "//" comments since this is the normal commenting
|
|
// style used in Chrome, and do so pretty stupidly. We don't want to write a
|
|
// full C++ parser here, we're just trying to get a good heuristic for checking
|
|
// the file.
|
|
//
|
|
// We assume the line has leading whitespace trimmed. We also assume that empty
|
|
// lines have already been filtered out.
|
|
bool ShouldCountTowardNonIncludeLines(const base::StringPiece& line) {
|
|
if (base::StartsWith(line, "//", base::CompareCase::SENSITIVE))
|
|
return false; // Don't count comments.
|
|
if (base::StartsWith(line, "/*", base::CompareCase::SENSITIVE) ||
|
|
base::StartsWith(line, " *", base::CompareCase::SENSITIVE))
|
|
return false; // C-style comment blocks with stars along the left side.
|
|
if (base::StartsWith(line, "#", base::CompareCase::SENSITIVE))
|
|
return false; // Don't count preprocessor.
|
|
if (base::ContainsOnlyChars(line, base::kWhitespaceASCII))
|
|
return false; // Don't count whitespace lines.
|
|
return true; // Count everything else.
|
|
}
|
|
|
|
// Given a line, checks to see if it looks like an include or import and
|
|
// extract the path. The type of include is returned. Returns INCLUDE_NONE on
|
|
// error or if this is not an include line.
|
|
//
|
|
// The 1-based character number on the line that the include was found at
|
|
// will be filled into *begin_char.
|
|
IncludeType ExtractInclude(const base::StringPiece& line,
|
|
base::StringPiece* path,
|
|
int* begin_char) {
|
|
static const char kInclude[] = "#include";
|
|
static const size_t kIncludeLen = arraysize(kInclude) - 1; // No null.
|
|
static const char kImport[] = "#import";
|
|
static const size_t kImportLen = arraysize(kImport) - 1; // No null.
|
|
|
|
base::StringPiece trimmed = TrimLeadingWhitespace(line);
|
|
if (trimmed.empty())
|
|
return INCLUDE_NONE;
|
|
|
|
base::StringPiece contents;
|
|
if (base::StartsWith(trimmed, base::StringPiece(kInclude, kIncludeLen),
|
|
base::CompareCase::SENSITIVE))
|
|
contents = TrimLeadingWhitespace(trimmed.substr(kIncludeLen));
|
|
else if (base::StartsWith(trimmed, base::StringPiece(kImport, kImportLen),
|
|
base::CompareCase::SENSITIVE))
|
|
contents = TrimLeadingWhitespace(trimmed.substr(kImportLen));
|
|
|
|
if (contents.empty())
|
|
return INCLUDE_NONE;
|
|
|
|
IncludeType type = INCLUDE_NONE;
|
|
char terminating_char = 0;
|
|
if (contents[0] == '"') {
|
|
type = INCLUDE_USER;
|
|
terminating_char = '"';
|
|
} else if (contents[0] == '<') {
|
|
type = INCLUDE_SYSTEM;
|
|
terminating_char = '>';
|
|
} else {
|
|
return INCLUDE_NONE;
|
|
}
|
|
|
|
// Count everything to next "/> as the contents.
|
|
size_t terminator_index = contents.find(terminating_char, 1);
|
|
if (terminator_index == base::StringPiece::npos)
|
|
return INCLUDE_NONE;
|
|
|
|
*path = contents.substr(1, terminator_index - 1);
|
|
// Note: one based so we do "+ 1".
|
|
*begin_char = static_cast<int>(path->data() - line.data()) + 1;
|
|
return type;
|
|
}
|
|
|
|
// Returns true if this line has a "nogncheck" comment associated with it.
|
|
bool HasNoCheckAnnotation(const base::StringPiece& line) {
|
|
return line.find("nogncheck") != base::StringPiece::npos;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
const int CIncludeIterator::kMaxNonIncludeLines = 10;
|
|
|
|
CIncludeIterator::CIncludeIterator(const InputFile* input)
|
|
: input_file_(input),
|
|
file_(input->contents()),
|
|
offset_(0),
|
|
line_number_(0),
|
|
lines_since_last_include_(0) {
|
|
}
|
|
|
|
CIncludeIterator::~CIncludeIterator() = default;
|
|
|
|
bool CIncludeIterator::GetNextIncludeString(base::StringPiece* out,
|
|
LocationRange* location) {
|
|
base::StringPiece line;
|
|
int cur_line_number = 0;
|
|
while (lines_since_last_include_ <= kMaxNonIncludeLines &&
|
|
GetNextLine(&line, &cur_line_number)) {
|
|
base::StringPiece include_contents;
|
|
int begin_char;
|
|
IncludeType type = ExtractInclude(line, &include_contents, &begin_char);
|
|
if (type == INCLUDE_USER && !HasNoCheckAnnotation(line)) {
|
|
// Only count user includes for now.
|
|
*out = include_contents;
|
|
*location = LocationRange(
|
|
Location(input_file_,
|
|
cur_line_number,
|
|
begin_char,
|
|
-1 /* TODO(scottmg): Is this important? */),
|
|
Location(input_file_,
|
|
cur_line_number,
|
|
begin_char + static_cast<int>(include_contents.size()),
|
|
-1 /* TODO(scottmg): Is this important? */));
|
|
|
|
lines_since_last_include_ = 0;
|
|
return true;
|
|
}
|
|
|
|
if (ShouldCountTowardNonIncludeLines(line))
|
|
lines_since_last_include_++;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CIncludeIterator::GetNextLine(base::StringPiece* line, int* line_number) {
|
|
if (offset_ == file_.size())
|
|
return false;
|
|
|
|
size_t begin = offset_;
|
|
while (offset_ < file_.size() && file_[offset_] != '\n')
|
|
offset_++;
|
|
line_number_++;
|
|
|
|
*line = file_.substr(begin, offset_ - begin);
|
|
*line_number = line_number_;
|
|
|
|
// If we didn't hit EOF, skip past the newline for the next one.
|
|
if (offset_ < file_.size())
|
|
offset_++;
|
|
return true;
|
|
}
|