Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: pkg/analyzer/lib/src/lint/analysis.dart

Issue 2559773002: Reapply "Move the linter core to the analyzer package" (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:collection';
6 import 'dart:io' as io;
7
8 import 'package:analyzer/dart/element/element.dart';
9 import 'package:analyzer/file_system/file_system.dart'
10 show File, Folder, ResourceProvider, ResourceUriResolver;
11 import 'package:analyzer/file_system/physical_file_system.dart';
12 import 'package:analyzer/source/package_map_resolver.dart';
13 import 'package:analyzer/src/context/builder.dart';
14 import 'package:analyzer/src/dart/sdk/sdk.dart';
15 import 'package:analyzer/src/generated/engine.dart';
16 import 'package:analyzer/src/generated/sdk.dart';
17 import 'package:analyzer/src/generated/source.dart';
18 import 'package:analyzer/src/generated/source_io.dart';
19 import 'package:analyzer/src/lint/io.dart';
20 import 'package:analyzer/src/lint/linter.dart';
21 import 'package:analyzer/src/lint/project.dart';
22 import 'package:analyzer/src/lint/registry.dart';
23 import 'package:analyzer/src/services/lint.dart';
24 import 'package:cli_util/cli_util.dart' as cli_util;
25 import 'package:package_config/packages.dart' show Packages;
26 import 'package:package_config/packages_file.dart' as pkgfile show parse;
27 import 'package:package_config/src/packages_impl.dart' show MapPackages;
28 import 'package:path/path.dart' as p;
29 import 'package:plugin/manager.dart';
30 import 'package:plugin/plugin.dart';
31
32 Source createSource(Uri sourceUri) {
33 return PhysicalResourceProvider.INSTANCE
34 .getFile(sourceUri.toFilePath())
35 .createSource(sourceUri);
36 }
37
38 /// Print the given message and exit with the given [exitCode]
39 void printAndFail(String message, {int exitCode: 15}) {
40 print(message);
41 io.exit(exitCode);
42 }
43
44 AnalysisOptions _buildAnalyzerOptions(DriverOptions options) {
45 AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl();
46 analysisOptions.strongMode = options.strongMode;
47 analysisOptions.hint = false;
48 analysisOptions.lint = options.enableLints;
49 analysisOptions.generateSdkErrors = options.showSdkWarnings;
50 analysisOptions.enableTiming = options.enableTiming;
51 return analysisOptions;
52 }
53
54 class AnalysisDriver {
55 /// The sources which have been analyzed so far. This is used to avoid
56 /// analyzing a source more than once, and to compute the total number of
57 /// sources analyzed for statistics.
58 Set<Source> _sourcesAnalyzed = new HashSet<Source>();
59
60 final LinterOptions options;
61
62 AnalysisDriver(this.options) {
63 _processPlugins();
64 }
65
66 /// Return the number of sources that have been analyzed so far.
67 int get numSourcesAnalyzed => _sourcesAnalyzed.length;
68
69 List<UriResolver> get resolvers {
70 // TODO(brianwilkerson) Use the context builder to compute all of the resolv ers.
71 ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
72 ContextBuilder builder = new ContextBuilder(resourceProvider, null, null);
73
74 DartSdk sdk = options.mockSdk ??
75 new FolderBasedDartSdk(
76 resourceProvider, resourceProvider.getFolder(sdkDir));
77
78 List<UriResolver> resolvers = [new DartUriResolver(sdk)];
79
80 if (options.packageRootPath != null) {
81 // TODO(brianwilkerson) After 0.30.0 is published, clean up the following.
82 try {
83 // Try to use the post 0.30.0 API.
84 (builder as dynamic).builderOptions.defaultPackagesDirectoryPath =
85 options.packageRootPath;
86 } catch (_) {
87 // If that fails, fall back to the pre 0.30.0 API.
88 (builder as dynamic).defaultPackagesDirectoryPath =
89 options.packageRootPath;
90 }
91 Map<String, List<Folder>> packageMap =
92 builder.convertPackagesToMap(builder.createPackageMap(null));
93 resolvers.add(new PackageMapUriResolver(resourceProvider, packageMap));
94 }
95
96 // File URI resolver must come last so that files inside "/lib" are
97 // are analyzed via "package:" URI's.
98 resolvers.add(new ResourceUriResolver(resourceProvider));
99 return resolvers;
100 }
101
102 String get sdkDir {
103 if (options.dartSdkPath != null) {
104 return options.dartSdkPath;
105 }
106 // In case no SDK has been specified, fall back to inferring it
107 // TODO: pass args to cli_util
108 return cli_util.getSdkDir().path;
109 }
110
111 List<AnalysisErrorInfo> analyze(Iterable<io.File> files) {
112 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
113 context.analysisOptions = _buildAnalyzerOptions(options);
114 registerLinters(context);
115
116 Packages packages = _getPackageConfig();
117
118 context.sourceFactory = new SourceFactory(resolvers, packages);
119 AnalysisEngine.instance.logger = new StdLogger();
120
121 List<Source> sources = [];
122 ChangeSet changeSet = new ChangeSet();
123 for (io.File file in files) {
124 File sourceFile = PhysicalResourceProvider.INSTANCE
125 .getFile(p.normalize(file.absolute.path));
126 Source source = sourceFile.createSource();
127 Uri uri = context.sourceFactory.restoreUri(source);
128 if (uri != null) {
129 // Ensure that we analyze the file using its canonical URI (e.g. if
130 // it's in "/lib", analyze it using a "package:" URI).
131 source = sourceFile.createSource(uri);
132 }
133 sources.add(source);
134 changeSet.addedSource(source);
135 }
136 context.applyChanges(changeSet);
137
138 // Temporary location
139 var project = new DartProject(context, sources);
140 // This will get pushed into the generator (or somewhere comparable) when
141 // we have a proper plugin.
142 Registry.ruleRegistry.forEach((lint) {
143 if (lint is ProjectVisitor) {
144 (lint as ProjectVisitor).visit(project);
145 }
146 });
147
148 List<AnalysisErrorInfo> errors = [];
149
150 for (Source source in sources) {
151 context.computeErrors(source);
152 errors.add(context.getErrors(source));
153 _sourcesAnalyzed.add(source);
154 }
155
156 if (options.visitTransitiveClosure) {
157 // In the process of computing errors for all the sources in [sources],
158 // the analyzer has visited the transitive closure of all libraries
159 // referenced by those sources. So now we simply need to visit all
160 // library sources known to the analysis context, and all parts they
161 // refer to.
162 for (Source librarySource in context.librarySources) {
163 for (Source source in _getAllUnitSources(context, librarySource)) {
164 if (!_sourcesAnalyzed.contains(source)) {
165 context.computeErrors(source);
166 errors.add(context.getErrors(source));
167 _sourcesAnalyzed.add(source);
168 }
169 }
170 }
171 }
172
173 return errors;
174 }
175
176 void registerLinters(AnalysisContext context) {
177 if (options.enableLints) {
178 setLints(context, options.enabledLints?.toList(growable: false));
179 }
180 }
181
182 /// Yield the sources for all the compilation units constituting
183 /// [librarySource] (including the defining compilation unit).
184 Iterable<Source> _getAllUnitSources(
185 AnalysisContext context, Source librarySource) {
186 List<Source> result = <Source>[librarySource];
187 result.addAll(context
188 .getLibraryElement(librarySource)
189 .parts
190 .map((CompilationUnitElement e) => e.source));
191 return result;
192 }
193
194 Packages _getPackageConfig() {
195 if (options.packageConfigPath != null) {
196 String packageConfigPath = options.packageConfigPath;
197 Uri fileUri = new Uri.file(packageConfigPath);
198 try {
199 io.File configFile = new io.File.fromUri(fileUri).absolute;
200 List<int> bytes = configFile.readAsBytesSync();
201 Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);
202 return new MapPackages(map);
203 } catch (e) {
204 printAndFail(
205 'Unable to read package config data from $packageConfigPath: $e');
206 }
207 }
208 return null;
209 }
210
211 void _processPlugins() {
212 List<Plugin> plugins = <Plugin>[];
213 plugins.addAll(AnalysisEngine.instance.requiredPlugins);
214 plugins.add(AnalysisEngine.instance.commandLinePlugin);
215 plugins.add(AnalysisEngine.instance.optionsPlugin);
216 ExtensionManager manager = new ExtensionManager();
217 manager.processPlugins(plugins);
218 }
219 }
220
221 class DriverOptions {
222 /// The maximum number of sources for which AST structures should be kept
223 /// in the cache. The default is 512.
224 int cacheSize = 512;
225
226 /// The path to the dart SDK.
227 String dartSdkPath;
228
229 /// Whether to show lint warnings.
230 bool enableLints = true;
231
232 /// Whether to gather timing data during analysis.
233 bool enableTiming = false;
234
235 /// The path to a `.packages` configuration file
236 String packageConfigPath;
237
238 /// The path to the package root.
239 String packageRootPath;
240
241 /// Whether to show SDK warnings.
242 bool showSdkWarnings = false;
243
244 /// Whether to use Dart's Strong Mode analyzer.
245 bool strongMode = true;
246
247 /// The mock SDK (to speed up testing) or `null` to use the actual SDK.
248 DartSdk mockSdk;
249
250 /// Whether to show lints for the transitive closure of imported and exported
251 /// libraries.
252 bool visitTransitiveClosure = false;
253 }
254
255 /// Prints logging information comments to the [outSink] and error messages to
256 /// [errorSink].
257 class StdLogger extends Logger {
258 @override
259 void logError(String message, [exception]) => errorSink.writeln(message);
260 @override
261 void logInformation(String message, [exception]) => outSink.writeln(message);
262 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/test/services/linter/linter_test.dart ('k') | pkg/analyzer/lib/src/lint/config.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698