Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
b33c7891
Unverified
Commit
b33c7891
authored
Apr 22, 2021
by
Greg Spencer
Committed by
GitHub
Apr 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix the sample analyzer to analyze dart:ui and make the analyzer null safe (#80742)
parent
a84ac2ec
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
215 additions
and
71 deletions
+215
-71
analyze_sample_code.dart
dev/bots/analyze_sample_code.dart
+141
-57
ui.dart
dev/bots/test/analyze-sample-code-test-dart-ui/ui.dart
+33
-0
analyze_sample_code_test.dart
dev/bots/test/analyze_sample_code_test.dart
+38
-13
snippets.dart
dev/snippets/lib/snippets.dart
+3
-1
No files found.
dev/bots/analyze_sample_code.dart
View file @
b33c7891
...
@@ -7,6 +7,8 @@
...
@@ -7,6 +7,8 @@
// To run this, from the root of the Flutter repository:
// To run this, from the root of the Flutter repository:
// bin/cache/dart-sdk/bin/dart dev/bots/analyze_sample_code.dart
// bin/cache/dart-sdk/bin/dart dev/bots/analyze_sample_code.dart
// @dart= 2.12
import
'dart:convert'
;
import
'dart:convert'
;
import
'dart:io'
;
import
'dart:io'
;
...
@@ -16,6 +18,7 @@ import 'package:watcher/watcher.dart';
...
@@ -16,6 +18,7 @@ import 'package:watcher/watcher.dart';
final
String
_flutterRoot
=
path
.
dirname
(
path
.
dirname
(
path
.
dirname
(
path
.
fromUri
(
Platform
.
script
))));
final
String
_flutterRoot
=
path
.
dirname
(
path
.
dirname
(
path
.
dirname
(
path
.
fromUri
(
Platform
.
script
))));
final
String
_defaultFlutterPackage
=
path
.
join
(
_flutterRoot
,
'packages'
,
'flutter'
,
'lib'
);
final
String
_defaultFlutterPackage
=
path
.
join
(
_flutterRoot
,
'packages'
,
'flutter'
,
'lib'
);
final
String
_defaultDartUiLocation
=
path
.
join
(
_flutterRoot
,
'bin'
,
'cache'
,
'pkg'
,
'sky_engine'
,
'lib'
,
'ui'
);
final
String
_flutter
=
path
.
join
(
_flutterRoot
,
'bin'
,
Platform
.
isWindows
?
'flutter.bat'
:
'flutter'
);
final
String
_flutter
=
path
.
join
(
_flutterRoot
,
'bin'
,
Platform
.
isWindows
?
'flutter.bat'
:
'flutter'
);
void
main
(
List
<
String
>
arguments
)
{
void
main
(
List
<
String
>
arguments
)
{
...
@@ -33,6 +36,20 @@ void main(List<String> arguments) {
...
@@ -33,6 +36,20 @@ void main(List<String> arguments) {
negatable:
false
,
negatable:
false
,
help:
'Print verbose output for the analysis process.'
,
help:
'Print verbose output for the analysis process.'
,
);
);
argParser
.
addOption
(
'dart-ui-location'
,
defaultsTo:
_defaultDartUiLocation
,
help:
'A location where the dart:ui dart files are to be found. Defaults to '
'the sky_engine directory installed in this flutter repo. This '
'is typically the engine/src/flutter/lib/ui directory in an engine dev setup. '
'Implies --include-dart-ui.'
,
);
argParser
.
addFlag
(
'include-dart-ui'
,
defaultsTo:
true
,
negatable:
true
,
help:
'Includes the dart:ui code supplied by the engine in the analysis.'
,
);
argParser
.
addFlag
(
argParser
.
addFlag
(
'help'
,
'help'
,
defaultsTo:
false
,
defaultsTo:
false
,
...
@@ -61,7 +78,20 @@ void main(List<String> arguments) {
...
@@ -61,7 +78,20 @@ void main(List<String> arguments) {
flutterPackage
=
Directory
(
_defaultFlutterPackage
);
flutterPackage
=
Directory
(
_defaultFlutterPackage
);
}
}
Directory
tempDirectory
;
final
bool
includeDartUi
=
parsedArguments
.
wasParsed
(
'dart-ui-location'
)
||
parsedArguments
[
'include-dart-ui'
]
as
bool
;
late
Directory
dartUiLocation
;
if
(((
parsedArguments
[
'dart-ui-location'
]
??
''
)
as
String
).
isNotEmpty
)
{
dartUiLocation
=
Directory
(
path
.
absolute
(
parsedArguments
[
'dart-ui-location'
]
as
String
));
}
else
{
dartUiLocation
=
Directory
(
_defaultDartUiLocation
);
}
if
(!
dartUiLocation
.
existsSync
())
{
stderr
.
writeln
(
'Unable to find dart:ui directory
${dartUiLocation.path}
'
);
exit
(-
1
);
}
Directory
?
tempDirectory
;
if
(
parsedArguments
.
wasParsed
(
'temp'
))
{
if
(
parsedArguments
.
wasParsed
(
'temp'
))
{
final
String
tempArg
=
parsedArguments
[
'temp'
]
as
String
;
final
String
tempArg
=
parsedArguments
[
'temp'
]
as
String
;
tempDirectory
=
Directory
(
path
.
join
(
Directory
.
systemTemp
.
absolute
.
path
,
path
.
basename
(
tempArg
)));
tempDirectory
=
Directory
(
path
.
join
(
Directory
.
systemTemp
.
absolute
.
path
,
path
.
basename
(
tempArg
)));
...
@@ -78,13 +108,19 @@ void main(List<String> arguments) {
...
@@ -78,13 +108,19 @@ void main(List<String> arguments) {
}
}
if
(
parsedArguments
[
'interactive'
]
!=
null
)
{
if
(
parsedArguments
[
'interactive'
]
!=
null
)
{
_runInteractive
(
tempDirectory
,
flutterPackage
,
parsedArguments
[
'interactive'
]
as
String
);
_runInteractive
(
tempDir:
tempDirectory
,
flutterPackage:
flutterPackage
,
filePath:
parsedArguments
[
'interactive'
]
as
String
,
dartUiLocation:
includeDartUi
?
dartUiLocation
:
null
,
);
}
else
{
}
else
{
try
{
try
{
exitCode
=
SampleChecker
(
exitCode
=
SampleChecker
(
flutterPackage
,
flutterPackage
,
tempDirectory:
tempDirectory
,
tempDirectory:
tempDirectory
,
verbose:
parsedArguments
[
'verbose'
]
as
bool
,
verbose:
parsedArguments
[
'verbose'
]
as
bool
,
dartUiLocation:
includeDartUi
?
dartUiLocation
:
null
,
).
checkSamples
();
).
checkSamples
();
}
on
SampleCheckerException
catch
(
e
)
{
}
on
SampleCheckerException
catch
(
e
)
{
stderr
.
write
(
e
);
stderr
.
write
(
e
);
...
@@ -96,8 +132,8 @@ void main(List<String> arguments) {
...
@@ -96,8 +132,8 @@ void main(List<String> arguments) {
class
SampleCheckerException
implements
Exception
{
class
SampleCheckerException
implements
Exception
{
SampleCheckerException
(
this
.
message
,
{
this
.
file
,
this
.
line
});
SampleCheckerException
(
this
.
message
,
{
this
.
file
,
this
.
line
});
final
String
message
;
final
String
message
;
final
String
file
;
final
String
?
file
;
final
int
line
;
final
int
?
line
;
@override
@override
String
toString
()
{
String
toString
()
{
...
@@ -126,11 +162,30 @@ class SampleCheckerException implements Exception {
...
@@ -126,11 +162,30 @@ class SampleCheckerException implements Exception {
/// don't necessarily match. It does, however, print the source of the
/// don't necessarily match. It does, however, print the source of the
/// problematic line.
/// problematic line.
class
SampleChecker
{
class
SampleChecker
{
SampleChecker
(
this
.
_flutterPackage
,
{
Directory
tempDirectory
,
this
.
verbose
=
false
})
/// Creates a [SampleChecker].
:
_tempDirectory
=
tempDirectory
,
///
_keepTmp
=
tempDirectory
!=
null
{
/// The positional argument is the path to the the package directory for the
_tempDirectory
??=
Directory
.
systemTemp
.
createTempSync
(
'flutter_analyze_sample_code.'
);
/// flutter package within the Flutter root dir.
}
///
/// The optional `tempDirectory` argument supplies the location for the
/// temporary files to be written and analyzed. If not supplied, it defaults
/// to a system generated temp directory.
///
/// The optional `verbose` argument indicates whether or not status output
/// should be emitted while doing the check.
///
/// The optional `dartUiLocation` argument indicates the location of the
/// `dart:ui` code to be analyzed along with the framework code. If not
/// supplied, the default location of the `dart:ui` code in the Flutter
/// repository is used (i.e. "<flutter repo>/bin/cache/pkg/sky_engine/lib/ui").
SampleChecker
(
this
.
_flutterPackage
,
{
Directory
?
tempDirectory
,
this
.
verbose
=
false
,
Directory
?
dartUiLocation
,
})
:
_tempDirectory
=
tempDirectory
??
Directory
.
systemTemp
.
createTempSync
(
'flutter_analyze_sample_code.'
),
_keepTmp
=
tempDirectory
!=
null
,
_dartUiLocation
=
dartUiLocation
;
/// The prefix of each comment line
/// The prefix of each comment line
static
const
String
_dartDocPrefix
=
'///'
;
static
const
String
_dartDocPrefix
=
'///'
;
...
@@ -166,11 +221,18 @@ class SampleChecker {
...
@@ -166,11 +221,18 @@ class SampleChecker {
/// The temporary directory where all output is written. This will be deleted
/// The temporary directory where all output is written. This will be deleted
/// automatically if there are no errors.
/// automatically if there are no errors.
Directory
_tempDirectory
;
final
Directory
_tempDirectory
;
/// The package directory for the flutter package within the flutter root dir.
/// The package directory for the flutter package within the flutter root dir.
final
Directory
_flutterPackage
;
final
Directory
_flutterPackage
;
/// The directory for the dart:ui code to be analyzed with the flutter code.
///
/// If this is null, then no dart:ui code is included in the analysis. It
/// defaults to the location inside of the flutter bin/cache directory that
/// contains the dart:ui code supplied by the engine.
final
Directory
?
_dartUiLocation
;
/// A serial number so that we can create unique expression names when we
/// A serial number so that we can create unique expression names when we
/// generate them.
/// generate them.
int
_expressionId
=
0
;
int
_expressionId
=
0
;
...
@@ -180,7 +242,7 @@ class SampleChecker {
...
@@ -180,7 +242,7 @@ class SampleChecker {
// Once the snippets tool has been precompiled by Dart, this contains the AOT
// Once the snippets tool has been precompiled by Dart, this contains the AOT
// snapshot.
// snapshot.
String
_snippetsSnapshotPath
;
String
?
_snippetsSnapshotPath
;
/// Finds the location of the snippets script.
/// Finds the location of the snippets script.
String
get
_snippetsExecutable
{
String
get
_snippetsExecutable
{
...
@@ -219,7 +281,7 @@ class SampleChecker {
...
@@ -219,7 +281,7 @@ class SampleChecker {
].
map
<
Line
>((
String
code
)
=>
Line
(
code
)).
toList
();
].
map
<
Line
>((
String
code
)
=>
Line
(
code
)).
toList
();
}
}
List
<
Line
>
_headers
;
List
<
Line
>
?
_headers
;
/// Checks all the samples in the Dart files in [_flutterPackage] for errors.
/// Checks all the samples in the Dart files in [_flutterPackage] for errors.
int
checkSamples
()
{
int
checkSamples
()
{
...
@@ -228,12 +290,19 @@ class SampleChecker {
...
@@ -228,12 +290,19 @@ class SampleChecker {
try
{
try
{
final
Map
<
String
,
Section
>
sections
=
<
String
,
Section
>{};
final
Map
<
String
,
Section
>
sections
=
<
String
,
Section
>{};
final
Map
<
String
,
Sample
>
snippets
=
<
String
,
Sample
>{};
final
Map
<
String
,
Sample
>
snippets
=
<
String
,
Sample
>{};
_extractSamples
(
_listDartFiles
(
_flutterPackage
,
recursive:
true
),
sectionMap:
sections
,
sampleMap:
snippets
);
if
(
_dartUiLocation
!=
null
&&
!
_dartUiLocation
!.
existsSync
())
{
stderr
.
writeln
(
'Unable to analyze engine dart samples at
${_dartUiLocation!.path}
.'
);
}
final
List
<
File
>
filesToAnalyze
=
<
File
>[
...
_listDartFiles
(
_flutterPackage
,
recursive:
true
),
if
(
_dartUiLocation
!=
null
&&
_dartUiLocation
!.
existsSync
())
...
_listDartFiles
(
_dartUiLocation
!,
recursive:
true
),
];
_extractSamples
(
filesToAnalyze
,
sectionMap:
sections
,
sampleMap:
snippets
);
errors
=
_analyze
(
_tempDirectory
,
sections
,
snippets
);
errors
=
_analyze
(
_tempDirectory
,
sections
,
snippets
);
}
finally
{
}
finally
{
if
(
errors
.
isNotEmpty
)
{
if
(
errors
.
isNotEmpty
)
{
for
(
final
String
filePath
in
errors
.
keys
)
{
for
(
final
String
filePath
in
errors
.
keys
)
{
errors
[
filePath
].
forEach
(
stderr
.
writeln
);
errors
[
filePath
]
!
.
forEach
(
stderr
.
writeln
);
}
}
stderr
.
writeln
(
'
\n
Found
${errors.length}
sample code errors.'
);
stderr
.
writeln
(
'
\n
Found
${errors.length}
sample code errors.'
);
}
}
...
@@ -248,7 +317,7 @@ class SampleChecker {
...
@@ -248,7 +317,7 @@ class SampleChecker {
}
}
// If we made a snapshot, remove it (so as not to clutter up the tree).
// If we made a snapshot, remove it (so as not to clutter up the tree).
if
(
_snippetsSnapshotPath
!=
null
)
{
if
(
_snippetsSnapshotPath
!=
null
)
{
final
File
snapshot
=
File
(
_snippetsSnapshotPath
);
final
File
snapshot
=
File
(
_snippetsSnapshotPath
!
);
if
(
snapshot
.
existsSync
())
{
if
(
snapshot
.
existsSync
())
{
snapshot
.
deleteSync
();
snapshot
.
deleteSync
();
}
}
...
@@ -285,7 +354,7 @@ class SampleChecker {
...
@@ -285,7 +354,7 @@ class SampleChecker {
}
else
{
}
else
{
return
Process
.
runSync
(
return
Process
.
runSync
(
_dartExecutable
,
_dartExecutable
,
<
String
>[
path
.
canonicalize
(
_snippetsSnapshotPath
),
...
args
],
<
String
>[
path
.
canonicalize
(
_snippetsSnapshotPath
!
),
...
args
],
workingDirectory:
workingDirectory
,
workingDirectory:
workingDirectory
,
);
);
}
}
...
@@ -307,7 +376,7 @@ class SampleChecker {
...
@@ -307,7 +376,7 @@ class SampleChecker {
...
sample
.
args
,
...
sample
.
args
,
];
];
if
(
verbose
)
if
(
verbose
)
print
(
'Generating sample for
${sample.start
?.filename}
:
${sample.start?
.line}
'
);
print
(
'Generating sample for
${sample.start
.filename}
:
${sample.start
.line}
'
);
final
ProcessResult
process
=
_runSnippetsScript
(
args
);
final
ProcessResult
process
=
_runSnippetsScript
(
args
);
if
(
verbose
)
if
(
verbose
)
stderr
.
write
(
'
${process.stderr}
'
);
stderr
.
write
(
'
${process.stderr}
'
);
...
@@ -324,14 +393,19 @@ class SampleChecker {
...
@@ -324,14 +393,19 @@ class SampleChecker {
/// Extracts the samples from the Dart files in [files], writes them
/// Extracts the samples from the Dart files in [files], writes them
/// to disk, and adds them to the appropriate [sectionMap] or [sampleMap].
/// to disk, and adds them to the appropriate [sectionMap] or [sampleMap].
void
_extractSamples
(
List
<
File
>
files
,
{
Map
<
String
,
Section
>
sectionMap
,
Map
<
String
,
Sample
>
sampleMap
,
bool
silent
=
false
})
{
void
_extractSamples
(
List
<
File
>
files
,
{
required
Map
<
String
,
Section
>
sectionMap
,
required
Map
<
String
,
Sample
>
sampleMap
,
bool
silent
=
false
,
})
{
final
List
<
Section
>
sections
=
<
Section
>[];
final
List
<
Section
>
sections
=
<
Section
>[];
final
List
<
Sample
>
samples
=
<
Sample
>[];
final
List
<
Sample
>
samples
=
<
Sample
>[];
int
dartpadCount
=
0
;
int
dartpadCount
=
0
;
int
sampleCount
=
0
;
int
sampleCount
=
0
;
for
(
final
File
file
in
files
)
{
for
(
final
File
file
in
files
)
{
final
String
relativeFilePath
=
path
.
relative
(
file
.
path
,
from:
_flutter
Package
.
path
);
final
String
relativeFilePath
=
path
.
relative
(
file
.
path
,
from:
_flutter
Root
);
final
List
<
String
>
sampleLines
=
file
.
readAsLinesSync
();
final
List
<
String
>
sampleLines
=
file
.
readAsLinesSync
();
final
List
<
Section
>
preambleSections
=
<
Section
>[];
final
List
<
Section
>
preambleSections
=
<
Section
>[];
// Whether or not we're in the file-wide preamble section ("Examples can assume").
// Whether or not we're in the file-wide preamble section ("Examples can assume").
...
@@ -342,11 +416,11 @@ class SampleChecker {
...
@@ -342,11 +416,11 @@ class SampleChecker {
bool
inSnippet
=
false
;
bool
inSnippet
=
false
;
// Whether or not we're in a '```dart' segment.
// Whether or not we're in a '```dart' segment.
bool
inDart
=
false
;
bool
inDart
=
false
;
String
dartVersionOverride
;
String
?
dartVersionOverride
;
int
lineNumber
=
0
;
int
lineNumber
=
0
;
final
List
<
String
>
block
=
<
String
>[];
final
List
<
String
>
block
=
<
String
>[];
List
<
String
>
snippetArgs
=
<
String
>[];
List
<
String
>
snippetArgs
=
<
String
>[];
Line
startLine
;
late
Line
startLine
;
for
(
final
String
line
in
sampleLines
)
{
for
(
final
String
line
in
sampleLines
)
{
lineNumber
+=
1
;
lineNumber
+=
1
;
final
String
trimmedLine
=
line
.
trim
();
final
String
trimmedLine
=
line
.
trim
();
...
@@ -425,7 +499,7 @@ class SampleChecker {
...
@@ -425,7 +499,7 @@ class SampleChecker {
}
}
}
}
if
(!
inSampleSection
)
{
if
(!
inSampleSection
)
{
final
Match
sampleMatch
=
_dartDocSampleBeginRegex
.
firstMatch
(
trimmedLine
);
final
RegExpMatch
?
sampleMatch
=
_dartDocSampleBeginRegex
.
firstMatch
(
trimmedLine
);
if
(
line
==
'// Examples can assume:'
)
{
if
(
line
==
'// Examples can assume:'
)
{
assert
(
block
.
isEmpty
);
assert
(
block
.
isEmpty
);
startLine
=
Line
(
''
,
filename:
relativeFilePath
,
line:
lineNumber
+
1
,
indent:
3
);
startLine
=
Line
(
''
,
filename:
relativeFilePath
,
line:
lineNumber
+
1
,
indent:
3
);
...
@@ -447,7 +521,7 @@ class SampleChecker {
...
@@ -447,7 +521,7 @@ class SampleChecker {
);
);
if
(
sampleMatch
[
2
]
!=
null
)
{
if
(
sampleMatch
[
2
]
!=
null
)
{
// There are arguments to the snippet tool to keep track of.
// There are arguments to the snippet tool to keep track of.
snippetArgs
=
_splitUpQuotedArgs
(
sampleMatch
[
2
]).
toList
();
snippetArgs
=
_splitUpQuotedArgs
(
sampleMatch
[
2
]
!
).
toList
();
}
else
{
}
else
{
snippetArgs
=
<
String
>[];
snippetArgs
=
<
String
>[];
}
}
...
@@ -507,7 +581,7 @@ class SampleChecker {
...
@@ -507,7 +581,7 @@ class SampleChecker {
// by an equals sign), add a "--" in front so that they parse as options.
// by an equals sign), add a "--" in front so that they parse as options.
return matches.map<String>((Match match) {
return matches.map<String>((Match match) {
String option = '';
String option = '';
if (match[1] != null && !match[1].startsWith('
-
')) {
if (match[1] != null && !match[1]
!
.startsWith('
-
')) {
option = '
--
';
option = '
--
';
}
}
if (match[2] != null) {
if (match[2] != null) {
...
@@ -543,7 +617,7 @@ dependencies:
...
@@ -543,7 +617,7 @@ dependencies:
final String sectionId = _createNameFromSource('
snippet
', section.start.filename, section.start.line);
final String sectionId = _createNameFromSource('
snippet
', section.start.filename, section.start.line);
final File outputFile = File(path.join(_tempDirectory.path, '
$sectionId
.
dart
'))..createSync(recursive: true);
final File outputFile = File(path.join(_tempDirectory.path, '
$sectionId
.
dart
'))..createSync(recursive: true);
final List<Line> mainContents = <Line>[
final List<Line> mainContents = <Line>[
if (section.dartVersionOverride != null) Line(section.dartVersionOverride) else const Line(''),
if (section.dartVersionOverride != null) Line(section.dartVersionOverride
!
) else const Line(''),
...headers,
...headers,
const Line(''),
const Line(''),
Line('
// From: ${section.start.filename}:${section.start.line}'),
Line('
// From: ${section.start.filename}:${section.start.line}'),
...
@@ -554,7 +628,7 @@ dependencies:
...
@@ -554,7 +628,7 @@ dependencies:
}
}
/// Invokes the analyzer on the given [directory] and returns the stdout.
/// Invokes the analyzer on the given [directory] and returns the stdout.
List
<
String
>
_runAnalyzer
(
Directory
directory
,
{
bool
silent
})
{
List
<
String
>
_runAnalyzer
(
Directory
directory
,
{
bool
silent
=
true
})
{
if
(!
silent
)
if
(!
silent
)
print
(
'Starting analysis of code samples.'
);
print
(
'Starting analysis of code samples.'
);
_createConfigurationFiles
(
directory
);
_createConfigurationFiles
(
directory
);
...
@@ -603,7 +677,7 @@ dependencies:
...
@@ -603,7 +677,7 @@ dependencies:
final
Map
<
String
,
List
<
AnalysisError
>>
analysisErrors
=
<
String
,
List
<
AnalysisError
>>{};
final
Map
<
String
,
List
<
AnalysisError
>>
analysisErrors
=
<
String
,
List
<
AnalysisError
>>{};
void
addAnalysisError
(
File
file
,
AnalysisError
error
)
{
void
addAnalysisError
(
File
file
,
AnalysisError
error
)
{
if
(
analysisErrors
.
containsKey
(
file
.
path
))
{
if
(
analysisErrors
.
containsKey
(
file
.
path
))
{
analysisErrors
[
file
.
path
].
add
(
error
);
analysisErrors
[
file
.
path
]
!
.
add
(
error
);
}
else
{
}
else
{
analysisErrors
[
file
.
path
]
=
<
AnalysisError
>[
error
];
analysisErrors
[
file
.
path
]
=
<
AnalysisError
>[
error
];
}
}
...
@@ -621,21 +695,21 @@ dependencies:
...
@@ -621,21 +695,21 @@ dependencies:
bool
unknownAnalyzerErrors
=
false
;
bool
unknownAnalyzerErrors
=
false
;
final
int
headerLength
=
headers
.
length
+
3
;
final
int
headerLength
=
headers
.
length
+
3
;
for
(
final
String
error
in
errors
)
{
for
(
final
String
error
in
errors
)
{
final
RegExpMatch
match
=
errorPattern
.
firstMatch
(
error
);
final
RegExpMatch
?
match
=
errorPattern
.
firstMatch
(
error
);
if
(
match
==
null
)
{
if
(
match
==
null
)
{
stderr
.
writeln
(
'Analyzer output:
$error
'
);
stderr
.
writeln
(
'Analyzer output:
$error
'
);
unknownAnalyzerErrors
=
true
;
unknownAnalyzerErrors
=
true
;
continue
;
continue
;
}
}
final
String
type
=
match
.
namedGroup
(
'type'
);
final
String
type
=
match
.
namedGroup
(
'type'
)
!
;
final
String
message
=
match
.
namedGroup
(
'description'
);
final
String
message
=
match
.
namedGroup
(
'description'
)
!
;
final
File
file
=
File
(
path
.
join
(
_tempDirectory
.
path
,
match
.
namedGroup
(
'file'
)));
final
File
file
=
File
(
path
.
join
(
_tempDirectory
.
path
,
match
.
namedGroup
(
'file'
)));
final
List
<
String
>
fileContents
=
file
.
readAsLinesSync
();
final
List
<
String
>
fileContents
=
file
.
readAsLinesSync
();
final
bool
isSnippet
=
path
.
basename
(
file
.
path
).
startsWith
(
'snippet.'
);
final
bool
isSnippet
=
path
.
basename
(
file
.
path
).
startsWith
(
'snippet.'
);
final
bool
isSample
=
path
.
basename
(
file
.
path
).
startsWith
(
'sample.'
);
final
bool
isSample
=
path
.
basename
(
file
.
path
).
startsWith
(
'sample.'
);
final
String
line
=
match
.
namedGroup
(
'line'
);
final
String
line
=
match
.
namedGroup
(
'line'
)
!
;
final
String
column
=
match
.
namedGroup
(
'column'
);
final
String
column
=
match
.
namedGroup
(
'column'
)
!
;
final
String
errorCode
=
match
.
namedGroup
(
'code'
);
final
String
errorCode
=
match
.
namedGroup
(
'code'
)
!
;
final
int
lineNumber
=
int
.
parse
(
line
,
radix:
10
)
-
(
isSnippet
?
headerLength
:
0
);
final
int
lineNumber
=
int
.
parse
(
line
,
radix:
10
)
-
(
isSnippet
?
headerLength
:
0
);
final
int
columnNumber
=
int
.
parse
(
column
,
radix:
10
);
final
int
columnNumber
=
int
.
parse
(
column
,
radix:
10
);
...
@@ -692,7 +766,7 @@ dependencies:
...
@@ -692,7 +766,7 @@ dependencies:
throw
SampleCheckerException
(
'Failed to parse error message:
$error
'
,
file:
file
.
path
,
line:
lineNumber
);
throw
SampleCheckerException
(
'Failed to parse error message:
$error
'
,
file:
file
.
path
,
line:
lineNumber
);
}
}
final
Section
actualSection
=
sections
[
file
.
path
];
final
Section
actualSection
=
sections
[
file
.
path
]
!
;
if
(
actualSection
==
null
)
{
if
(
actualSection
==
null
)
{
throw
SampleCheckerException
(
throw
SampleCheckerException
(
"Unknown section for
${file.path}
. Maybe the temporary directory wasn't empty?"
,
"Unknown section for
${file.path}
. Maybe the temporary directory wasn't empty?"
,
...
@@ -702,10 +776,10 @@ dependencies:
...
@@ -702,10 +776,10 @@ dependencies:
}
}
final
Line
actualLine
=
actualSection
.
code
[
lineNumber
-
1
];
final
Line
actualLine
=
actualSection
.
code
[
lineNumber
-
1
];
if
(
actualLine
?
.
filename
==
null
)
{
if
(
actualLine
.
filename
==
null
)
{
if
(
errorCode
==
'missing_identifier'
&&
lineNumber
>
1
)
{
if
(
errorCode
==
'missing_identifier'
&&
lineNumber
>
1
)
{
if
(
fileContents
[
lineNumber
-
2
].
endsWith
(
','
))
{
if
(
fileContents
[
lineNumber
-
2
].
endsWith
(
','
))
{
final
Line
actualLine
=
sections
[
file
.
path
].
code
[
lineNumber
-
2
];
final
Line
actualLine
=
sections
[
file
.
path
]
!
.
code
[
lineNumber
-
2
];
addAnalysisError
(
addAnalysisError
(
file
,
file
,
AnalysisError
(
AnalysisError
(
...
@@ -779,7 +853,7 @@ dependencies:
...
@@ -779,7 +853,7 @@ dependencies:
}
else
{
}
else
{
final
List
<
String
>
buffer
=
<
String
>[];
final
List
<
String
>
buffer
=
<
String
>[];
int
subblocks
=
0
;
int
subblocks
=
0
;
Line
subline
;
Line
?
subline
;
final
List
<
Section
>
subsections
=
<
Section
>[];
final
List
<
Section
>
subsections
=
<
Section
>[];
for
(
int
index
=
0
;
index
<
block
.
length
;
index
+=
1
)
{
for
(
int
index
=
0
;
index
<
block
.
length
;
index
+=
1
)
{
// Each section of the dart code that is either split by a blank line, or with '// ...' is
// Each section of the dart code that is either split by a blank line, or with '// ...' is
...
@@ -821,7 +895,7 @@ dependencies:
...
@@ -821,7 +895,7 @@ dependencies:
/// A class to represent a line of input code.
/// A class to represent a line of input code.
class
Line
{
class
Line
{
const
Line
(
this
.
code
,
{
this
.
filename
,
this
.
line
,
this
.
indent
});
const
Line
(
this
.
code
,
{
this
.
filename
=
'unknown'
,
this
.
line
=
-
1
,
this
.
indent
=
0
});
final
String
filename
;
final
String
filename
;
final
int
line
;
final
int
line
;
final
int
indent
;
final
int
indent
;
...
@@ -883,10 +957,10 @@ class Section {
...
@@ -883,10 +957,10 @@ class Section {
}
}
Line
get
start
=>
code
.
firstWhere
((
Line
line
)
=>
line
.
filename
!=
null
);
Line
get
start
=>
code
.
firstWhere
((
Line
line
)
=>
line
.
filename
!=
null
);
final
List
<
Line
>
code
;
final
List
<
Line
>
code
;
final
String
dartVersionOverride
;
final
String
?
dartVersionOverride
;
Section
copyWith
({
String
dartVersionOverride
})
{
Section
copyWith
({
String
?
dartVersionOverride
})
{
return
Section
(
code
,
dartVersionOverride:
dartVersionOverride
);
return
Section
(
code
,
dartVersionOverride:
dartVersionOverride
??
this
.
dartVersionOverride
);
}
}
}
}
...
@@ -895,10 +969,14 @@ class Section {
...
@@ -895,10 +969,14 @@ class Section {
/// regular snippets, because they must be injected into templates in order to be
/// regular snippets, because they must be injected into templates in order to be
/// analyzed.
/// analyzed.
class
Sample
{
class
Sample
{
Sample
({
this
.
start
,
List
<
String
>
input
,
List
<
String
>
args
,
this
.
serial
})
{
Sample
({
this
.
input
=
input
.
toList
();
required
this
.
start
,
this
.
args
=
args
.
toList
();
required
List
<
String
>
input
,
}
required
List
<
String
>
args
,
required
this
.
serial
,
})
:
input
=
input
.
toList
(),
args
=
args
.
toList
(),
contents
=
<
String
>[];
final
Line
start
;
final
Line
start
;
final
int
serial
;
final
int
serial
;
List
<
String
>
input
;
List
<
String
>
input
;
...
@@ -936,16 +1014,16 @@ class AnalysisError {
...
@@ -936,16 +1014,16 @@ class AnalysisError {
final
int
column
;
final
int
column
;
final
String
message
;
final
String
message
;
final
String
errorCode
;
final
String
errorCode
;
final
Line
source
;
final
Line
?
source
;
final
Sample
sample
;
final
Sample
?
sample
;
@override
@override
String
toString
()
{
String
toString
()
{
if
(
source
!=
null
)
{
if
(
source
!=
null
)
{
return
'
${source.toStringWithColumn(column)}
\n
>>>
$type
:
$message
(
$errorCode
)'
;
return
'
${source
!
.toStringWithColumn(column)}
\n
>>>
$type
:
$message
(
$errorCode
)'
;
}
else
if
(
sample
!=
null
)
{
}
else
if
(
sample
!=
null
)
{
return
'In sample starting at '
return
'In sample starting at '
'
${sample
.start.filename}
:
${sample.start.line}
:
${sample
.contents[line - 1]}
\n
'
'
${sample
!.start.filename}
:
${sample!.start.line}
:
${sample!
.contents[line - 1]}
\n
'
'>>>
$type
:
$message
(
$errorCode
)'
;
'>>>
$type
:
$message
(
$errorCode
)'
;
}
else
{
}
else
{
return
'<source unknown>:
$line
:
$column
\n
>>>
$type
:
$message
(
$errorCode
)'
;
return
'<source unknown>:
$line
:
$column
\n
>>>
$type
:
$message
(
$errorCode
)'
;
...
@@ -953,21 +1031,28 @@ class AnalysisError {
...
@@ -953,21 +1031,28 @@ class AnalysisError {
}
}
}
}
Future
<
void
>
_runInteractive
(
Directory
tempDir
,
Directory
flutterPackage
,
String
filePath
)
async
{
Future
<
void
>
_runInteractive
({
required
Directory
?
tempDir
,
required
Directory
flutterPackage
,
required
String
filePath
,
required
Directory
?
dartUiLocation
,
})
async
{
filePath
=
path
.
isAbsolute
(
filePath
)
?
filePath
:
path
.
join
(
path
.
current
,
filePath
);
filePath
=
path
.
isAbsolute
(
filePath
)
?
filePath
:
path
.
join
(
path
.
current
,
filePath
);
final
File
file
=
File
(
filePath
);
final
File
file
=
File
(
filePath
);
if
(!
file
.
existsSync
())
{
if
(!
file
.
existsSync
())
{
throw
'Path
${file.absolute.path}
does not exist.'
;
throw
'Path
${file.absolute.path}
does not exist
(
$filePath
)
.'
;
}
}
if
(!
path
.
isWithin
(
_flutterRoot
,
file
.
absolute
.
path
))
{
if
(!
path
.
isWithin
(
_flutterRoot
,
file
.
absolute
.
path
)
&&
throw
'Path
${file.absolute.path}
is not within the flutter root:
$_flutterRoot
'
;
(
dartUiLocation
==
null
||
!
path
.
isWithin
(
dartUiLocation
.
path
,
file
.
absolute
.
path
)))
{
throw
'Path
${file.absolute.path}
is not within the flutter root: '
'
$_flutterRoot${dartUiLocation != null ? ' or the dart:ui location: $dartUiLocation' : ''}
'
;
}
}
if
(
tempDir
==
null
)
{
if
(
tempDir
==
null
)
{
tempDir
=
Directory
.
systemTemp
.
createTempSync
(
'flutter_analyze_sample_code.'
);
tempDir
=
Directory
.
systemTemp
.
createTempSync
(
'flutter_analyze_sample_code.'
);
ProcessSignal
.
sigint
.
watch
().
listen
((
_
)
{
ProcessSignal
.
sigint
.
watch
().
listen
((
_
)
{
print
(
'Deleting temp files...'
);
print
(
'Deleting temp files...'
);
tempDir
.
deleteSync
(
recursive:
true
);
tempDir
!
.
deleteSync
(
recursive:
true
);
exit
(
0
);
exit
(
0
);
});
});
print
(
'Using temp dir
${tempDir.path}
'
);
print
(
'Using temp dir
${tempDir.path}
'
);
...
@@ -982,7 +1067,7 @@ Future<void> _runInteractive(Directory tempDir, Directory flutterPackage, String
...
@@ -982,7 +1067,7 @@ Future<void> _runInteractive(Directory tempDir, Directory flutterPackage, String
stderr
.
writeln
(
'
\
u001B[2J
\
u001B[H'
);
// Clears the old results from the terminal.
stderr
.
writeln
(
'
\
u001B[2J
\
u001B[H'
);
// Clears the old results from the terminal.
if
(
errors
.
isNotEmpty
)
{
if
(
errors
.
isNotEmpty
)
{
for
(
final
String
filePath
in
errors
.
keys
)
{
for
(
final
String
filePath
in
errors
.
keys
)
{
errors
[
filePath
].
forEach
(
stderr
.
writeln
);
errors
[
filePath
]
!
.
forEach
(
stderr
.
writeln
);
}
}
stderr
.
writeln
(
'
\n
Found
${errors.length}
errors.'
);
stderr
.
writeln
(
'
\n
Found
${errors.length}
errors.'
);
}
else
{
}
else
{
...
@@ -1012,10 +1097,9 @@ Future<void> _runInteractive(Directory tempDir, Directory flutterPackage, String
...
@@ -1012,10 +1097,9 @@ Future<void> _runInteractive(Directory tempDir, Directory flutterPackage, String
case
'q'
:
case
'q'
:
print
(
'Exiting...'
);
print
(
'Exiting...'
);
exit
(
0
);
exit
(
0
);
break
;
case
'r'
:
case
'r'
:
print
(
'Deleting temp files...'
);
print
(
'Deleting temp files...'
);
tempDir
.
deleteSync
(
recursive:
true
);
tempDir
!
.
deleteSync
(
recursive:
true
);
rerun
();
rerun
();
break
;
break
;
}
}
...
...
dev/bots/test/analyze-sample-code-test-dart-ui/ui.dart
0 → 100644
View file @
b33c7891
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.12
// This is a dummy dart:ui package for the sample code analyzer tests to use.
library
dart
.
ui
;
/// Annotation used by Flutter's Dart compiler to indicate that an
/// [Object.toString] override should not be replaced with a supercall.
///
/// {@tool sample}
/// A sample if using keepToString to prevent replacement by a supercall.
///
/// ```dart
/// class MyStringBuffer {
/// StringBuffer _buffer = StringBuffer();
///
/// @keepToString
/// @override
/// String toString() {
/// return _buffer.toString();
/// }
/// }
/// ```
/// {@end-tool}
const
_KeepToString
keepToString
=
_KeepToString
();
class
_KeepToString
{
const
_KeepToString
();
}
\ No newline at end of file
dev/bots/test/analyze_sample_code_test.dart
View file @
b33c7891
...
@@ -7,35 +7,42 @@ import 'dart:io';
...
@@ -7,35 +7,42 @@ import 'dart:io';
import
'common.dart'
;
import
'common.dart'
;
void
main
(
)
{
void
main
(
)
{
test
(
'analyze_sample_code'
,
()
{
// These tests don't run on Windows because the sample analyzer doesn't
// support Windows as a platform, since it is only run on Linux in the
// continuous integration tests.
if
(
Platform
.
isWindows
)
{
return
;
}
test
(
'analyze_sample_code smoke test'
,
()
{
final
ProcessResult
process
=
Process
.
runSync
(
final
ProcessResult
process
=
Process
.
runSync
(
'../../bin/cache/dart-sdk/bin/dart'
,
'../../bin/cache/dart-sdk/bin/dart'
,
<
String
>[
'analyze_sample_code.dart'
,
'test/analyze-sample-code-test-input'
],
<
String
>[
'analyze_sample_code.dart'
,
'
--no-include-dart-ui'
,
'
test/analyze-sample-code-test-input'
],
);
);
final
List
<
String
>
stdoutLines
=
process
.
stdout
.
toString
().
split
(
'
\n
'
);
final
List
<
String
>
stdoutLines
=
process
.
stdout
.
toString
().
split
(
'
\n
'
);
final
List
<
String
>
stderrLines
=
process
.
stderr
.
toString
().
split
(
'
\n
'
)
final
List
<
String
>
stderrLines
=
process
.
stderr
.
toString
().
split
(
'
\n
'
)
..
removeWhere
((
String
line
)
=>
line
.
startsWith
(
'Analyzer output:'
)
||
line
.
startsWith
(
'Building flutter tool...'
));
..
removeWhere
((
String
line
)
=>
line
.
startsWith
(
'Analyzer output:'
)
||
line
.
startsWith
(
'Building flutter tool...'
));
expect
(
process
.
exitCode
,
isNot
(
equals
(
0
)));
expect
(
process
.
exitCode
,
isNot
(
equals
(
0
)));
expect
(
stderrLines
,
<
String
>[
expect
(
stderrLines
,
<
String
>[
'In sample starting at known_broken_documentation.dart:117:bool? _visible = true;'
,
'In sample starting at
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:117:bool? _visible = true;'
,
'>>> info: Use late for private members with non-nullable type (use_late_for_private_fields_and_variables)'
,
'>>> info: Use late for private members with non-nullable type (use_late_for_private_fields_and_variables)'
,
'In sample starting at known_broken_documentation.dart:117: child: Text(title),'
,
'In sample starting at
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:117: child: Text(title),'
,
'>>> error: The final variable
\'
title
\'
can
\'
t be read because it is potentially unassigned at this point (read_potentially_unassigned_final)'
,
'>>> error: The final variable
\'
title
\'
can
\'
t be read because it is potentially unassigned at this point (read_potentially_unassigned_final)'
,
'known_broken_documentation.dart:30:9: new Opacity('
,
'
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:30:9: new Opacity('
,
'>>> info: Unnecessary new keyword (unnecessary_new)'
,
'>>> info: Unnecessary new keyword (unnecessary_new)'
,
'known_broken_documentation.dart:62:9: new Opacity('
,
'
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:62:9: new Opacity('
,
'>>> info: Unnecessary new keyword (unnecessary_new)'
,
'>>> info: Unnecessary new keyword (unnecessary_new)'
,
'known_broken_documentation.dart:95:9: const text0 = Text(
\'
Poor wandering ones!
\'
);'
,
'
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:95:9: const text0 = Text(
\'
Poor wandering ones!
\'
);'
,
'>>> info: Specify type annotations (always_specify_types)'
,
'>>> info: Specify type annotations (always_specify_types)'
,
'known_broken_documentation.dart:103:9: const text1 = _Text(
\'
Poor wandering ones!
\'
);'
,
'
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:103:9: const text1 = _Text(
\'
Poor wandering ones!
\'
);'
,
'>>> info: Specify type annotations (always_specify_types)'
,
'>>> info: Specify type annotations (always_specify_types)'
,
'known_broken_documentation.dart:111:9: final String? bar =
\'
Hello
\'
;'
,
'
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:111:9: final String? bar =
\'
Hello
\'
;'
,
'>>> info: Prefer const over final for declarations (prefer_const_declarations)'
,
'>>> info: Prefer const over final for declarations (prefer_const_declarations)'
,
'known_broken_documentation.dart:111:23: final String? bar =
\'
Hello
\'
;'
,
'
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:111:23: final String? bar =
\'
Hello
\'
;'
,
'>>> info: Use a non-nullable type for a final variable initialized with a non-nullable value (unnecessary_nullable_for_final_variable_declarations)'
,
'>>> info: Use a non-nullable type for a final variable initialized with a non-nullable value (unnecessary_nullable_for_final_variable_declarations)'
,
'known_broken_documentation.dart:112:9: final int foo = null;'
,
'
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:112:9: final int foo = null;'
,
'>>> info: Prefer const over final for declarations (prefer_const_declarations)'
,
'>>> info: Prefer const over final for declarations (prefer_const_declarations)'
,
'known_broken_documentation.dart:112:25: final int foo = null;'
,
'
dev/bots/test/analyze-sample-code-test-input/
known_broken_documentation.dart:112:25: final int foo = null;'
,
'>>> error: A value of type
\'
Null
\'
can
\'
t be assigned to a variable of type
\'
int
\'
(invalid_assignment)'
,
'>>> error: A value of type
\'
Null
\'
can
\'
t be assigned to a variable of type
\'
int
\'
(invalid_assignment)'
,
''
,
''
,
'Found 2 sample code errors.'
,
'Found 2 sample code errors.'
,
...
@@ -46,5 +53,23 @@ void main() {
...
@@ -46,5 +53,23 @@ void main() {
'Starting analysis of code samples.'
,
'Starting analysis of code samples.'
,
''
,
''
,
]);
]);
},
skip:
Platform
.
isWindows
);
});
test
(
'Analyzes dart:ui code'
,
()
{
final
ProcessResult
process
=
Process
.
runSync
(
'../../bin/cache/dart-sdk/bin/dart'
,
<
String
>[
'analyze_sample_code.dart'
,
'--dart-ui-location'
,
'test/analyze-sample-code-test-dart-ui'
,
'test/analyze-sample-code-test-input'
,
],
);
final
List
<
String
>
stdoutLines
=
process
.
stdout
.
toString
().
split
(
'
\n
'
);
expect
(
process
.
exitCode
,
isNot
(
equals
(
0
)));
expect
(
stdoutLines
,
equals
(<
String
>[
// There is one sample code section in the test's dummy dart:ui code.
'Found 8 snippet code blocks, 1 sample code sections, and 2 dartpad sections.'
,
''
,
]));
});
}
}
dev/snippets/lib/snippets.dart
View file @
b33c7891
...
@@ -179,7 +179,9 @@ class SnippetGenerator {
...
@@ -179,7 +179,9 @@ class SnippetGenerator {
description
.
add
(
line
);
description
.
add
(
line
);
}
else
{
}
else
{
assert
(
language
!=
null
);
assert
(
language
!=
null
);
components
.
last
.
contents
.
add
(
line
);
if
(
components
.
isNotEmpty
)
{
components
.
last
.
contents
.
add
(
line
);
}
}
}
}
}
return
<
_ComponentTuple
>[
return
<
_ComponentTuple
>[
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment