| OLD | NEW |
| (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 library analyzer.src.task.dart; |
| 6 |
| 7 import 'dart:collection'; |
| 8 |
| 9 import 'package:analyzer/src/generated/ast.dart'; |
| 10 import 'package:analyzer/src/generated/element.dart'; |
| 11 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; |
| 12 import 'package:analyzer/src/generated/error.dart'; |
| 13 import 'package:analyzer/src/generated/java_engine.dart'; |
| 14 import 'package:analyzer/src/generated/parser.dart'; |
| 15 import 'package:analyzer/src/generated/resolver.dart'; |
| 16 import 'package:analyzer/src/generated/scanner.dart'; |
| 17 import 'package:analyzer/src/generated/source.dart'; |
| 18 import 'package:analyzer/src/task/general.dart'; |
| 19 import 'package:analyzer/task/dart.dart'; |
| 20 import 'package:analyzer/task/general.dart'; |
| 21 import 'package:analyzer/task/model.dart'; |
| 22 |
| 23 /** |
| 24 * A task that builds a compilation unit element for a single compilation unit. |
| 25 */ |
| 26 class BuildCompilationUnitElementTask extends SourceBasedAnalysisTask { |
| 27 /** |
| 28 * The name of the input whose value is the line information for the |
| 29 * compilation unit. |
| 30 */ |
| 31 static const String LINE_INFO_INPUT_NAME = "lineInfo"; |
| 32 |
| 33 /** |
| 34 * The name of the input whose value is the AST for the compilation unit. |
| 35 */ |
| 36 static const String PARSED_UNIT_INPUT_NAME = "parsedUnit"; |
| 37 |
| 38 /** |
| 39 * The task descriptor describing this kind of task. |
| 40 */ |
| 41 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 42 'BUILD_COMPILATION_UNIT_ELEMENT', |
| 43 createTask, |
| 44 buildInputs, |
| 45 <ResultDescriptor>[COMPILATION_UNIT_ELEMENT, BUILT_UNIT]); |
| 46 |
| 47 /** |
| 48 * Initialize a newly created task to build a compilation unit element for |
| 49 * the given [target] in the given [context]. |
| 50 */ |
| 51 BuildCompilationUnitElementTask(InternalAnalysisContext context, |
| 52 AnalysisTarget target) |
| 53 : super(context, target); |
| 54 |
| 55 @override |
| 56 TaskDescriptor get descriptor => DESCRIPTOR; |
| 57 |
| 58 @override |
| 59 void internalPerform() { |
| 60 Source source = getRequiredSource(); |
| 61 CompilationUnit unit = getRequiredInput(PARSED_UNIT_INPUT_NAME); |
| 62 |
| 63 CompilationUnitBuilder builder = new CompilationUnitBuilder(); |
| 64 CompilationUnitElement element = builder.buildCompilationUnit(source, unit); |
| 65 |
| 66 outputs[COMPILATION_UNIT_ELEMENT] = element; |
| 67 outputs[BUILT_UNIT] = unit; |
| 68 } |
| 69 |
| 70 /** |
| 71 * Return a map from the names of the inputs of this kind of task to the task |
| 72 * input descriptors describing those inputs for a task with the given [target
]. |
| 73 */ |
| 74 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 75 return <String, TaskInput>{ |
| 76 PARSED_UNIT_INPUT_NAME: PARSED_UNIT.inputFor(target) |
| 77 }; |
| 78 } |
| 79 |
| 80 /** |
| 81 * Create a [BuildCompilationUnitElementTask] based on the given [target] in |
| 82 * the given [context]. |
| 83 */ |
| 84 static BuildCompilationUnitElementTask createTask(AnalysisContext context, |
| 85 AnalysisTarget target) { |
| 86 return new BuildCompilationUnitElementTask(context, target); |
| 87 } |
| 88 } |
| 89 |
| 90 /** |
| 91 * A task that parses the content of a Dart file, producing an AST structure. |
| 92 */ |
| 93 class ParseDartTask extends SourceBasedAnalysisTask { |
| 94 /** |
| 95 * The name of the input whose value is the line information produced for the |
| 96 * file. |
| 97 */ |
| 98 static const String LINE_INFO_INPUT_NAME = "lineInfo"; |
| 99 |
| 100 /** |
| 101 * The name of the input whose value is the token stream produced for the file
. |
| 102 */ |
| 103 static const String TOKEN_STREAM_INPUT_NAME = "tokenStream"; |
| 104 |
| 105 /** |
| 106 * The task descriptor describing this kind of task. |
| 107 */ |
| 108 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 109 'PARSE_DART', |
| 110 createTask, |
| 111 buildInputs, |
| 112 <ResultDescriptor>[ |
| 113 EXPORTED_LIBRARIES, |
| 114 IMPORTED_LIBRARIES, |
| 115 INCLUDED_PARTS, |
| 116 PARSE_ERRORS, |
| 117 PARSED_UNIT, |
| 118 SOURCE_KIND]); |
| 119 |
| 120 /** |
| 121 * Initialize a newly created task to parse the content of the Dart file |
| 122 * associated with the given [target] in the given [context]. |
| 123 */ |
| 124 ParseDartTask(InternalAnalysisContext context, AnalysisTarget target) |
| 125 : super(context, target); |
| 126 |
| 127 @override |
| 128 TaskDescriptor get descriptor => DESCRIPTOR; |
| 129 |
| 130 @override |
| 131 void internalPerform() { |
| 132 Source source = getRequiredSource(); |
| 133 LineInfo lineInfo = getRequiredInput(LINE_INFO_INPUT_NAME); |
| 134 Token tokenStream = getRequiredInput(TOKEN_STREAM_INPUT_NAME); |
| 135 |
| 136 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 137 Parser parser = new Parser(source, errorListener); |
| 138 AnalysisOptions options = context.analysisOptions; |
| 139 parser.parseFunctionBodies = options.analyzeFunctionBodies; |
| 140 CompilationUnit unit = parser.parseCompilationUnit(tokenStream); |
| 141 unit.lineInfo = lineInfo; |
| 142 |
| 143 bool hasNonPartOfDirective = false; |
| 144 bool hasPartOfDirective = false; |
| 145 HashSet<Source> exportedSources = new HashSet<Source>(); |
| 146 HashSet<Source> importedSources = new HashSet<Source>(); |
| 147 HashSet<Source> includedSources = new HashSet<Source>(); |
| 148 for (Directive directive in unit.directives) { |
| 149 if (directive is PartOfDirective) { |
| 150 hasPartOfDirective = true; |
| 151 } else { |
| 152 hasNonPartOfDirective = true; |
| 153 if (directive is UriBasedDirective) { |
| 154 Source referencedSource = |
| 155 resolveDirective(context, source, directive, errorListener); |
| 156 if (referencedSource != null) { |
| 157 if (directive is ExportDirective) { |
| 158 exportedSources.add(referencedSource); |
| 159 } else if (directive is ImportDirective) { |
| 160 importedSources.add(referencedSource); |
| 161 } else if (directive is PartDirective) { |
| 162 if (referencedSource != source) { |
| 163 includedSources.add(referencedSource); |
| 164 } |
| 165 } else { |
| 166 throw new AnalysisException( |
| 167 "$runtimeType failed to handle a ${directive.runtimeType}"); |
| 168 } |
| 169 } |
| 170 } |
| 171 } |
| 172 } |
| 173 SourceKind sourceKind = SourceKind.LIBRARY; |
| 174 if (!hasNonPartOfDirective && hasPartOfDirective) { |
| 175 sourceKind = SourceKind.PART; |
| 176 } |
| 177 |
| 178 outputs[EXPORTED_LIBRARIES] = exportedSources.toList(); |
| 179 outputs[IMPORTED_LIBRARIES] = importedSources.toList(); |
| 180 outputs[INCLUDED_PARTS] = includedSources.toList(); |
| 181 outputs[PARSE_ERRORS] = errorListener.getErrorsForSource(source); |
| 182 outputs[PARSED_UNIT] = unit; |
| 183 outputs[SOURCE_KIND] = sourceKind; |
| 184 } |
| 185 |
| 186 /** |
| 187 * Return a map from the names of the inputs of this kind of task to the task |
| 188 * input descriptors describing those inputs for a task with the given [target
]. |
| 189 */ |
| 190 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 191 return <String, TaskInput>{ |
| 192 LINE_INFO_INPUT_NAME: LINE_INFO.inputFor(target), |
| 193 TOKEN_STREAM_INPUT_NAME: TOKEN_STREAM.inputFor(target) |
| 194 }; |
| 195 } |
| 196 |
| 197 /** |
| 198 * Create a [ParseDartTask] based on the given [target] in the given |
| 199 * [context]. |
| 200 */ |
| 201 static ParseDartTask createTask(AnalysisContext context, |
| 202 AnalysisTarget target) { |
| 203 return new ParseDartTask(context, target); |
| 204 } |
| 205 |
| 206 /** |
| 207 * Return the result of resolving the URI of the given URI-based [directive] |
| 208 * against the URI of the given library, or `null` if the URI is not valid. |
| 209 * |
| 210 * Resolution is to be performed in the given [context]. Errors should be |
| 211 * reported to the [errorListener]. |
| 212 */ |
| 213 static Source resolveDirective(AnalysisContext context, Source librarySource, |
| 214 UriBasedDirective directive, AnalysisErrorListener errorListener) { |
| 215 StringLiteral uriLiteral = directive.uri; |
| 216 String uriContent = uriLiteral.stringValue; |
| 217 if (uriContent != null) { |
| 218 uriContent = uriContent.trim(); |
| 219 directive.uriContent = uriContent; |
| 220 } |
| 221 UriValidationCode code = directive.validate(); |
| 222 if (code == null) { |
| 223 String encodedUriContent = Uri.encodeFull(uriContent); |
| 224 Source source = |
| 225 context.sourceFactory.resolveUri(librarySource, encodedUriContent); |
| 226 directive.source = source; |
| 227 return source; |
| 228 } |
| 229 if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) { |
| 230 return null; |
| 231 } |
| 232 if (code == UriValidationCode.URI_WITH_INTERPOLATION) { |
| 233 errorListener.onError( |
| 234 new AnalysisError.con2( |
| 235 librarySource, |
| 236 uriLiteral.offset, |
| 237 uriLiteral.length, |
| 238 CompileTimeErrorCode.URI_WITH_INTERPOLATION)); |
| 239 return null; |
| 240 } |
| 241 if (code == UriValidationCode.INVALID_URI) { |
| 242 errorListener.onError( |
| 243 new AnalysisError.con2( |
| 244 librarySource, |
| 245 uriLiteral.offset, |
| 246 uriLiteral.length, |
| 247 CompileTimeErrorCode.INVALID_URI, |
| 248 [uriContent])); |
| 249 return null; |
| 250 } |
| 251 throw new AnalysisException('Failed to handle validation code: $code'); |
| 252 } |
| 253 } |
| 254 |
| 255 /** |
| 256 * A task that scans the content of a file, producing a set of Dart tokens. |
| 257 */ |
| 258 class ScanDartTask extends SourceBasedAnalysisTask { |
| 259 /** |
| 260 * The name of the input whose value is the content of the file. |
| 261 */ |
| 262 static const String CONTENT_INPUT_NAME = "content"; |
| 263 |
| 264 /** |
| 265 * The task descriptor describing this kind of task. |
| 266 */ |
| 267 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 268 'SCAN_DART', |
| 269 createTask, |
| 270 buildInputs, |
| 271 <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM]); |
| 272 |
| 273 /** |
| 274 * Initialize a newly created task to access the content of the source |
| 275 * associated with the given [target] in the given [context]. |
| 276 */ |
| 277 ScanDartTask(InternalAnalysisContext context, AnalysisTarget target) |
| 278 : super(context, target); |
| 279 |
| 280 @override |
| 281 TaskDescriptor get descriptor => DESCRIPTOR; |
| 282 |
| 283 @override |
| 284 void internalPerform() { |
| 285 Source source = getRequiredSource(); |
| 286 String content = getRequiredInput(CONTENT_INPUT_NAME); |
| 287 |
| 288 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 289 Scanner scanner = |
| 290 new Scanner(source, new CharSequenceReader(content), errorListener); |
| 291 scanner.preserveComments = context.analysisOptions.preserveComments; |
| 292 outputs[TOKEN_STREAM] = scanner.tokenize(); |
| 293 outputs[LINE_INFO] = new LineInfo(scanner.lineStarts); |
| 294 outputs[SCAN_ERRORS] = errorListener.getErrorsForSource(source); |
| 295 } |
| 296 |
| 297 /** |
| 298 * Return a map from the names of the inputs of this kind of task to the task |
| 299 * input descriptors describing those inputs for a task with the given [target
]. |
| 300 */ |
| 301 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 302 return <String, TaskInput>{ |
| 303 CONTENT_INPUT_NAME: CONTENT.inputFor(target) |
| 304 }; |
| 305 } |
| 306 |
| 307 /** |
| 308 * Create a [ScanDartTask] based on the given [target] in the given [context]. |
| 309 */ |
| 310 static ScanDartTask createTask(AnalysisContext context, |
| 311 AnalysisTarget target) { |
| 312 return new ScanDartTask(context, target); |
| 313 } |
| 314 } |
| OLD | NEW |