Linter Demo Errors: 18Warnings: 28File: /home/fstrocco/Dart/dart/benchmark/compiler/lib/src/dart_backend/outputter.dart // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. part of dart_backend; typedef bool IsSafeToRemoveTypeDeclarations( Map> classMembers); typedef void ElementCallback(E element); typedef void ElementPostProcessFunction( AstElement element, ElementAst elementAst, ElementCallback typedefCallback, ElementCallback classCallback); typedef ElementAst ComputeElementAstFunction(AstElement element); typedef bool ElementFilter(Element element); typedef List ElementSorter(Iterable elements); /// Output engine for dart2dart that is shared between the dart2js and the /// analyzer implementations of dart2dart. class DartOutputter { final DiagnosticListener listener; final CompilerOutputProvider outputProvider; final bool forceStripTypes; // TODO(antonm): make available from command-line options. final bool outputAst = false; final bool enableMinification; /// If `true`, libraries are generated into separate files. final bool multiFile; /// Internal structures accessible for tests and logging. // TODO(johnniwinther): Clean this up. PlaceholderRenamer renamer; MainOutputGenerator output; LibraryInfo libraryInfo; ElementInfo elementInfo; // TODO(johnniwinther): Support recompilation. DartOutputter(this.listener, this.outputProvider, {bool this.forceStripTypes: false, bool this.enableMinification: false, bool this.multiFile: false}); /// Generate Dart code for the program starting at [mainFunction]. /// /// [libraries] is the set of all libraries (user/package/sdk) that are /// referenced in the program. /// /// [instantiatedClasses] is the set of classes that are potentially /// instantiated in the program. /// /// [resolvedElements] is the set of methods, constructors, and fields that /// are potentially accessed/called in the program. /// /// The [sortElements] function is used to sort [instantiatedClasses] and /// [resolvedElements] in the generated output. /// /// Returns the total size of the generated code. int assembleProgram({ MirrorRenamer mirrorRenamer: const MirrorRenamer(), Iterable libraries, Iterable instantiatedClasses, Iterable resolvedElements, Iterable usedTypeLiterals: const [], FunctionElement mainFunction, Uri outputUri, ElementPostProcessFunction postProcessElementAst, ComputeElementAstFunction computeElementAst, ElementFilter shouldOutput, IsSafeToRemoveTypeDeclarations isSafeToRemoveTypeDeclarations, ElementSorter sortElements}) { assert(invariant(NO_LOCATION_SPANNABLE, libraries != null, message: "'libraries' must be non-null.")); assert(invariant(NO_LOCATION_SPANNABLE, instantiatedClasses != null, message: "'instantiatedClasses' must be non-null.")); assert(invariant(NO_LOCATION_SPANNABLE, resolvedElements != null, message: "'resolvedElements' must be non-null.")); assert(invariant(NO_LOCATION_SPANNABLE, mainFunction != null, message: "'mainFunction' must be non-null.")); assert(invariant(NO_LOCATION_SPANNABLE, computeElementAst != null, message: "'computeElementAst' must be non-null.")); assert(invariant(NO_LOCATION_SPANNABLE, shouldOutput != null, message: "'shouldOutput' must be non-null.")); assert(invariant(NO_LOCATION_SPANNABLE, isSafeToRemoveTypeDeclarations != null, message: "'isSafeToRemoveTypeDeclarations' must be non-null.")); if (sortElements == null) { // Ensure deterministic output order. sortElements = (Iterable elements) { List list = elements.toList(); list.sort((Element a, Element b) => a.name.compareTo(b.name)); return list; }; } libraryInfo = LibraryInfo.processLibraries( listener, libraries, resolvedElements); elementInfo = ElementInfoProcessor.createElementInfo( instantiatedClasses, resolvedElements, usedTypeLiterals, postProcessElementAst: postProcessElementAst, parseElementAst: computeElementAst, shouldOutput: shouldOutput, sortElements: sortElements); PlaceholderCollector collector = collectPlaceholders( listener, mirrorRenamer, mainFunction, libraryInfo, elementInfo); renamer = createRenamer( collector, libraryInfo, elementInfo, enableMinification: enableMinification, forceStripTypes: forceStripTypes, isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations); if (outputAst) { String code = astOutput(listener, elementInfo); outputProvider("", "dart") ..add(code) ..close(); return code.length; } else { output = new MainOutputGenerator(); return output.generateCode( libraryInfo, elementInfo, collector, renamer, mainFunction, outputUri, outputProvider, mirrorRenamer, multiFile: multiFile, forceStripTypes: forceStripTypes, enableMinification: enableMinification); } } static PlaceholderCollector collectPlaceholders( DiagnosticListener listener, MirrorRenamer mirrorRenamer, FunctionElement mainFunction, LibraryInfo libraryInfo, ElementInfo elementInfo) { // Create all necessary placeholders. PlaceholderCollector collector = new PlaceholderCollector( listener, mirrorRenamer, libraryInfo.fixedDynamicNames, elementInfo.elementAsts, mainFunction); makePlaceholders(element) { collector.collect(element); if (element.isClass && !element.isEnumClass) { elementInfo.classMembers[element].forEach(makePlaceholders); } } elementInfo.topLevelElements.forEach(makePlaceholders); return collector; } static PlaceholderRenamer createRenamer( PlaceholderCollector collector, LibraryInfo libraryInfo, ElementInfo elementInfo, {bool enableMinification: false, bool forceStripTypes: false, isSafeToRemoveTypeDeclarations}) { // Create renames. bool shouldCutDeclarationTypes = forceStripTypes || (enableMinification && isSafeToRemoveTypeDeclarations(elementInfo.classMembers)); PlaceholderRenamer placeholderRenamer = new PlaceholderRenamer( libraryInfo.fixedDynamicNames, libraryInfo.fixedStaticNames, libraryInfo.reexportingLibraries, cutDeclarationTypes: shouldCutDeclarationTypes, enableMinification: enableMinification); placeholderRenamer.computeRenames(collector); return placeholderRenamer; } static String astOutput(DiagnosticListener listener, ElementInfo elementInfo) { // TODO(antonm): Ideally XML should be a separate backend. // TODO(antonm): obey renames and minification, at least as an option. StringBuffer sb = new StringBuffer(); outputElement(element) { sb.write(element.parseNode(listener).toDebugString()); } // Emit XML for AST instead of the program. for (Element topLevel in elementInfo.topLevelElements) { if (topLevel.isClass && !elementInfo.emitNoMembersFor.contains(topLevel)) { // TODO(antonm): add some class info. elementInfo.classMembers[topLevel].forEach(outputElement); } else { outputElement(topLevel); } } return '\n$sb\n'; } } class LibraryInfo { final Set fixedStaticNames; final Set fixedDynamicNames; final Map reexportingLibraries; final List userLibraries; LibraryInfo(this.fixedStaticNames, this.fixedDynamicNames, this.reexportingLibraries, this.userLibraries); static LibraryInfo processLibraries( DiagnosticListener listener, Iterable libraries, Iterable resolvedElements) { Set fixedStaticNames = new Set(); Set fixedDynamicNames = new Set(); Map reexportingLibraries = {}; List userLibraries = []; // Conservatively traverse all platform libraries and collect member names. // TODO(antonm): ideally we should only collect names of used members, // however as of today there are problems with names of some core library // interfaces, most probably for interfaces of literals. for (LibraryElement library in libraries) { if (!library.isPlatformLibrary) { userLibraries.add(library); continue; } library.forEachLocalMember((Element element) { if (element.isClass) { ClassElement classElement = element; assert(invariant(classElement, classElement.isResolved, message: "Unresolved platform class.")); classElement.forEachLocalMember((member) { if (member.isInstanceMember) { fixedDynamicNames.add(member.name); } else { fixedStaticNames.add(member.name); } }); } // Even class names are added due to a delicate problem we have: // if one imports dart:core with a prefix, we cannot tell prefix.name // from dynamic invocation (alas!). So we'd better err on preserving // those names. fixedStaticNames.add(element.name); }); for (Element export in library.exports) { if (!library.isInternalLibrary && export.library.isInternalLibrary) { // If an element of an internal library is reexported by a platform // library, we have to import the reexporting library instead of the // internal library, because the internal library is an // implementation detail of dart2js. reexportingLibraries[export] = library; } } } // Map to keep track of names of enum classes. Since these cannot be renamed // we ensure that they are unique. Map enumClassMap = {}; // As of now names of named optionals are not renamed. Therefore add all // field names used as named optionals into [fixedMemberNames]. for (final element in resolvedElements) { if (!element.isConstructor) continue; for (ParameterElement parameter in element.parameters) { if (parameter.isInitializingFormal && parameter.isNamed) { fixedDynamicNames.add(parameter.name); } } ClassElement cls = element.enclosingClass; if (cls != null && cls.isEnumClass) { fixedDynamicNames.add('index'); ClassElement existingEnumClass = enumClassMap.putIfAbsent(cls.name, () => cls); if (existingEnumClass != cls) { listener.reportError(cls, MessageKind.GENERIC, {'text': "Duplicate enum names are not supported in dart2dart."}); listener.reportInfo(existingEnumClass, MessageKind.GENERIC, {'text': "This is the other declaration of '${cls.name}'."}); } } } fixedStaticNames.addAll(enumClassMap.keys); // The VM will automatically invoke the call method of objects // that are invoked as functions. Make sure to not rename that. fixedDynamicNames.add('call'); return new LibraryInfo( fixedStaticNames, fixedDynamicNames, reexportingLibraries, userLibraries); } } class ElementInfo { final Map elementAsts; final Iterable topLevelElements; final Map> classMembers; final Iterable emitNoMembersFor; ElementInfo(this.elementAsts, this.topLevelElements, this.classMembers, this.emitNoMembersFor); } class ElementInfoProcessor implements ElementInfo { final Map elementAsts = new Map(); final Set topLevelElements = new Set(); final Map> classMembers = new Map>(); final Set emitNoMembersFor = new Set(); final ElementPostProcessFunction postProcessElementAst; final ComputeElementAstFunction parseElementAst; final ElementFilter shouldOutput; ElementInfoProcessor( {this.postProcessElementAst, this.parseElementAst, this.shouldOutput}); static ElementInfo createElementInfo( Iterable instantiatedClasses, Iterable resolvedElements, Iterable usedTypeLiterals, {ElementPostProcessFunction postProcessElementAst, ComputeElementAstFunction parseElementAst, ElementFilter shouldOutput, ElementSorter sortElements}) { ElementInfoProcessor processor = new ElementInfoProcessor( postProcessElementAst: postProcessElementAst, parseElementAst: parseElementAst, shouldOutput: shouldOutput); return processor.process( instantiatedClasses, resolvedElements, usedTypeLiterals, sortElements: sortElements); } ElementInfo process(Iterable instantiatedClasses, Iterable resolvedElements, Iterable usedTypeLiterals, {ElementSorter sortElements}) { // Build all top level elements to emit and necessary class members. instantiatedClasses.where(shouldOutput).forEach(addClass); resolvedElements.where(shouldOutput).forEach(addMember); usedTypeLiterals.forEach((ClassElement element) { if (shouldOutput(element)) { if (!topLevelElements.contains(element)) { // The class is only referenced by type literals. emitNoMembersFor.add(element); } addClass(element); } }); // Sort elements. List sortedTopLevels = sortElements(topLevelElements); Map> sortedClassMembers = new Map>(); classMembers.forEach((classElement, members) { sortedClassMembers[classElement] = sortElements(members); }); return new ElementInfo( elementAsts, sortedTopLevels, sortedClassMembers, emitNoMembersFor); } void processElement(Element element, ElementAst elementAst) { if (postProcessElementAst != null) { postProcessElementAst(element, elementAst, newTypedefElementCallback, newClassElementCallback); } elementAsts[element] = elementAst; } void addTopLevel(AstElement element, ElementAst elementAst) { if (topLevelElements.contains(element)) return; topLevelElements.add(element); processElement(element, elementAst); } void addClass(ClassElement classElement) { TreeElements treeElements = new TreeElementMapping(classElement); backend2frontend.TreePrinter treePrinter = new backend2frontend.TreePrinter(treeElements); Node node = treePrinter.makeNodeForClassElement(classElement); addTopLevel(classElement, new ElementAst(node, treeElements)); classMembers.putIfAbsent(classElement, () => new Set()); } void newTypedefElementCallback(TypedefElement element) { if (!shouldOutput(element)) return; TreeElements treeElements = new TreeElementMapping(element); backend2frontend.TreePrinter treePrinter = new backend2frontend.TreePrinter(treeElements); Node node = treePrinter.makeTypedef(element); addTopLevel(element, new ElementAst(node, treeElements)); } void newClassElementCallback(ClassElement classElement) { if (!shouldOutput(classElement)) return; addClass(classElement); } void addMember(element) { if (element.isClassMember) { ClassElement enclosingClass = element.enclosingClass; assert(enclosingClass.isClass); assert(shouldOutput(enclosingClass)); addClass(enclosingClass); classMembers[enclosingClass].add(element); if (enclosingClass.isEnumClass) return; processElement(element, parseElementAst(element)); } else { if (element.isTopLevel) { addTopLevel(element, parseElementAst(element)); } } } } /// Main output generator for [DartOutputter] that emits dart code through a /// [CompilerOutputProvider]. class MainOutputGenerator { final Map> memberNodes = new Map>(); final List topLevelNodes = []; /// Generates the code and returns the total size. int generateCode( LibraryInfo libraryInfo, ElementInfo elementInfo, PlaceholderCollector collector, PlaceholderRenamer placeholderRenamer, FunctionElement mainFunction, Uri outputUri, CompilerOutputProvider outputProvider, MirrorRenamer mirrorRenamer, {bool multiFile: false, bool forceStripTypes: false, bool enableMinification: false}) { for (Element element in elementInfo.topLevelElements) { topLevelNodes.add(elementInfo.elementAsts[element].ast); if (element.isClass) { ClassElement cls = element; if (cls.isMixinApplication || cls.isEnumClass) { continue; } final members = []; for (Element member in elementInfo.classMembers[cls]) { members.add(elementInfo.elementAsts[member].ast); } memberNodes[elementInfo.elementAsts[cls].ast] = members; } } mirrorRenamer.addRenames(placeholderRenamer.renames, topLevelNodes, collector); Map outputPaths = new Map(); Map unparsers = new Map(); // The single unparser used if we collect all the output in one file. EmitterUnparser mainUnparser = multiFile ? null : new EmitterUnparser(placeholderRenamer.renames, stripTypes: forceStripTypes, minify: enableMinification); if (multiFile) { // TODO(sigurdm): Factor handling of library-paths out from emitting. String mainName = outputUri.pathSegments.last; String mainBaseName = mainName.endsWith(".dart") ? mainName.substring(0, mainName.length - 5) : mainName; // Map each library to a path based on the uri of the original // library and [compiler.outputUri]. Set usedLibraryPaths = new Set(); for (LibraryElement library in libraryInfo.userLibraries) { if (library == mainFunction.library) { outputPaths[library] = mainBaseName; } else { List names = library.canonicalUri.pathSegments.last.split("."); if (names.last == "dart") { names = names.sublist(0, names.length - 1); } outputPaths[library] = "$mainBaseName.${makeUnique(names.join("."), usedLibraryPaths)}"; } } /// Rewrites imports/exports to refer to the paths given in [outputPaths]. for(LibraryElement outputLibrary in libraryInfo.userLibraries) { EmitterUnparser unparser = new EmitterUnparser( placeholderRenamer.renames, stripTypes: forceStripTypes, minify: enableMinification); unparsers[outputLibrary] = unparser; LibraryName libraryName = outputLibrary.libraryTag; if (libraryName != null) { unparser.visitLibraryName(libraryName); } for (LibraryTag tag in outputLibrary.tags) { if (tag is! LibraryDependency) continue; LibraryDependency dependency = tag; LibraryElement libraryElement = outputLibrary.getLibraryFromTag(dependency); String uri = outputPaths.containsKey(libraryElement) ? "${outputPaths[libraryElement]}.dart" : libraryElement.canonicalUri.toString(); if (dependency is Import) { unparser.unparseImportTag(uri); } else { unparser.unparseExportTag(uri); } } } } else { placeholderRenamer.platformImports.forEach( (LibraryElement library, String prefix) { assert(library.isPlatformLibrary && !library.isInternalLibrary); mainUnparser.unparseImportTag(library.canonicalUri.toString()); if (prefix != null) { // Adding a prefixed import because (some) top-level access need // it to avoid shadowing. // TODO(johnniwinther): Avoid prefix-less import if not needed. mainUnparser.unparseImportTag(library.canonicalUri.toString(), prefix: prefix); } }); } for (int i = 0; i < elementInfo.topLevelElements.length; i++) { Element element = elementInfo.topLevelElements.elementAt(i); Node node = topLevelNodes[i]; Unparser unparser = multiFile ? unparsers[element.library] : mainUnparser; if (node is ClassNode) { // TODO(smok): Filter out default constructors here. unparser.unparseClassWithBody(node, memberNodes[node]); } else { unparser.unparse(node); } unparser.newline(); } int totalSize = 0; if (multiFile) { for(LibraryElement outputLibrary in libraryInfo.userLibraries) { // TODO(sigurdm): Make the unparser output directly into the buffer // instead of caching in `.result`. String code = unparsers[outputLibrary].result; totalSize += code.length; outputProvider(outputPaths[outputLibrary], "dart") ..add(code) ..close(); } } else { String code = mainUnparser.result; outputProvider("", "dart") ..add(code) ..close(); totalSize = code.length; } return totalSize; } }