blob: a0454eddf1bc976a6cfd76312fdb8e0d07551d70 [file] [log] [blame]
// Copyright (c) 2020, 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 'package:analyzer/dart/ast/ast.dart';
import 'package:scrape/scrape.dart';
final quoteRegExp = RegExp('\\\\?[\'"]');
void main(List<String> arguments) {
Scrape()
..addHistogram('Directive')
..addHistogram('Expression')
..addHistogram('Escapes')
..addVisitor(() => StringVisitor())
..runCommandLine(arguments);
}
class StringVisitor extends ScrapeVisitor {
@override
void visitSimpleStringLiteral(SimpleStringLiteral node) {
_record('Expression', node);
_recordEscapes(node);
super.visitSimpleStringLiteral(node);
}
@override
void visitStringInterpolation(StringInterpolation node) {
// Entire expression containing interpolation elements.
_record('Expression', node);
// TODO: Analyze escaped quotes inside strings.
// TODO: Analyze string literals nested inside interpolation.
super.visitStringInterpolation(node);
}
@override
void visitExportDirective(ExportDirective node) {
_record('Directive', node.uri);
// Don't recurse so that we don't treat the URI as a string expression.
}
@override
void visitImportDirective(ImportDirective node) {
_record('Directive', node.uri);
// Don't recurse so that we don't treat the URI as a string expression.
}
@override
void visitPartDirective(PartDirective node) {
_record('Directive', node.uri);
// Don't recurse so that we don't treat the URI as a string expression.
}
@override
void visitPartOfDirective(PartOfDirective node) {
if (node.uri != null) _record('Directive', node.uri!);
// Don't recurse so that we don't treat the URI as a string expression.
}
void _record(String histogram, StringLiteral string) {
record(histogram, _quoteType(string.beginToken.lexeme));
}
void _recordEscapes(StringLiteral string) {
var quote = _quoteType(string.beginToken.lexeme);
// Ignore the rarer quote styles.
if (quote != "'" && quote != '"') return;
var contents = string.toSource();
contents = contents.substring(1, contents.length - 1);
var quotes = quoteRegExp
.allMatches(contents)
.map((match) => match[0])
.toSet()
.toList();
quotes.sort();
if (quotes.isNotEmpty) {
record('Escapes', '$quote containing ${quotes.join(" ")}');
}
}
String _quoteType(String lexeme) {
const types = ['"""', "'''", 'r"""', "r'''", '"', "'", 'r"', "r'"];
for (var type in types) {
if (lexeme.startsWith(type)) return type;
}
log('Unknown string quote in $lexeme');
return '';
}
}