Ignore files that are hidden by generated files.

We cannot analyze them - their URIs will be resolved to other files,
element models will not correspond to ASTs, etc.

R=brianwilkerson@google.com, paulberry@google.com
BUG=

Review-Url: https://codereview.chromium.org/2654303003 .
This commit is contained in:
Konstantin Shcheglov
2017-01-27 08:47:43 -08:00
parent 97f968de1c
commit f28e8afb23
6 changed files with 183 additions and 69 deletions
+19 -5
View File
@@ -74,7 +74,7 @@ class AnalysisDriver {
/**
* The version of data format, should be incremented on every format change.
*/
static const int DATA_VERSION = 13;
static const int DATA_VERSION = 14;
/**
* The name of the driver, e.g. the name of the folder.
@@ -416,6 +416,9 @@ class AnalysisDriver {
* The results of analysis are eventually produced by the [results] stream.
*/
void addFile(String path) {
if (!_fsState.hasUri(path)) {
return;
}
if (AnalysisEngine.isDartFileName(path)) {
_addedFiles.add(path);
_filesToAnalyze.add(path);
@@ -497,9 +500,13 @@ class AnalysisDriver {
/**
* Return a [Future] that completes with the [AnalysisDriverUnitIndex] for
* the file with the given [path].
* the file with the given [path], or with `null` if the file cannot be
* analyzed.
*/
Future<AnalysisDriverUnitIndex> getIndex(String path) {
if (!_fsState.hasUri(path)) {
return null;
}
var completer = new Completer<AnalysisDriverUnitIndex>();
_indexRequestedFiles
.putIfAbsent(path, () => <Completer<AnalysisDriverUnitIndex>>[])
@@ -511,8 +518,8 @@ class AnalysisDriver {
/**
* Return a [Future] that completes with a [AnalysisResult] for the Dart
* file with the given [path]. If the file is not a Dart file, the [Future]
* completes with `null`.
* file with the given [path]. If the file is not a Dart file or cannot
* be analyzed, the [Future] completes with `null`.
*
* The [path] must be absolute and normalized.
*
@@ -527,6 +534,10 @@ class AnalysisDriver {
* state transitions to "idle".
*/
Future<AnalysisResult> getResult(String path) {
if (!_fsState.hasUri(path)) {
return null;
}
// Return the cached result.
{
AnalysisResult result = _priorityResults[path];
@@ -560,9 +571,12 @@ class AnalysisDriver {
/**
* Return a [Future] that completes with the [CompilationUnitElement] for the
* file with the given [path].
* file with the given [path], or with `null` if the file cannot be analyzed.
*/
Future<CompilationUnitElement> getUnitElement(String path) {
if (!_fsState.hasUri(path)) {
return null;
}
var completer = new Completer<CompilationUnitElement>();
_unitElementRequestedFiles
.putIfAbsent(path, () => <Completer<CompilationUnitElement>>[])
@@ -539,6 +539,11 @@ class FileSystemState {
*/
final Set<String> knownFilePaths = new Set<String>();
/**
* Mapping from a path to the flag whether there is a URI for the path.
*/
final Map<String, bool> _hasUriForPath = {};
/**
* Mapping from a path to the corresponding [FileState]s, canonical or not.
*/
@@ -592,7 +597,7 @@ class FileSystemState {
// Try to get the existing instance.
file = _uriToFile[uri];
// If we have a file, call it the canonical one and return it.
if (file != null && file.path == path) {
if (file != null) {
_pathToCanonicalFile[path] = file;
return file;
}
@@ -647,6 +652,26 @@ class FileSystemState {
..insert(0, canonicalFile);
}
/**
* Return `true` if there is a URI that can be resolved to the [path].
*
* When a file exists, but for the URI that corresponds to the file is
* resolved to another file, e.g. a generated one in Bazel, Gn, etc, we
* cannot analyze the original file.
*/
bool hasUri(String path) {
bool flag = _hasUriForPath[path];
if (flag == null) {
File resource = _resourceProvider.getFile(path);
Source fileSource = resource.createSource();
Uri uri = _sourceFactory.restoreUri(fileSource);
Source uriSource = _sourceFactory.forUri2(uri);
flag = uriSource.fullName == path;
_hasUriForPath[path] = flag;
}
return flag;
}
/**
* Remove the file with the given [path].
*/
+52 -40
View File
@@ -48,10 +48,12 @@ class Search {
for (FileState file in _driver.fsState.knownFiles) {
CompilationUnitElement unitElement =
await _driver.getUnitElement(file.path);
for (ClassElement clazz in unitElement.types) {
clazz.accessors.forEach(addElement);
clazz.fields.forEach(addElement);
clazz.methods.forEach(addElement);
if (unitElement != null) {
for (ClassElement clazz in unitElement.types) {
clazz.accessors.forEach(addElement);
clazz.fields.forEach(addElement);
clazz.methods.forEach(addElement);
}
}
}
return elements;
@@ -132,12 +134,14 @@ class Search {
for (FileState file in _driver.fsState.knownFiles) {
CompilationUnitElement unitElement =
await _driver.getUnitElement(file.path);
unitElement.accessors.forEach(addElement);
unitElement.enums.forEach(addElement);
unitElement.functions.forEach(addElement);
unitElement.functionTypeAliases.forEach(addElement);
unitElement.topLevelVariables.forEach(addElement);
unitElement.types.forEach(addElement);
if (unitElement != null) {
unitElement.accessors.forEach(addElement);
unitElement.enums.forEach(addElement);
unitElement.functions.forEach(addElement);
unitElement.functionTypeAliases.forEach(addElement);
unitElement.topLevelVariables.forEach(addElement);
unitElement.types.forEach(addElement);
}
}
return elements;
}
@@ -157,17 +161,19 @@ class Search {
List<SearchResult> results = [];
for (String file in files) {
AnalysisDriverUnitIndex index = await _driver.getIndex(file);
_IndexRequest request = new _IndexRequest(index);
var fileResults = await request.getUnresolvedMemberReferences(
name,
const {
IndexRelationKind.IS_READ_BY: SearchResultKind.READ,
IndexRelationKind.IS_WRITTEN_BY: SearchResultKind.WRITE,
IndexRelationKind.IS_READ_WRITTEN_BY: SearchResultKind.READ_WRITE,
IndexRelationKind.IS_INVOKED_BY: SearchResultKind.INVOCATION
},
() => _driver.getUnitElement(file));
results.addAll(fileResults);
if (index != null) {
_IndexRequest request = new _IndexRequest(index);
var fileResults = await request.getUnresolvedMemberReferences(
name,
const {
IndexRelationKind.IS_READ_BY: SearchResultKind.READ,
IndexRelationKind.IS_WRITTEN_BY: SearchResultKind.WRITE,
IndexRelationKind.IS_READ_WRITTEN_BY: SearchResultKind.READ_WRITE,
IndexRelationKind.IS_INVOKED_BY: SearchResultKind.INVOCATION
},
() => _driver.getUnitElement(file));
results.addAll(fileResults);
}
}
return results;
@@ -217,12 +223,14 @@ class Search {
Map<IndexRelationKind, SearchResultKind> relationToResultKind,
String file) async {
AnalysisDriverUnitIndex index = await _driver.getIndex(file);
_IndexRequest request = new _IndexRequest(index);
int elementId = request.findElementId(element);
if (elementId != -1) {
List<SearchResult> fileResults = await request.getRelations(
elementId, relationToResultKind, () => _driver.getUnitElement(file));
results.addAll(fileResults);
if (index != null) {
_IndexRequest request = new _IndexRequest(index);
int elementId = request.findElementId(element);
if (elementId != -1) {
List<SearchResult> fileResults = await request.getRelations(elementId,
relationToResultKind, () => _driver.getUnitElement(file));
results.addAll(fileResults);
}
}
}
@@ -689,15 +697,17 @@ class _IndexRequest {
if (resultKind != null) {
int offset = index.usedElementOffsets[i];
enclosingUnitElement ??= await getEnclosingUnitElement();
Element enclosingElement =
_getEnclosingElement(enclosingUnitElement, offset);
results.add(new SearchResult._(
enclosingElement,
resultKind,
offset,
index.usedElementLengths[i],
true,
index.usedElementIsQualifiedFlags[i]));
if (enclosingUnitElement != null) {
Element enclosingElement =
_getEnclosingElement(enclosingUnitElement, offset);
results.add(new SearchResult._(
enclosingElement,
resultKind,
offset,
index.usedElementLengths[i],
true,
index.usedElementIsQualifiedFlags[i]));
}
}
}
return results;
@@ -763,10 +773,12 @@ class _IndexRequest {
if (resultKind != null) {
int offset = index.usedNameOffsets[i];
enclosingUnitElement ??= await getEnclosingUnitElement();
Element enclosingElement =
_getEnclosingElement(enclosingUnitElement, offset);
results.add(new SearchResult._(enclosingElement, resultKind, offset,
name.length, false, index.usedNameIsQualifiedFlags[i]));
if (enclosingUnitElement != null) {
Element enclosingElement =
_getEnclosingElement(enclosingUnitElement, offset);
results.add(new SearchResult._(enclosingElement, resultKind, offset,
name.length, false, index.usedNameIsQualifiedFlags[i]));
}
}
}
@@ -15,6 +15,7 @@ import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:test/test.dart';
import 'package:typed_mock/typed_mock.dart';
import '../../context/mock_sdk.dart';
@@ -51,10 +52,12 @@ class BaseAnalysisDriverTest {
final StringBuffer logBuffer = new StringBuffer();
PerformanceLog logger;
final UriResolver generatedUriResolver = new _GeneratedUriResolverMock();
AnalysisDriverScheduler scheduler;
AnalysisDriver driver;
final List<AnalysisStatus> allStatuses = <AnalysisStatus>[];
final List<AnalysisResult> allResults = <AnalysisResult>[];
final List<ExceptionResult> allExceptions = <ExceptionResult>[];
String testProject;
String testFile;
@@ -113,6 +116,7 @@ class BaseAnalysisDriverTest {
'test',
new SourceFactory([
new DartUriResolver(sdk),
generatedUriResolver,
new PackageMapUriResolver(provider, <String, List<Folder>>{
'test': [provider.getFolder(testProject)]
}),
@@ -122,6 +126,7 @@ class BaseAnalysisDriverTest {
scheduler.start();
driver.status.listen(allStatuses.add);
driver.results.listen(allResults.add);
driver.exceptions.listen(allExceptions.add);
}
String _p(String path) => provider.convertPath(path);
@@ -140,3 +145,5 @@ class _ElementVisitorFunctionWrapper extends GeneralizingElementVisitor {
super.visitElement(element);
}
}
class _GeneratedUriResolverMock extends TypedMock implements UriResolver {}
@@ -28,6 +28,7 @@ import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:typed_mock/typed_mock.dart';
import '../../context/mock_sdk.dart';
import 'base.dart';
@@ -633,6 +634,66 @@ part 'foo.dart';
expect(errors[0].errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST);
}
test_generatedFile() async {
Uri uri = Uri.parse('package:aaa/foo.dart');
String templatePath = _p('/aaa/lib/foo.dart');
String generatedPath = _p('/generated/aaa/lib/foo.dart');
provider.newFile(
templatePath,
r'''
a() {}
b() {}
''');
provider.newFile(
generatedPath,
r'''
aaa() {}
bbb() {}
''');
Source generatedSource = new _SourceMock();
when(generatedSource.uri).thenReturn(uri);
when(generatedSource.fullName).thenReturn(generatedPath);
when(generatedUriResolver.resolveAbsolute(uri, uri))
.thenReturn(generatedSource);
when(generatedUriResolver.restoreAbsolute(anyObject))
.thenInvoke((Source source) {
String path = source.fullName;
if (path == templatePath || path == generatedPath) {
return uri;
} else {
return null;
}
});
driver.addFile(templatePath);
await driver.waitForIdle();
expect(allExceptions, isEmpty);
expect(allResults, isEmpty);
var result = await driver.getResult(templatePath);
expect(result, isNull);
expect(allExceptions, isEmpty);
expect(allResults, isEmpty);
var element = await driver.getUnitElement(templatePath);
expect(element, isNull);
expect(allExceptions, isEmpty);
expect(allResults, isEmpty);
driver.priorityFiles = [templatePath];
driver.changeFile(templatePath);
await driver.waitForIdle();
expect(allExceptions, isEmpty);
expect(allResults, isEmpty);
expect(driver.knownFiles, isNot(contains(templatePath)));
}
test_getFilesReferencingName() async {
var a = _p('/test/bin/a.dart');
var b = _p('/test/bin/b.dart');
@@ -1836,3 +1897,5 @@ var A = B;
return hex.encode(md5.convert(UTF8.encode(content)).bytes);
}
}
class _SourceMock extends TypedMock implements Source {}
@@ -275,29 +275,6 @@ class A2 {}
expect(file.unlinked.classes, isEmpty);
}
test_getFileForPath_generatedFile() {
Uri uri = Uri.parse('package:aaa/foo.dart');
String templatePath = _p('/aaa/lib/foo.dart');
String generatedPath = _p('/generated/aaa/lib/foo.dart');
Source generatedSource = new _SourceMock();
when(generatedSource.fullName).thenReturn(generatedPath);
when(generatedSource.uri).thenReturn(uri);
when(generatedUriResolver.resolveAbsolute(uri, uri))
.thenReturn(generatedSource);
FileState generatedFile = fileSystemState.getFileForUri(uri);
expect(generatedFile.path, generatedPath);
expect(generatedFile.uri, uri);
FileState templateFile = fileSystemState.getFileForPath(templatePath);
expect(templateFile.path, templatePath);
expect(templateFile.uri, uri);
expect(fileSystemState.getFilesForPath(templatePath), [templateFile]);
}
test_getFileForPath_library() {
String a1 = _p('/aaa/lib/a1.dart');
String a2 = _p('/aaa/lib/a2.dart');
@@ -464,6 +441,22 @@ part 'not-a2.dart';
expect(files, [filePackageUri, fileFileUri]);
}
test_hasUri() {
Uri uri = Uri.parse('package:aaa/foo.dart');
String templatePath = _p('/aaa/lib/foo.dart');
String generatedPath = _p('/generated/aaa/lib/foo.dart');
Source generatedSource = new _SourceMock();
when(generatedSource.fullName).thenReturn(generatedPath);
when(generatedSource.uri).thenReturn(uri);
when(generatedUriResolver.resolveAbsolute(uri, uri))
.thenReturn(generatedSource);
expect(fileSystemState.hasUri(templatePath), isFalse);
expect(fileSystemState.hasUri(generatedPath), isTrue);
}
test_referencedNames() {
String path = _p('/aaa/lib/a.dart');
provider.newFile(