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
11a54dee
Commit
11a54dee
authored
May 06, 2016
by
Phil Quitslund
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3752 from pq/analysis_rework
Analysis re-work to use analyzer APIs.
parents
4d9fdda7
2df43d50
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
366 additions
and
294 deletions
+366
-294
pubspec.yaml
packages/flutter_test/pubspec.yaml
+3
-3
analyze.dart
packages/flutter_tools/lib/src/commands/analyze.dart
+83
-284
analysis.dart
packages/flutter_tools/lib/src/dart/analysis.dart
+275
-0
pubspec.yaml
packages/flutter_tools/pubspec.yaml
+3
-4
analyze_duplicate_names_test.dart
...ages/flutter_tools/test/analyze_duplicate_names_test.dart
+2
-3
No files found.
packages/flutter_test/pubspec.yaml
View file @
11a54dee
...
...
@@ -7,10 +7,10 @@ dependencies:
# here we pin it precisely to avoid version skew across our packages.
test
:
0.12.13+1
# We don't actually depend on 'analyzer', but 'test'
does. We pin the
# version of analyzer we depend on to avoid version skew across our
# We don't actually depend on 'analyzer', but 'test'
and 'flutter_tools' do.
#
We pin the
version of analyzer we depend on to avoid version skew across our
# packages.
analyzer
:
0.27.
2
analyzer
:
0.27.
4-alpha.1
flutter
:
path
:
../flutter
packages/flutter_tools/lib/src/commands/analyze.dart
View file @
11a54dee
...
...
@@ -11,101 +11,17 @@ import 'package:path/path.dart' as path;
import
'package:yaml/yaml.dart'
as
yaml
;
import
'../artifacts.dart'
;
import
'../base/logger.dart'
;
import
'../base/process.dart'
;
import
'../base/utils.dart'
;
import
'../build_configuration.dart'
;
import
'../dart/analysis.dart'
;
import
'../dart/sdk.dart'
;
import
'../globals.dart'
;
import
'../runner/flutter_command.dart'
;
bool
isDartFile
(
FileSystemEntity
entry
)
=>
entry
is
File
&&
entry
.
path
.
endsWith
(
'.dart'
);
bool
isDartTestFile
(
FileSystemEntity
entry
)
=>
entry
is
File
&&
entry
.
path
.
endsWith
(
'_test.dart'
);
bool
isDartBenchmarkFile
(
FileSystemEntity
entry
)
=>
entry
is
File
&&
entry
.
path
.
endsWith
(
'_bench.dart'
);
RegExp
_testFileParser
=
new
RegExp
(
r'^(.+)_test(\.dart)$'
);
void
_addDriverTest
(
FileSystemEntity
entry
,
List
<
String
>
dartFiles
)
{
if
(
isDartTestFile
(
entry
))
{
final
String
testFileName
=
entry
.
path
;
dartFiles
.
add
(
testFileName
);
Match
groups
=
_testFileParser
.
firstMatch
(
testFileName
);
assert
(
groups
.
groupCount
==
2
);
final
String
hostFileName
=
'
${groups[1]}${groups[2]}
'
;
File
hostFile
=
new
File
(
hostFileName
);
if
(
hostFile
.
existsSync
())
{
assert
(
isDartFile
(
hostFile
));
dartFiles
.
add
(
hostFileName
);
}
}
}
void
_addPackage
(
String
directoryPath
,
List
<
String
>
dartFiles
,
Set
<
String
>
pubSpecDirectories
)
{
final
int
originalDartFilesCount
=
dartFiles
.
length
;
// .../directoryPath/*/bin/*.dart
// .../directoryPath/*/lib/main.dart
// .../directoryPath/*/test/*_test.dart
// .../directoryPath/*/test/*/*_test.dart
// .../directoryPath/*/benchmark/*/*_bench.dart
Directory
binDirectory
=
new
Directory
(
path
.
join
(
directoryPath
,
'bin'
));
if
(
binDirectory
.
existsSync
())
{
for
(
FileSystemEntity
subentry
in
binDirectory
.
listSync
())
{
if
(
isDartFile
(
subentry
))
dartFiles
.
add
(
subentry
.
path
);
}
}
String
mainPath
=
path
.
join
(
directoryPath
,
'lib'
,
'main.dart'
);
if
(
FileSystemEntity
.
isFileSync
(
mainPath
))
dartFiles
.
add
(
mainPath
);
Directory
testDirectory
=
new
Directory
(
path
.
join
(
directoryPath
,
'test'
));
if
(
testDirectory
.
existsSync
())
{
for
(
FileSystemEntity
entry
in
testDirectory
.
listSync
())
{
if
(
entry
is
Directory
)
{
for
(
FileSystemEntity
subentry
in
entry
.
listSync
())
{
if
(
isDartTestFile
(
subentry
))
dartFiles
.
add
(
subentry
.
path
);
}
}
else
if
(
isDartTestFile
(
entry
))
{
dartFiles
.
add
(
entry
.
path
);
}
}
}
Directory
testDriverDirectory
=
new
Directory
(
path
.
join
(
directoryPath
,
'test_driver'
));
if
(
testDriverDirectory
.
existsSync
())
{
for
(
FileSystemEntity
entry
in
testDriverDirectory
.
listSync
())
{
if
(
entry
is
Directory
)
{
for
(
FileSystemEntity
subentry
in
entry
.
listSync
())
_addDriverTest
(
subentry
,
dartFiles
);
}
else
if
(
isDartTestFile
(
entry
))
{
_addDriverTest
(
entry
,
dartFiles
);
}
}
}
Directory
benchmarkDirectory
=
new
Directory
(
path
.
join
(
directoryPath
,
'benchmark'
));
if
(
benchmarkDirectory
.
existsSync
())
{
for
(
FileSystemEntity
entry
in
benchmarkDirectory
.
listSync
())
{
if
(
entry
is
Directory
)
{
for
(
FileSystemEntity
subentry
in
entry
.
listSync
())
{
if
(
isDartBenchmarkFile
(
subentry
))
dartFiles
.
add
(
subentry
.
path
);
}
}
else
if
(
isDartBenchmarkFile
(
entry
))
{
dartFiles
.
add
(
entry
.
path
);
}
}
}
if
(
originalDartFilesCount
!=
dartFiles
.
length
)
pubSpecDirectories
.
add
(
directoryPath
);
}
bool
isDartFile
(
FileSystemEntity
entry
)
=>
entry
is
File
&&
entry
.
path
.
endsWith
(
'.dart'
);
class
FileChanged
{
}
typedef
bool
FileFilter
(
FileSystemEntity
entity
);
class
AnalyzeCommand
extends
FlutterCommand
{
AnalyzeCommand
()
{
...
...
@@ -172,94 +88,60 @@ class AnalyzeCommand extends FlutterCommand {
Future
<
int
>
_analyzeOnce
()
async
{
Stopwatch
stopwatch
=
new
Stopwatch
()..
start
();
Set
<
String
>
pubSpecDirectories
=
new
HashSet
<
String
>();
List
<
String
>
dartFiles
=
argResults
.
rest
.
toList
()
;
Set
<
Directory
>
pubSpecDirectories
=
new
HashSet
<
Directory
>();
List
<
File
>
dartFiles
=
<
File
>[]
;
for
(
String
file
in
dartFiles
)
{
for
(
String
file
in
argResults
.
rest
.
toList
()
)
{
file
=
path
.
normalize
(
path
.
absolute
(
file
));
String
root
=
path
.
rootPrefix
(
file
);
dartFiles
.
add
(
new
File
(
file
));
while
(
file
!=
root
)
{
file
=
path
.
dirname
(
file
);
if
(
FileSystemEntity
.
isFileSync
(
path
.
join
(
file
,
'pubspec.yaml'
)))
{
pubSpecDirectories
.
add
(
file
);
pubSpecDirectories
.
add
(
new
Directory
(
file
)
);
break
;
}
}
}
if
(
argResults
[
'current-directory'
])
{
//TODO (pq): revisit package and directory defaults
if
(
argResults
[
'current-directory'
]
&&
!
argResults
[
'flutter-repo'
])
{
// ./*.dart
Directory
currentDirectory
=
new
Directory
(
'.'
);
bool
foundOne
=
false
;
for
(
FileSystemEntity
entry
in
currentDirectory
.
listSync
())
{
if
(
isDartFile
(
entry
))
{
dartFiles
.
add
(
entry
.
path
);
dartFiles
.
add
(
entry
);
foundOne
=
true
;
}
}
if
(
foundOne
)
pubSpecDirectories
.
add
(
'.'
);
pubSpecDirectories
.
add
(
currentDirectory
);
}
if
(
argResults
[
'current-package'
])
_addPackage
(
'.'
,
dartFiles
,
pubSpecDirectories
);
if
(
argResults
[
'flutter-repo'
])
{
//examples/*/ as package
//examples/layers/*/ as files
//dev/manual_tests/*/ as package
//dev/manual_tests/*/ as files
for
(
Directory
dir
in
runner
.
getRepoPackages
())
_addPackage
(
dir
.
path
,
dartFiles
,
pubSpecDirectories
);
Directory
subdirectory
;
subdirectory
=
new
Directory
(
path
.
join
(
ArtifactStore
.
flutterRoot
,
'examples'
,
'layers'
));
if
(
subdirectory
.
existsSync
())
{
bool
foundOne
=
false
;
for
(
FileSystemEntity
entry
in
subdirectory
.
listSync
())
{
if
(
entry
is
Directory
)
{
for
(
FileSystemEntity
subentry
in
entry
.
listSync
())
{
if
(
isDartFile
(
subentry
))
{
dartFiles
.
add
(
subentry
.
path
);
foundOne
=
true
;
}
}
}
}
if
(
foundOne
)
pubSpecDirectories
.
add
(
subdirectory
.
path
);
if
(
argResults
[
'current-package'
]
&&
!
argResults
[
'flutter-repo'
])
{
// **/.*dart
Directory
currentDirectory
=
new
Directory
(
'.'
);
_collectDartFiles
(
currentDirectory
,
dartFiles
);
pubSpecDirectories
.
add
(
currentDirectory
);
}
subdirectory
=
new
Directory
(
path
.
join
(
ArtifactStore
.
flutterRoot
,
'dev'
,
'manual_tests'
));
if
(
subdirectory
.
existsSync
())
{
bool
foundOne
=
false
;
for
(
FileSystemEntity
entry
in
subdirectory
.
listSync
())
{
if
(
entry
is
Directory
)
{
_addPackage
(
entry
.
path
,
dartFiles
,
pubSpecDirectories
);
}
else
if
(
isDartFile
(
entry
))
{
dartFiles
.
add
(
entry
.
path
);
foundOne
=
true
;
}
}
if
(
foundOne
)
pubSpecDirectories
.
add
(
subdirectory
.
path
);
//TODO (ianh): Fix the intl package resource generator
//TODO (pq): extract this regexp from the exclude in options
RegExp
stockExampleFiles
=
new
RegExp
(
'examples/stocks/lib/.*
\
.dart
\$
'
);
if
(
argResults
[
'flutter-repo'
])
{
for
(
Directory
dir
in
runner
.
getRepoPackages
())
{
_collectDartFiles
(
dir
,
dartFiles
,
exclude:
(
FileSystemEntity
entity
)
=>
stockExampleFiles
.
hasMatch
(
entity
.
path
));
pubSpecDirectories
.
add
(
dir
);
}
}
dartFiles
=
dartFiles
.
map
((
String
directory
)
=>
path
.
normalize
(
path
.
absolute
(
directory
))).
toSet
().
toList
();
dartFiles
.
sort
();
// prepare a Dart file that references all the above Dart files
StringBuffer
mainBody
=
new
StringBuffer
();
for
(
int
index
=
0
;
index
<
dartFiles
.
length
;
index
+=
1
)
mainBody
.
writeln
(
'import
\'
${dartFiles[index]}
\'
as file
$index
;'
);
mainBody
.
writeln
(
'void main() { }'
);
// determine what all the various .packages files depend on
PackageDependencyTracker
dependencies
=
new
PackageDependencyTracker
();
for
(
Directory
directory
in
pubSpecDirectories
.
map
((
String
path
)
=>
new
Directory
(
path
))
)
{
for
(
Directory
directory
in
pubSpecDirectories
)
{
String
pubSpecYamlPath
=
path
.
join
(
directory
.
path
,
'pubspec.yaml'
);
File
pubSpecYamlFile
=
new
File
(
pubSpecYamlPath
);
if
(
pubSpecYamlFile
.
existsSync
())
{
...
...
@@ -309,98 +191,36 @@ class AnalyzeCommand extends FlutterCommand {
for
(
String
package
in
packages
.
keys
)
packagesBody
.
writeln
(
'
$package
:
${path.toUri(packages[package])}
'
);
// save the Dart file and the .packages file to disk
// save the .packages file to disk
//TODO (pq): consider passing package info via a data URI
Directory
host
=
Directory
.
systemTemp
.
createTempSync
(
'flutter-analyze-'
);
File
mainFile
=
new
File
(
path
.
join
(
host
.
path
,
'main.dart'
))..
writeAsStringSync
(
mainBody
.
toString
());
File
optionsFile
=
new
File
(
path
.
join
(
ArtifactStore
.
flutterRoot
,
'packages'
,
'flutter_tools'
,
'flutter_analysis_options'
));
File
packagesFile
=
new
File
(
path
.
join
(
host
.
path
,
'.packages'
))..
writeAsStringSync
(
packagesBody
.
toString
());
List
<
String
>
cmd
=
<
String
>[
sdkBinaryName
(
'dartanalyzer'
,
sdkLocation:
argResults
[
'dart-sdk'
]),
// do not set '--warnings', since that will include the entire Dart SDK
'--ignore-unrecognized-flags'
,
'--enable_type_checks'
,
'--package-warnings'
,
'--fatal-warnings'
,
'--fatal-hints'
,
// defines lints
'--options'
,
optionsFile
.
path
,
'--packages'
,
packagesFile
.
path
,
mainFile
.
path
];
Status
status
;
String
packagesFilePath
=
path
.
join
(
host
.
path
,
'.packages'
);
new
File
(
packagesFilePath
).
writeAsStringSync
(
packagesBody
.
toString
());
if
(
argResults
[
'preamble'
])
{
if
(
dartFiles
.
length
==
1
)
{
status
=
logger
.
startProgress
(
'Analyzing
${path.relative(dartFiles.first
)}
...'
);
logger
.
printStatus
(
'Analyzing
${path.relative(dartFiles.first.path
)}
...'
);
}
else
{
status
=
logger
.
startProgress
(
'Analyzing
${dartFiles.length}
entry point
s...'
);
logger
.
printStatus
(
'Analyzing
${dartFiles.length}
file
s...'
);
}
for
(
String
file
in
dartFiles
)
printTrace
(
file
);
}
DriverOptions
options
=
new
DriverOptions
();
options
.
dartSdkPath
=
argResults
[
'dart-sdk'
];
options
.
packageConfigPath
=
packagesFilePath
;
options
.
analysisOptionsFile
=
path
.
join
(
ArtifactStore
.
flutterRoot
,
'packages'
,
'flutter_tools'
,
'flutter_analysis_options'
);
AnalysisDriver
analyzer
=
new
AnalysisDriver
(
options
);
printTrace
(
cmd
.
join
(
' '
));
Process
process
=
await
Process
.
start
(
cmd
[
0
],
cmd
.
sublist
(
1
),
workingDirectory:
host
.
path
);
int
errorCount
=
0
;
StringBuffer
output
=
new
StringBuffer
();
process
.
stdout
.
transform
(
UTF8
.
decoder
).
listen
((
String
data
)
{
output
.
write
(
data
);
});
process
.
stderr
.
transform
(
UTF8
.
decoder
).
listen
((
String
data
)
{
// dartanalyzer doesn't seem to ever output anything on stderr
errorCount
+=
1
;
printError
(
data
);
});
int
exitCode
=
await
process
.
exitCode
;
status
?.
stop
(
showElapsedTime:
true
);
List
<
Pattern
>
patternsToSkip
=
<
Pattern
>[
'Analyzing [
${mainFile.path}
]...'
,
new
RegExp
(
'^
\\
[(hint|error)
\\
] Unused import
\\
(
${mainFile.path}
,'
),
new
RegExp
(
r'^\[.+\] .+ \(.+/\.pub-cache/.+'
),
new
RegExp
(
r'[0-9]+ (error|warning|hint|lint).+found\.'
),
new
RegExp
(
r'^$'
),
];
RegExp
generalPattern
=
new
RegExp
(
r'^\[(error|warning|hint|lint)\] (.+) \(([^(),]+), line ([0-9]+), col ([0-9]+)\)$'
);
RegExp
conflictingNamesPattern
=
new
RegExp
(
'^The imported libraries
\'
([^
\'
]+)
\'
and
\'
([^
\'
]+)
\'
cannot have the same name
\'
([^
\'
]+)
\'
\$
'
);
RegExp
missingFilePattern
=
new
RegExp
(
'^Target of URI does not exist:
\'
([^
\'
)]+)
\'
\$
'
);
RegExp
documentAllMembersPattern
=
new
RegExp
(
'^Document all public members
\$
'
);
Set
<
String
>
changedFiles
=
new
Set
<
String
>();
// files about which we've complained that they changed
_SourceCache
cache
=
new
_SourceCache
(
10
);
//TODO (pq): consider error handling
List
<
AnalysisErrorDescription
>
errors
=
analyzer
.
analyze
(
dartFiles
);
int
errorCount
=
0
;
int
membersMissingDocumentation
=
0
;
List
<
String
>
errorLines
=
output
.
toString
().
split
(
'
\n
'
);
for
(
String
errorLine
in
errorLines
)
{
if
(
patternsToSkip
.
every
((
Pattern
pattern
)
=>
pattern
.
allMatches
(
errorLine
).
isEmpty
))
{
Match
groups
=
generalPattern
.
firstMatch
(
errorLine
);
if
(
groups
!=
null
)
{
String
level
=
groups
[
1
];
String
filename
=
groups
[
3
];
String
errorMessage
=
groups
[
2
];
int
lineNumber
=
int
.
parse
(
groups
[
4
]);
int
colNumber
=
int
.
parse
(
groups
[
5
]);
try
{
File
source
=
new
File
(
filename
);
List
<
String
>
sourceLines
=
cache
.
getSourceFor
(
source
);
if
(
lineNumber
>
sourceLines
.
length
)
throw
new
FileChanged
();
String
sourceLine
=
sourceLines
[
lineNumber
-
1
];
if
(
colNumber
>
sourceLine
.
length
)
throw
new
FileChanged
();
for
(
AnalysisErrorDescription
error
in
errors
)
{
bool
shouldIgnore
=
false
;
if
(
documentAllMembersPattern
.
firstMatch
(
errorMessage
)
!=
null
)
{
if
(
error
.
errorCode
.
name
==
'public_member_api_docs'
)
{
// https://github.com/dart-lang/linter/issues/207
// https://github.com/dart-lang/linter/issues/208
if
(
isFlutterLibrary
(
filen
ame
))
{
if
(
isFlutterLibrary
(
error
.
source
.
fullN
ame
))
{
if
(!
argResults
[
'dartdocs'
])
{
membersMissingDocumentation
+=
1
;
shouldIgnore
=
true
;
...
...
@@ -408,51 +228,29 @@ class AnalyzeCommand extends FlutterCommand {
}
else
{
shouldIgnore
=
true
;
}
}
else
if
(
filename
==
mainFile
.
path
)
{
Match
libs
=
conflictingNamesPattern
.
firstMatch
(
errorMessage
);
Match
missing
=
missingFilePattern
.
firstMatch
(
errorMessage
);
if
(
libs
!=
null
)
{
errorLine
=
'[
$level
]
$errorMessage
(
${dartFiles[lineNumber-1]}
)'
;
// strip the reference to the generated main.dart
}
else
if
(
missing
!=
null
)
{
errorLine
=
'[
$level
] File does not exist (
${missing[1]}
)'
;
}
else
{
errorLine
+=
' (Please file a bug on the "flutter analyze" command saying that you saw this message.)'
;
}
}
else
if
(
filename
.
endsWith
(
'.mojom.dart'
))
{
// autogenerated code - TODO(ianh): Fix the Dart mojom compiler
//TODO(ianh): Fix the Dart mojom compiler
if
(
error
.
source
.
fullName
.
endsWith
(
'.mojom.dart'
))
shouldIgnore
=
true
;
}
else
if
(
sourceLines
.
first
.
startsWith
(
'// DO NOT EDIT. This is code generated'
))
{
// autogenerated code - TODO(ianh): Fix the intl package resource generator
shouldIgnore
=
true
;
}
if
(
shouldIgnore
)
continue
;
}
on
FileSystemException
catch
(
exception
)
{
if
(
changedFiles
.
add
(
filename
))
printError
(
'[warning] Could not read file (
${exception.message}${ exception.osError != null ? "; ${exception.osError}
" : ""}) (
$filename
)'
);
}
on
FileChanged
{
if
(
changedFiles
.
add
(
filename
))
printError
(
'[warning] File shrank during analysis (
$filename
)'
);
}
}
printError
(
errorLine
);
printError
(
error
.
asString
());
errorCount
+=
1
;
}
}
stopwatch
.
stop
();
String
elapsed
=
(
stopwatch
.
elapsedMilliseconds
/
1000.0
).
toStringAsFixed
(
1
);
host
.
deleteSync
(
recursive:
true
);
if
(
exitCode
<
0
||
exitCode
>
3
)
// analyzer exit codes: 0 = nothing, 1 = hints, 2 = warnings, 3 = errors
return
exitCode
;
if
(
_isBenchmarking
)
_writeBenchmark
(
stopwatch
,
errorCount
);
if
(
errorCount
>
0
)
{
if
(
membersMissingDocumentation
>
0
&&
argResults
[
'flutter-repo'
])
printError
(
'[lint]
$membersMissingDocumentation
public
${ membersMissingDocumentation == 1 ? "member lacks" : "members lack" }
documentation'
);
printError
(
'[lint]
$membersMissingDocumentation
public
${ membersMissingDocumentation == 1 ? "member lacks" : "members lack" }
documentation (ran in
${elapsed}
s)'
);
else
print
(
'(Ran in
${elapsed}
s)'
);
return
1
;
// we consider any level of error to be an error exit (we don't report different levels)
}
if
(
argResults
[
'congratulate'
])
{
...
...
@@ -465,6 +263,24 @@ class AnalyzeCommand extends FlutterCommand {
return
0
;
}
List
<
File
>
_collectDartFiles
(
Directory
dir
,
List
<
File
>
collected
,
{
FileFilter
exclude
})
{
// Bail out in case of a .dartignore.
if
(
FileSystemEntity
.
isFileSync
(
path
.
join
(
path
.
dirname
(
dir
.
path
),
'.dartignore'
)))
return
collected
;
for
(
FileSystemEntity
entity
in
dir
.
listSync
(
recursive:
false
,
followLinks:
false
))
{
if
(
isDartFile
(
entity
)
&&
(
exclude
==
null
||
!
exclude
(
entity
)))
collected
.
add
(
entity
);
if
(
entity
is
Directory
)
{
String
name
=
path
.
basename
(
entity
.
path
);
if
(!
name
.
startsWith
(
'.'
)
&&
name
!=
'packages'
)
_collectDartFiles
(
entity
,
collected
,
exclude:
exclude
);
}
}
return
collected
;
}
Future
<
int
>
_analyzeWatch
()
async
{
List
<
String
>
directories
;
...
...
@@ -829,20 +645,3 @@ class AnalysisError implements Comparable<AnalysisError> {
return
'
${severity.toLowerCase().padLeft(7)}
•
$message
•
$relativePath
:
$startLine
:
$startColumn
'
;
}
}
class
_SourceCache
{
_SourceCache
(
this
.
cacheSize
);
final
int
cacheSize
;
final
Map
<
String
,
List
<
String
>>
_lines
=
new
LinkedHashMap
<
String
,
List
<
String
>>();
List
<
String
>
getSourceFor
(
File
file
)
{
if
(!
_lines
.
containsKey
(
file
.
path
))
{
if
(
_lines
.
length
>=
cacheSize
)
_lines
.
remove
(
_lines
.
keys
.
first
);
_lines
[
file
.
path
]
=
file
.
readAsLinesSync
();
}
return
_lines
[
file
.
path
];
}
}
packages/flutter_tools/lib/src/dart/analysis.dart
0 → 100644
View file @
11a54dee
// Copyright 2016 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.
import
'dart:collection'
;
import
'dart:io'
;
import
'package:analyzer/file_system/file_system.dart'
as
file_system
;
import
'package:analyzer/file_system/file_system.dart'
show
Folder
;
import
'package:analyzer/file_system/physical_file_system.dart'
;
import
'package:analyzer/plugin/options.dart'
;
import
'package:analyzer/source/analysis_options_provider.dart'
;
import
'package:analyzer/source/embedder.dart'
;
import
'package:analyzer/source/error_processor.dart'
;
import
'package:analyzer/source/package_map_provider.dart'
;
import
'package:analyzer/source/package_map_resolver.dart'
;
import
'package:analyzer/source/pub_package_map_provider.dart'
;
import
'package:analyzer/src/generated/engine.dart'
;
import
'package:analyzer/src/generated/error.dart'
;
import
'package:analyzer/src/generated/java_io.dart'
;
import
'package:analyzer/src/generated/sdk.dart'
;
import
'package:analyzer/src/generated/sdk_io.dart'
;
import
'package:analyzer/src/generated/source.dart'
;
import
'package:analyzer/src/generated/source_io.dart'
;
import
'package:analyzer/src/task/options.dart'
;
import
'package:cli_util/cli_util.dart'
as
cli_util
;
import
'package:linter/src/plugin/linter_plugin.dart'
;
import
'package:package_config/packages.dart'
show
Packages
;
import
'package:package_config/packages_file.dart'
as
pkgfile
show
parse
;
import
'package:package_config/src/packages_impl.dart'
show
MapPackages
;
import
'package:path/path.dart'
as
path
;
import
'package:plugin/manager.dart'
;
import
'package:plugin/plugin.dart'
;
class
AnalysisDriver
{
Set
<
Source
>
_analyzedSources
=
new
HashSet
<
Source
>();
AnalysisOptionsProvider
analysisOptionsProvider
=
new
AnalysisOptionsProvider
();
AnalysisContext
context
;
DriverOptions
options
;
AnalysisDriver
(
this
.
options
)
{
AnalysisEngine
.
instance
.
logger
=
new
_StdLogger
(
outSink:
options
.
outSink
,
errorSink:
options
.
errorSink
);
_processPlugins
();
}
String
get
sdkDir
=>
options
.
dartSdkPath
??
cli_util
.
getSdkDir
().
path
;
List
<
AnalysisErrorDescription
>
analyze
(
Iterable
<
File
>
files
)
{
List
<
AnalysisErrorInfo
>
infos
=
_analyze
(
files
);
List
<
AnalysisErrorDescription
>
errors
=
<
AnalysisErrorDescription
>[];
for
(
AnalysisErrorInfo
info
in
infos
)
{
for
(
AnalysisError
error
in
info
.
errors
)
{
if
(!
_isFiltered
(
error
))
{
errors
.
add
(
new
AnalysisErrorDescription
(
error
,
info
.
lineInfo
));
}
}
}
return
errors
;
}
List
<
AnalysisErrorInfo
>
_analyze
(
Iterable
<
File
>
files
)
{
context
=
AnalysisEngine
.
instance
.
createAnalysisContext
();
_processAnalysisOptions
(
context
,
options
);
Packages
packages
=
_getPackageConfig
();
context
.
sourceFactory
=
new
SourceFactory
(
_getResolvers
(
context
,
packages
),
packages
);
List
<
Source
>
sources
=
<
Source
>[];
ChangeSet
changeSet
=
new
ChangeSet
();
for
(
File
file
in
files
)
{
JavaFile
sourceFile
=
new
JavaFile
(
path
.
normalize
(
file
.
absolute
.
path
));
Source
source
=
new
FileBasedSource
(
sourceFile
,
sourceFile
.
toURI
());
Uri
uri
=
context
.
sourceFactory
.
restoreUri
(
source
);
if
(
uri
!=
null
)
{
source
=
new
FileBasedSource
(
sourceFile
,
uri
);
}
sources
.
add
(
source
);
changeSet
.
addedSource
(
source
);
}
context
.
applyChanges
(
changeSet
);
List
<
AnalysisErrorInfo
>
infos
=
<
AnalysisErrorInfo
>[];
for
(
Source
source
in
sources
)
{
context
.
computeErrors
(
source
);
infos
.
add
(
context
.
getErrors
(
source
));
_analyzedSources
.
add
(
source
);
}
return
infos
;
}
Packages
_getPackageConfig
()
{
if
(
options
.
packageConfigPath
!=
null
)
{
String
packageConfigPath
=
options
.
packageConfigPath
;
Uri
fileUri
=
new
Uri
.
file
(
packageConfigPath
);
try
{
File
configFile
=
new
File
.
fromUri
(
fileUri
).
absolute
;
List
<
int
>
bytes
=
configFile
.
readAsBytesSync
();
Map
<
String
,
Uri
>
map
=
pkgfile
.
parse
(
bytes
,
configFile
.
uri
);
return
new
MapPackages
(
map
);
}
catch
(
e
)
{
throw
new
AnalysisDriverException
(
'Unable to create package map.'
);
}
}
return
null
;
}
Map
<
String
,
List
<
file_system
.
Folder
>>
_getPackageMap
(
Packages
packages
)
{
if
(
packages
==
null
)
return
null
;
Map
<
String
,
List
<
file_system
.
Folder
>>
folderMap
=
new
Map
<
String
,
List
<
file_system
.
Folder
>>();
packages
.
asMap
().
forEach
((
String
packagePath
,
Uri
uri
)
{
folderMap
[
packagePath
]
=
<
file_system
.
Folder
>[
PhysicalResourceProvider
.
INSTANCE
.
getFolder
(
path
.
fromUri
(
uri
))
];
});
return
folderMap
;
}
List
<
UriResolver
>
_getResolvers
(
InternalAnalysisContext
context
,
Packages
packages
)
{
DartSdk
sdk
=
new
DirectoryBasedDartSdk
(
new
JavaFile
(
sdkDir
));
List
<
UriResolver
>
resolvers
=
<
UriResolver
>[];
Map
<
String
,
List
<
file_system
.
Folder
>>
packageMap
=
_getPackageMap
(
packages
);
EmbedderYamlLocator
yamlLocator
=
context
.
embedderYamlLocator
;
yamlLocator
.
refresh
(
packageMap
);
EmbedderUriResolver
embedderUriResolver
=
new
EmbedderUriResolver
(
yamlLocator
.
embedderYamls
);
if
(
embedderUriResolver
.
length
==
0
)
{
resolvers
.
add
(
new
DartUriResolver
(
sdk
));
}
else
{
resolvers
.
add
(
embedderUriResolver
);
}
if
(
options
.
packageRootPath
!=
null
)
{
JavaFile
packageDirectory
=
new
JavaFile
(
options
.
packageRootPath
);
resolvers
.
add
(
new
PackageUriResolver
(<
JavaFile
>[
packageDirectory
]));
}
else
{
PubPackageMapProvider
pubPackageMapProvider
=
new
PubPackageMapProvider
(
PhysicalResourceProvider
.
INSTANCE
,
sdk
);
PackageMapInfo
packageMapInfo
=
pubPackageMapProvider
.
computePackageMap
(
PhysicalResourceProvider
.
INSTANCE
.
getResource
(
'.'
));
Map
<
String
,
List
<
Folder
>>
packageMap
=
packageMapInfo
.
packageMap
;
if
(
packageMap
!=
null
)
{
resolvers
.
add
(
new
PackageMapUriResolver
(
PhysicalResourceProvider
.
INSTANCE
,
packageMap
));
}
}
resolvers
.
add
(
new
FileUriResolver
());
return
resolvers
;
}
bool
_isFiltered
(
AnalysisError
error
)
{
ErrorProcessor
processor
=
ErrorProcessor
.
getProcessor
(
context
,
error
);
// Filtered errors are processed to a severity of `null`.
return
processor
!=
null
&&
processor
.
severity
==
null
;
}
void
_processAnalysisOptions
(
AnalysisContext
context
,
AnalysisOptions
analysisOptions
)
{
List
<
OptionsProcessor
>
optionsProcessors
=
AnalysisEngine
.
instance
.
optionsPlugin
.
optionsProcessors
;
try
{
String
optionsPath
=
options
.
analysisOptionsFile
;
if
(
optionsPath
!=
null
)
{
file_system
.
File
file
=
PhysicalResourceProvider
.
INSTANCE
.
getFile
(
optionsPath
);
Map
<
Object
,
Object
>
optionMap
=
analysisOptionsProvider
.
getOptionsFromFile
(
file
);
optionsProcessors
.
forEach
(
(
OptionsProcessor
p
)
=>
p
.
optionsProcessed
(
context
,
optionMap
));
if
(
optionMap
!=
null
)
{
configureContextOptions
(
context
,
optionMap
);
}
}
}
on
Exception
catch
(
e
)
{
optionsProcessors
.
forEach
((
OptionsProcessor
p
)
=>
p
.
onError
(
e
));
}
}
void
_processPlugins
()
{
List
<
Plugin
>
plugins
=
<
Plugin
>[];
plugins
.
addAll
(
AnalysisEngine
.
instance
.
requiredPlugins
);
plugins
.
add
(
AnalysisEngine
.
instance
.
commandLinePlugin
);
plugins
.
add
(
AnalysisEngine
.
instance
.
optionsPlugin
);
plugins
.
add
(
linterPlugin
);
ExtensionManager
manager
=
new
ExtensionManager
();
manager
.
processPlugins
(
plugins
);
}
}
class
AnalysisDriverException
implements
Exception
{
final
String
message
;
AnalysisDriverException
([
this
.
message
]);
@override
String
toString
()
=>
message
==
null
?
'Exception'
:
'Exception:
$message
'
;
}
class
AnalysisErrorDescription
{
static
Directory
cwd
=
Directory
.
current
.
absolute
;
final
AnalysisError
error
;
final
LineInfo
line
;
AnalysisErrorDescription
(
this
.
error
,
this
.
line
);
ErrorCode
get
errorCode
=>
error
.
errorCode
;
String
get
errorType
=>
error
.
errorCode
.
type
.
displayName
;
LineInfo_Location
get
location
=>
line
.
getLocation
(
error
.
offset
);
String
get
path
=>
_shorten
(
cwd
.
path
,
error
.
source
.
fullName
);
Source
get
source
=>
error
.
source
;
String
asString
()
=>
'[
$errorType
]
${error.message}
(
$path
, '
'line
${location.lineNumber}
, col
${location.columnNumber}
)'
;
static
String
_shorten
(
String
root
,
String
path
)
=>
path
.
startsWith
(
root
)
?
path
.
substring
(
root
.
length
+
1
)
:
path
;
}
class
DriverOptions
extends
AnalysisOptionsImpl
{
@override
int
cacheSize
=
512
;
/// The path to the dart SDK.
String
dartSdkPath
;
/// The path to a `.packages` configuration file
String
packageConfigPath
;
/// The path to the package root.
String
packageRootPath
;
/// The path to analysis options.
String
analysisOptionsFile
;
@override
bool
generateSdkErrors
=
false
;
/// Analysis options map.
Map
<
Object
,
Object
>
analysisOptions
;
@override
bool
lint
=
true
;
/// Out sink for logging.
IOSink
outSink
=
stdout
;
/// Error sink for logging.
IOSink
errorSink
=
stderr
;
}
class
_StdLogger
extends
Logger
{
final
IOSink
outSink
;
final
IOSink
errorSink
;
_StdLogger
({
this
.
outSink
,
this
.
errorSink
});
@override
void
logError
(
String
message
,
[
Exception
exception
])
=>
errorSink
.
writeln
(
message
);
@override
void
logInformation
(
String
message
,
[
Exception
exception
])
=>
outSink
.
writeln
(
message
);
}
packages/flutter_tools/pubspec.yaml
View file @
11a54dee
...
...
@@ -15,6 +15,7 @@ dependencies:
http
:
^0.11.3
json_rpc_2
:
^2.0.0
json_schema
:
^1.0.3
linter
:
^0.1.15
mustache4dart
:
^1.0.0
package_config
:
^0.1.3
path
:
^1.3.0
...
...
@@ -33,10 +34,8 @@ dependencies:
# precisely.
test
:
0.12.13+1
# We don't actually depend on 'analyzer', but 'test' does. We pin the
# version of analyzer we depend on to avoid version skew across our
# packages.
analyzer
:
0.27.2
# Pinned in flutter_test as well.
analyzer
:
0.27.4-alpha.1
dev_dependencies
:
mockito
:
^0.11.0
...
...
packages/flutter_tools/test/analyze_duplicate_names_test.dart
View file @
11a54dee
...
...
@@ -38,9 +38,8 @@ void main() {
return
createTestCommandRunner
(
command
).
run
(
<
String
>[
'analyze'
,
'--no-current-package'
,
'--no-current-directory'
,
dartFileA
.
path
,
dartFileB
.
path
]
).
then
((
int
code
)
{
expect
(
code
,
1
);
expect
(
testLogger
.
errorText
,
'[warning] The imported libraries
\'
a.dart
\'
and
\'
b.dart
\'
cannot have the same name
\'
test
\'
(
${dartFileB.path}
)
\n
'
);
expect
(
testLogger
.
statusText
,
'Analyzing 2 entry points...
\n
'
);
expect
(
code
,
0
);
expect
(
testLogger
.
statusText
,
startsWith
(
'Analyzing 2 files...
\n
No analyzer warnings!'
));
});
},
overrides:
<
Type
,
dynamic
>{
...
...
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