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