From ecbd1874bf2055d69808367b7cccbc7485df96dd Mon Sep 17 00:00:00 2001 From: "scheglov@google.com" Date: Wed, 1 Feb 2012 17:47:04 +0000 Subject: [PATCH] Recompile unit with potential conflict/dependency on some top-level symbol. 1. Change dependency tracking from API version on unit to just unit last modified time. 2. Track sets of top-level and all declared symbols in units, recompile in case of possible conflict. 3. Track units with TypeErrorCode.CANNOT_BE_RESOLVED, recompile if any unit changes top-level symbols. 4. Better tests with source code directly in test method. R=zundel@google.com BUG= TEST= Review URL: https://chromiumcodereview.appspot.com//9148026 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@3799 260f80e4-7a28-3924-810f-c04153c831b5 --- .../google/dart/compiler/DartCompiler.java | 229 ++++--- .../dart/compiler/DartCompilerErrorCode.java | 5 + .../compiler/DartCompilerMainContext.java | 32 + .../compiler/DefaultDartArtifactProvider.java | 2 +- .../google/dart/compiler/DeltaAnalyzer.java | 1 - .../com/google/dart/compiler/ErrorCode.java | 6 + .../com/google/dart/compiler/LibraryDeps.java | 341 +++++++--- .../dart/compiler/LibraryDepsVisitor.java | 69 +- .../google/dart/compiler/ast/DartClass.java | 21 - .../google/dart/compiler/ast/DartField.java | 15 - .../google/dart/compiler/ast/DartNode.java | 18 - .../compiler/ast/DartToSourceVisitor.java | 17 - .../google/dart/compiler/ast/DartUnit.java | 86 ++- .../google/dart/compiler/ast/LibraryNode.java | 5 +- .../google/dart/compiler/ast/LibraryUnit.java | 208 ------ .../doc/DartDocumentationGenerator.java | 17 +- .../backend/js/ClosureJsErrorCode.java | 5 + .../dart/compiler/backend/js/JsErrorCode.java | 5 + .../dart/compiler/parser/DartParser.java | 37 +- .../dart/compiler/parser/ParserErrorCode.java | 5 + .../compiler/resolver/ResolverErrorCode.java | 23 +- .../dart/compiler/resolver/TypeErrorCode.java | 27 +- .../compiler/MockBundleLibrarySource.java | 1 + .../TypeHeuristicImplementationTest.java | 10 +- .../compiler/common/ErrorExpectation.java | 77 ++- .../dart/compiler/end2end/End2EndTests.java | 2 + .../inc/IncrementalCompilation2Test.java | 561 ++++++++++++++++ .../inc/IncrementalCompilationTest.java | 624 ++++++++---------- .../IncrementalCompilationWithPrefixTest.java | 30 +- .../end2end/inc/MemoryLibrarySource.java | 108 +++ .../dart/compiler/end2end/inc/my.app.dart | 2 +- .../compiler/parser/AbstractParserTest.java | 6 +- .../compiler/parser/NegativeParserTest.java | 91 +++ .../resolver/NegativeResolverTest.java | 10 + .../type/TypeAnalyzerCompilerTest.java | 34 + 35 files changed, 1735 insertions(+), 995 deletions(-) create mode 100644 compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilation2Test.java create mode 100644 compiler/javatests/com/google/dart/compiler/end2end/inc/MemoryLibrarySource.java diff --git a/compiler/java/com/google/dart/compiler/DartCompiler.java b/compiler/java/com/google/dart/compiler/DartCompiler.java index 6aff5e63ec0..8287ea5c92f 100644 --- a/compiler/java/com/google/dart/compiler/DartCompiler.java +++ b/compiler/java/com/google/dart/compiler/DartCompiler.java @@ -5,6 +5,8 @@ package com.google.dart.compiler; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.collect.Sets.SetView; import com.google.common.io.CharStreams; import com.google.common.io.Closeables; import com.google.common.io.Files; @@ -69,7 +71,6 @@ import java.util.Set; */ public class DartCompiler { - public static final String EXTENSION_API = "api"; public static final String EXTENSION_DEPS = "deps"; public static final String EXTENSION_LOG = "log"; @@ -230,9 +231,8 @@ public class DartCompiler { } /** - * This method reads all libraries, updating their apis as necessary. They - * will be populated from some combination of fully-parsed compilation units - * and api files. + * This method reads all libraries. They will be populated from some combination of fully-parsed + * and diet-parser compilation units. */ private void parseOutOfDateFiles() throws IOException { TraceEvent logEvent = @@ -241,17 +241,21 @@ public class DartCompiler { long parseStart = compilerMetrics != null ? CompilerMetrics.getCPUTime() : 0; try { + final Set topLevelSymbolsDiff = Sets.newHashSet(); for (LibraryUnit lib : libraries.values()) { LibrarySource libSrc = lib.getSource(); - boolean libIsDartUri = SystemLibraryManager.isDartUri(libSrc.getUri()); - LibraryUnit apiLib = new LibraryUnit(libSrc); LibraryNode selfSourcePath = lib.getSelfSourcePath(); - boolean shouldLoadApi = incremental || (libIsDartUri && usePrecompiledDartLibs); - boolean apiOutOfDate = !(shouldLoadApi && apiLib.loadApi(context, context)); + boolean libIsDartUri = SystemLibraryManager.isDartUri(libSrc.getUri()); - // Parse each compilation unit and update the API to reflect its contents. + // Load the existing DEPS, or create an empty one. + LibraryDeps deps = lib.getDeps(context); + Set newUnitPaths = Sets.newHashSet(); + + // Parse each compilation unit. for (LibraryNode libNode : lib.getSourcePaths()) { - final DartSource dartSrc = libSrc.getSourceFor(libNode.getText()); + String relPath = libNode.getText(); + newUnitPaths.add(relPath); + final DartSource dartSrc = libSrc.getSourceFor(relPath); if (dartSrc == null || !dartSrc.exists()) { // Dart Editor needs to have all missing files reported as compilation errors. // In addition, continue allows lib.populateTopLevelNodes() to be called so that the @@ -260,35 +264,89 @@ public class DartCompiler { continue; } - DartUnit apiUnit = apiLib.getUnit(dartSrc.getName()); - if (apiUnit == null || isSourceOutOfDate(dartSrc, libSrc)) { - DartUnit unit = parse(dartSrc, lib.getPrefixes()); + + if (!incremental + || (libIsDartUri && !usePrecompiledDartLibs) + || isSourceOutOfDate(dartSrc, libSrc)) { + DartUnit unit = parse(dartSrc, lib.getPrefixes(), false); if (unit != null) { if (libNode == selfSourcePath) { lib.setSelfDartUnit(unit); } + // Replace unit within the library. lib.putUnit(unit); - apiOutOfDate = true; + context.setFilesHaveChanged(); + // Include into top-level symbols diff from current units, already existed or new. + { + LibraryDeps.Source source = deps.getSource(relPath); + Set newTopSymbols = unit.getTopDeclarationNames(); + if (source != null) { + Set oldTopSymbols = source.getTopSymbols(); + SetView diff0 = Sets.symmetricDifference(oldTopSymbols, newTopSymbols); + topLevelSymbolsDiff.addAll(diff0); + } else { + topLevelSymbolsDiff.addAll(newTopSymbols); + } + } } } else { - if (libNode == selfSourcePath) { - lib.setSelfDartUnit(apiUnit); + DartUnit dietUnit = parse(dartSrc, lib.getPrefixes(), true); + if (dietUnit != null) { + if (libNode == selfSourcePath) { + lib.setSelfDartUnit(dietUnit); + } + lib.putUnit(dietUnit); } - lib.putUnit(apiUnit); } } - // Persist the api file. - if (apiOutOfDate) { - context.setFilesHaveChanged(); - if (!checkOnly) { - lib.saveApi(context); + // Include into top-level symbols diff from units which disappeared since last compiling. + { + Set oldUnitPaths = deps.getUnitPaths(); + Set disappearedUnitPaths = Sets.difference(oldUnitPaths, newUnitPaths); + for (String relPath : disappearedUnitPaths) { + LibraryDeps.Source source = deps.getSource(relPath); + if (source != null) { + Set oldTopSymbols = source.getTopSymbols(); + topLevelSymbolsDiff.addAll(oldTopSymbols); + } } } + } - // Populate the library's class map. This is used later for - // dependency checking. - lib.populateTopLevelNodes(); + // Parse units, which potentially depend on the difference in top-level symbols. + if (!topLevelSymbolsDiff.isEmpty()) { + context.setFilesHaveChanged(); + for (LibraryUnit lib : libraries.values()) { + LibrarySource libSrc = lib.getSource(); + LibraryNode selfSourcePath = lib.getSelfSourcePath(); + LibraryDeps deps = lib.getDeps(context); + for (LibraryNode libNode : lib.getSourcePaths()) { + String relPath = libNode.getText(); + // Prepare source dependency. + LibraryDeps.Source source = deps.getSource(relPath); + if (source == null) { + continue; + } + // Check re-compilation conditions. + if (source.shouldRecompileOnAnyTopLevelChange() + || !Sets.intersection(source.getAllSymbols(), topLevelSymbolsDiff).isEmpty() + || !Sets.intersection(source.getHoles(), topLevelSymbolsDiff).isEmpty()) { + DartSource dartSrc = libSrc.getSourceFor(relPath); + if (dartSrc == null || !dartSrc.exists()) { + continue; + } + DartUnit unit = parse(dartSrc, lib.getPrefixes(), false); + if (unit != null) { + if (libNode == selfSourcePath) { + lib.setSelfDartUnit(unit); + } else { + lib.putUnit(unit); + } + } + } + } + } } } finally { if (compilerMetrics != null) { @@ -379,8 +437,7 @@ public class DartCompiler { } /** - * Determines whether the given source is out-of-date with respect to its artifacts or - * its library's associated api. + * Determines whether the given source is out-of-date with respect to its artifacts. */ private boolean isSourceOutOfDate(DartSource dartSrc, LibrarySource libSrc) { TraceEvent logEvent = @@ -405,7 +462,7 @@ public class DartCompiler { Tracer.end(backendEvent); } } - return (context.isOutOfDate(dartSrc, libSrc, EXTENSION_API)); + return false; } finally { Tracer.end(logEvent); } @@ -438,8 +495,7 @@ public class DartCompiler { } /** - * Parses compilation units that are out-of-date with respect to their dependencies. The - * parsed units will replace api units already in the library. + * Parses compilation units that are out-of-date with respect to their dependencies. */ private void addOutOfDateDeps() throws IOException { TraceEvent logEvent = Tracer.canTrace() ? Tracer.start(DartEventType.ADD_OUTOFDATE) : null; @@ -455,17 +511,22 @@ public class DartCompiler { // Load the existing DEPS, or create an empty one. LibraryDeps deps = lib.getDeps(context); - // Parse units that are out-of-date with respect to their - // dependencies. - for (String sourceName : deps.getSourceNames()) { - LibraryDeps.Source depSource = deps.getSource(sourceName); - if (isSourceOutOfDate(lib, depSource)) { + // Prepare all top-level symbols. + Set oldTopLevelSymbols = Sets.newHashSet(); + for (LibraryDeps.Source source : deps.getSources()) { + oldTopLevelSymbols.addAll(source.getTopSymbols()); + } + + // Parse units that are out-of-date with respect to their dependencies. + for (DartUnit unit : lib.getUnits()) { + String relPath = unit.getSource().getRelativePath(); + LibraryDeps.Source source = deps.getSource(relPath); + if (isUnitOutOfDate(lib, source)) { filesHaveChanged = true; - DartSource dartSrc = lib.getSource().getSourceFor(sourceName); - if ((dartSrc != null) && (dartSrc.exists())) { - DartUnit unit = parse(dartSrc, lib.getPrefixes()); + DartSource dartSrc = lib.getSource().getSourceFor(relPath); + if (dartSrc != null && dartSrc.exists()) { + unit = parse(dartSrc, lib.getPrefixes(), false); if (unit != null) { - // Replace the newly-parsed unit within the library. lib.putUnit(unit); } } @@ -482,52 +543,30 @@ public class DartCompiler { } /** - * Determines whether the given source (as referenced by {@link LibraryDeps.Source}) is - * out-of-date with respect to any of its dependencies. + * Determines whether the given dependencies are out-of-date. */ - private boolean isSourceOutOfDate(LibraryUnit lib, LibraryDeps.Source depSource) { - for (String nodeName : depSource.getNodeNames()) { - TraceEvent logEvent = - Tracer.canTrace() ? Tracer.start(DartEventType.IS_CLASS_OUT_OF_DATE, "class", - nodeName) : null; - try { - if (depSource.isHole(nodeName)) { - // The dependency's a "hole", meaning that any new identifier in the - // library scope that shadows it should force a recompile. - if (lib.getTopLevelNode(nodeName) != null) { - // The library defines a top-level node with the same name as the hole, so - // we need to recompile. - return true; - } - } else { - // Normal dependency. - Dependency dep = depSource.getDependency(nodeName); - - // Find the cached API and get its hash. - LibraryUnit depLib = libraries.get(dep.getLibUri()); - if (depLib == null) { - // The library no longer exists, so presume that we need to - // recompile. - return true; - } - - // If there's a hash mismatch, deps are out of date - DartNode depNode = depLib.getTopLevelNode(nodeName); - if (depNode == null) { - // Node was removed. That's about as mismatched as you can get. - return true; - } - String hash = Integer.toString(depNode.computeHash()); - if (!hash.equals(dep.getHash())) { - return true; - } - } - } finally { - Tracer.end(logEvent); + private boolean isUnitOutOfDate(LibraryUnit lib, LibraryDeps.Source source) { + // If we don't have dependency information, then we can not be sure that nothing changed. + if (source == null) { + return true; + } + // Check all dependencies. + for (Dependency dep : source.getDeps()) { + LibraryUnit depLib = libraries.get(dep.getLibUri()); + if (depLib == null) { + return true; + } + // Prepare unit. + DartUnit depUnit = depLib.getUnit(dep.getUnitName()); + if (depUnit == null) { + return true; + } + // May be unit modified. + if (depUnit.getSource().getLastModified() != dep.getLastModified()) { + return true; } } - - // No holes or hash mismatches; in date. + // No changed dependencies. return false; } @@ -684,7 +723,7 @@ public class DartCompiler { // Dump the compiler parse tree if dump format is set in arguments BaseASTWriter astWriter = ASTWriterFactory.create(config); - + // Coverage instrumenter CoverageInstrumenter coverageInstrumenter = CoverageInstrumenter.createInstance(config); coverageInstrumenter.process(libraries); @@ -698,7 +737,7 @@ public class DartCompiler { astWriter.process(unit); - // Don't compile api-only units. + // Don't compile diet units. if (unit.isDiet()) { continue; } @@ -743,7 +782,7 @@ public class DartCompiler { } // Update deps. - lib.getDeps(context).update(unit, context); + lib.getDeps(context).update(context, unit); // We compiled something, so remember that this means we need to // persist the deps and package the app. @@ -808,7 +847,7 @@ public class DartCompiler { } } - DartUnit parse(DartSource dartSrc, Set libraryPrefixes) throws IOException { + DartUnit parse(DartSource dartSrc, Set libraryPrefixes, boolean diet) throws IOException { TraceEvent parseEvent = Tracer.canTrace() ? Tracer.start(DartEventType.PARSE, "src", dartSrc.getName()) : null; CompilerMetrics compilerMetrics = context.getCompilerMetrics(); @@ -833,7 +872,7 @@ public class DartCompiler { } else { DartScannerParserContext parserContext = new DartScannerParserContext(dartSrc, srcCode, context, context.getCompilerMetrics()); - parser = new DartParser(parserContext, libraryPrefixes); + parser = new DartParser(parserContext, libraryPrefixes, diet); } DartUnit unit = parser.parseUnit(dartSrc); if (compilerMetrics != null) { @@ -891,13 +930,13 @@ public class DartCompiler { } @Override - DartUnit parse(DartSource dartSrc, Set prefixes) throws IOException { + DartUnit parse(DartSource dartSrc, Set prefixes, boolean diet) throws IOException { if (parsedUnits == null) { - return super.parse(dartSrc, prefixes); + return super.parse(dartSrc, prefixes, diet); } URI srcUri = dartSrc.getUri(); DartUnit parsedUnit = parsedUnits.get(srcUri); - return parsedUnit == null ? super.parse(dartSrc, prefixes) : parsedUnit; + return parsedUnit == null ? super.parse(dartSrc, prefixes, diet) : parsedUnit; } } @@ -1034,8 +1073,9 @@ public class DartCompiler { } /** - * Compiles the source file which could be a single *.dart source file or a *.app file. If it - * is the former an *.app file is conceptually synthesized. + * Treats the sourceFile as the top level library and generates compiled output by + * linking the dart source in this file with all libraries referenced with #import + * statements. */ public static String compileApp(File sourceFile, CompilerConfiguration config) throws IOException { TraceEvent logEvent = @@ -1144,7 +1184,6 @@ public class DartCompiler { embeddedLibraries.add(new NamedPlaceHolderLibrarySource("dart:coreimpl")); } - new Compiler(lib, embeddedLibraries, config, context).compile(); int errorCount = context.getErrorCount(); if (config.typeErrorsAreFatal()) { @@ -1209,11 +1248,11 @@ public class DartCompiler { new TypeAnalyzer() }; for (DartUnit unit : libraryUnit.getUnits()) { - // Don't analyze api-only units. + // Don't analyze diet units. if (unit.isDiet()) { continue; } - + for (DartCompilationPhase phase : phases) { unit = phase.exec(unit, context, compiler.getTypeProvider()); // Ignore errors. TypeAnalyzer should be able to cope with diff --git a/compiler/java/com/google/dart/compiler/DartCompilerErrorCode.java b/compiler/java/com/google/dart/compiler/DartCompilerErrorCode.java index 105cf456f43..87078805f1b 100644 --- a/compiler/java/com/google/dart/compiler/DartCompilerErrorCode.java +++ b/compiler/java/com/google/dart/compiler/DartCompilerErrorCode.java @@ -50,4 +50,9 @@ public enum DartCompilerErrorCode implements ErrorCode { public SubSystem getSubSystem() { return SubSystem.COMPILER; } + + @Override + public boolean needsRecompilation() { + return true; + } } diff --git a/compiler/java/com/google/dart/compiler/DartCompilerMainContext.java b/compiler/java/com/google/dart/compiler/DartCompilerMainContext.java index 5aff52ca5e2..beb23040698 100644 --- a/compiler/java/com/google/dart/compiler/DartCompilerMainContext.java +++ b/compiler/java/com/google/dart/compiler/DartCompilerMainContext.java @@ -4,6 +4,8 @@ package com.google.dart.compiler; +import com.google.common.collect.Lists; +import com.google.common.collect.MapMaker; import com.google.dart.compiler.ast.DartUnit; import com.google.dart.compiler.ast.LibraryUnit; import com.google.dart.compiler.metrics.CompilerMetrics; @@ -14,6 +16,9 @@ import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -29,6 +34,8 @@ final class DartCompilerMainContext implements DartCompilerListener, DartCompile private final LibrarySource lib; private final DartArtifactProvider provider; private final DartCompilerListener listener; + private final Map> errors = + new MapMaker().weakKeys().makeMap(); private final AtomicInteger errorCount = new AtomicInteger(0); private final AtomicInteger warningCount = new AtomicInteger(0); private final AtomicInteger typeErrorCount = new AtomicInteger(0); @@ -49,6 +56,19 @@ final class DartCompilerMainContext implements DartCompilerListener, DartCompile @Override public void onError(DartCompilationError event) { + // Remember error. + { + Source source = event.getSource(); + if (source != null) { + List sourceErrors = errors.get(source); + if (sourceErrors == null) { + sourceErrors = Lists.newArrayList(); + errors.put(source, sourceErrors); + } + sourceErrors.add(event); + } + } + // Increment counters. if (event.getErrorCode().getSubSystem() == SubSystem.STATIC_TYPE) { incrementTypeErrorCount(); } else if (shouldWarnOnNoSuchType() && event.getErrorCode() == ResolverErrorCode.NO_SUCH_TYPE) { @@ -58,6 +78,7 @@ final class DartCompilerMainContext implements DartCompilerListener, DartCompile } else if (event.getErrorCode().getErrorSeverity() == ErrorSeverity.WARNING) { incrementWarningCount(); } + // Notify listener. listener.onError(event); } @@ -102,6 +123,17 @@ final class DartCompilerMainContext implements DartCompilerListener, DartCompile return provider.getArtifactWriter(source, part, extension); } + /** + * @return the {@link DartCompilationError}s found in the given {@link Source}. + */ + public List getSourceErrors(Source source) { + List sourceErrors = errors.get(source); + if (sourceErrors != null) { + return sourceErrors; + } + return Collections.emptyList(); + } + public int getErrorCount() { return errorCount.get(); } diff --git a/compiler/java/com/google/dart/compiler/DefaultDartArtifactProvider.java b/compiler/java/com/google/dart/compiler/DefaultDartArtifactProvider.java index 42efa0aa68c..b7058a76226 100644 --- a/compiler/java/com/google/dart/compiler/DefaultDartArtifactProvider.java +++ b/compiler/java/com/google/dart/compiler/DefaultDartArtifactProvider.java @@ -81,7 +81,7 @@ public class DefaultDartArtifactProvider extends DartArtifactProvider { } } File artifactFile = getArtifactFile(base, "", extension); - return artifactFile.lastModified() < source.getLastModified(); + return !artifactFile.exists() || artifactFile.lastModified() < source.getLastModified(); } // TODO(jbrosenberg): remove 'source' argument from this method, it's not used diff --git a/compiler/java/com/google/dart/compiler/DeltaAnalyzer.java b/compiler/java/com/google/dart/compiler/DeltaAnalyzer.java index 7e827c5cf92..78a04b02ad8 100644 --- a/compiler/java/com/google/dart/compiler/DeltaAnalyzer.java +++ b/compiler/java/com/google/dart/compiler/DeltaAnalyzer.java @@ -78,7 +78,6 @@ class DeltaAnalyzer { // Create a library unit which holds the new unit. LibraryUnit libraryUnit = new LibraryUnit(makeLibrarySource("delta")); libraryUnit.putUnit(unit); - libraryUnit.populateTopLevelNodes(); // Create top-level elements for the new unit. new TopLevelElementBuilder().exec(libraryUnit, context); diff --git a/compiler/java/com/google/dart/compiler/ErrorCode.java b/compiler/java/com/google/dart/compiler/ErrorCode.java index 4305b82f41a..5662c3cb0c2 100644 --- a/compiler/java/com/google/dart/compiler/ErrorCode.java +++ b/compiler/java/com/google/dart/compiler/ErrorCode.java @@ -22,4 +22,10 @@ public interface ErrorCode { * @return the {@link SubSystem} which issued this error. */ SubSystem getSubSystem(); + + /** + * @return true if this {@link ErrorCode} should cause recompilation of the source + * during next incremental compilation. + */ + boolean needsRecompilation(); } diff --git a/compiler/java/com/google/dart/compiler/LibraryDeps.java b/compiler/java/com/google/dart/compiler/LibraryDeps.java index a1ec4a0100a..38fdf10b41a 100644 --- a/compiler/java/com/google/dart/compiler/LibraryDeps.java +++ b/compiler/java/com/google/dart/compiler/LibraryDeps.java @@ -1,188 +1,311 @@ // Copyright (c) 2011, 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. - package com.google.dart.compiler; +import com.google.common.base.Objects; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.dart.compiler.ast.DartUnit; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; -import java.io.StringWriter; import java.io.Writer; import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collections; +import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Map.Entry; +import java.util.Set; /** * Represents a library's dependencies artifact. */ public class LibraryDeps { + private static final String VERSION = "v00001"; /** - * Each dependency record contains the library in which it was found, along with a hash of its - * structure. Any change in the hash of the target dependency will force a recompile of the - * associated compilation unit. + * Each dependency record contains the library in which it was found, name of the unit in this + * library and last-modified timestamp. Any change in the timestamp of the target dependency will + * force a recompile of the associated compilation unit. */ public static class Dependency { private final URI libUri; - private final String hash; + private final String unitName; + private final long lastModified; - public Dependency(URI libUri, String hash) { + public Dependency(URI libUri, String unitName, long lastModified) { this.libUri = libUri; - this.hash = hash; + this.unitName = unitName; + this.lastModified = lastModified; } - public String getHash() { - return hash; + @Override + public boolean equals(Object obj) { + if (obj instanceof Dependency) { + Dependency dep = (Dependency) obj; + return Objects.equal(libUri, dep.libUri) && Objects.equal(unitName, dep.unitName); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(libUri, unitName); } public URI getLibUri() { return libUri; } + + public String getUnitName() { + return unitName; + } + + public long getLastModified() { + return lastModified; + } } - /** - * Each source is a map from class names to its associated {@link Dependency}. - * - * A special dependency entry, called a 'hole', represents a name that, if - * newly-defined in the library scope, will force a recompile of the unit. - * This is represented by the static constant {@link Source#HOLE}. - */ public static class Source { - private final Map deps = new ConcurrentHashMap(); - private final static Dependency HOLE = new Dependency(null, null); + private final Set deps = Sets.newHashSet(); + private final Set topSymbols = Sets.newHashSet(); + private final Set allSymbols = Sets.newHashSet(); + private final Set holes = Sets.newHashSet(); + private boolean shouldRecompileOnAnyTopLevelChange = false; /** - * Gets the node names of all dependencies for this source. + * @return the {@link Set} of {@link Dependency}s. */ - public Iterable getNodeNames() { - return deps.keySet(); + public Set getDeps() { + return deps; } - public void putDependency(String nodeName, Dependency dep) { - deps.put(nodeName, dep); + /** + * @return the names of top-level elements, such as methods and classes. + */ + public Set getTopSymbols() { + return topSymbols; } - public Dependency getDependency(String nodeName) { - return deps.get(nodeName); + /** + * @return the names of all elements in unit, such as names of local variables, fields, etc. + */ + public Set getAllSymbols() { + return allSymbols; } - public void putHole(String nodeName) { - deps.put(nodeName, HOLE); + /** + * @return the names of functions, which are invoked without qualifier. So, declaration or + * removing function with such name on top-level should cause recompiling. + */ + public Set getHoles() { + return holes; } - public boolean isHole(String nodeName) { - return deps.containsKey(nodeName) && (deps.get(nodeName) == HOLE); + /** + * @return true if this unit should be recompiled on any change in the set of + * top-level symbols. Typically unit has compilation errors, which potentially may be + * fixed, so we should recompile this unit. + */ + public boolean shouldRecompileOnAnyTopLevelChange() { + return shouldRecompileOnAnyTopLevelChange; + } + + /** + * Adds new {@link Dependency}. + */ + public void addDep(Dependency dep) { + deps.add(dep); + } + + /** + * Adds symbol to the {@link Set} of top symbols. + */ + public void addTopSymbol(String symbol) { + if (!Strings.isNullOrEmpty(symbol)) { + topSymbols.add(symbol); + } + } + + /** + * Adds symbol to the {@link Set} of all symbols. + */ + public void addAllSymbol(String symbol) { + allSymbols.add(symbol); + } + + /** + * Adds new hole for {@link #getHoles()}. + */ + public void addHole(String hole) { + holes.add(hole); } } - public static LibraryDeps fromReader(Reader reader) throws IOException { + public static LibraryDeps fromReader(Reader reader) { + try { + return fromReaderEx(reader); + } catch (Throwable e) { + return null; + } + } + + private static LibraryDeps fromReaderEx(Reader reader) throws Exception { LibraryDeps deps = new LibraryDeps(); BufferedReader buf = new BufferedReader(reader); - String srcName; - while (null != (srcName = buf.readLine())) { - Source src = new Source(); - - String line; - while (null != (line = buf.readLine())) { - // Blank line: next source. + // Check version. + { + String line = buf.readLine(); + if (!Objects.equal(line, VERSION)) { + return deps; + } + } + // Read units dependencies. + String relPath; + while (null != (relPath = buf.readLine())) { + Source source = new Source(); + // Read flags. + source.shouldRecompileOnAnyTopLevelChange = Boolean.parseBoolean(buf.readLine()); + // Read top symbols. + { + String line = buf.readLine(); + Iterable topSymbols = Splitter.on(' ').omitEmptyStrings().split(line); + Iterables.addAll(source.topSymbols, topSymbols); + } + // Read all symbols. + { + String line = buf.readLine(); + Iterable allSymbols = Splitter.on(' ').omitEmptyStrings().split(line); + Iterables.addAll(source.allSymbols, allSymbols); + } + // Read holes. + { + String line = buf.readLine(); + Iterable holes = Splitter.on(' ').omitEmptyStrings().split(line); + Iterables.addAll(source.holes, holes); + } + // Read dependencies. + while (true) { + String line = buf.readLine(); + // Blank line: next unit. if (line.length() == 0) { break; } - + // Parse line. String[] parts = line.split(" "); - switch (parts.length) { - case 3: - // Full dependency. - try { - src.deps.put(parts[0], new Dependency(new URI(parts[1]), parts[2])); - } catch (URISyntaxException e) { - return null; - } - break; - case 1: - // Name only: hole. - src.deps.put(parts[0], Source.HOLE); - break; - default: - return null; - } + source.deps.add(new Dependency(new URI(parts[0]), parts[1], Long.parseLong(parts[2]))); } - - deps.sources.put(srcName, src); + // Remember dependencies for current unit. + deps.sources.put(relPath, source); } - return deps; } - private final Map sources = new ConcurrentHashMap(); + private final Map sources = Maps.newHashMap(); public LibraryDeps() { } - public Source getSource(String sourceName) { - return sources.get(sourceName); - } - - public Iterable getSourceNames() { + /** + * @return the relative paths of all units with remembered dependencies. + */ + public Set getUnitPaths() { return sources.keySet(); } - public void setSource(String sourceName, Source source) { - sources.put(sourceName, source); + /** + * @return all {@link Source} descriptions for all units in this library. + */ + public Iterable getSources() { + return sources.values(); } - @Override - public String toString() { - try { - StringWriter writer = new StringWriter(); - write(writer); - return writer.toString(); - } catch (IOException e) { - throw new AssertionError(); + /** + * @return the {@link Source} description of the unit with given path. + */ + public Source getSource(String relPath) { + return sources.get(relPath); + } + + /** + * Remembers {@link Dependency}s of the unit with given path. + */ + public void putSource(String relPath, Source source) { + sources.put(relPath, source); + } + + /** + * Update the library dependencies to reflect this unit's classes. + */ + public void update(DartCompilerMainContext context, DartUnit unit) { + Source source = new Source(); + String relPath = unit.getSource().getRelativePath(); + putSource(relPath, source); + // Remember dependencies. + LibraryDepsVisitor.exec(unit, source); + // Fill Source with symbols. + for (String name : unit.getDeclarationNames()) { + source.addAllSymbol(name); + } + for (String name : unit.getTopDeclarationNames()) { + source.addTopSymbol(name); + } + // Analyze errors and see if any of them should force recompilation. + List sourceErrors = context.getSourceErrors(unit.getSource()); + for (DartCompilationError error : sourceErrors) { + if (error.getErrorCode().needsRecompilation()) { + source.shouldRecompileOnAnyTopLevelChange = true; + break; + } } } - public void update(DartUnit unit, DartCompilerContext context) { - // Update the library deps to reflect this unit's classes. - LibraryDepsVisitor.exec(unit, this); - } - public void write(Writer writer) throws IOException { - // For stability from run to run, this output needs to be sorted - ArrayList sortedSourceNames = new ArrayList(sources.size()); - sortedSourceNames.addAll(sources.keySet()); - Collections.sort(sortedSourceNames); - - for (String srcName : sortedSourceNames) { - writer.write(srcName); + // Write version. + writer.write(VERSION); + writer.write('\n'); + // Write entries. + for (Entry entry : sources.entrySet()) { + String relPath = entry.getKey(); + Source source = entry.getValue(); + // Unit name. + writer.write(relPath); writer.write('\n'); - Source src = sources.get(srcName); - - // sort the types per source name - ArrayList sortedTypes = new ArrayList(src.deps.size()); - sortedTypes.addAll(src.deps.keySet()); - Collections.sort(sortedTypes); - - for (String type : sortedTypes) { - writer.write(type); - - Dependency dep = src.getDependency(type); - if (dep != Source.HOLE) { - writer.write(' '); - writer.write(dep.libUri.toString()); - writer.write(' '); - writer.write(dep.hash); - } - + // Flags. + writer.write(Boolean.toString(source.shouldRecompileOnAnyTopLevelChange)); + writer.write('\n'); + // Write top symbols. + for (String symbol : source.topSymbols) { + writer.write(symbol); + writer.write(' '); + } + writer.write('\n'); + // Write all symbols. + for (String symbol : source.allSymbols) { + writer.write(symbol); + writer.write(' '); + } + writer.write('\n'); + // Write holes. + for (String hole : source.holes) { + writer.write(hole); + writer.write(' '); + } + writer.write('\n'); + // Write dependencies. + for (Dependency dep : source.deps) { + writer.write(dep.libUri.toString()); + writer.write(' '); + writer.write(dep.unitName); + writer.write(' '); + writer.write(Long.toString(dep.lastModified)); writer.write('\n'); } - + // Empty line after each unit. writer.write('\n'); } } diff --git a/compiler/java/com/google/dart/compiler/LibraryDepsVisitor.java b/compiler/java/com/google/dart/compiler/LibraryDepsVisitor.java index 14de2a45d8b..e66601aff78 100644 --- a/compiler/java/com/google/dart/compiler/LibraryDepsVisitor.java +++ b/compiler/java/com/google/dart/compiler/LibraryDepsVisitor.java @@ -1,13 +1,10 @@ // Copyright (c) 2011, 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. - package com.google.dart.compiler; import com.google.dart.compiler.ast.DartClass; -import com.google.dart.compiler.ast.DartField; import com.google.dart.compiler.ast.DartIdentifier; -import com.google.dart.compiler.ast.DartMethodDefinition; import com.google.dart.compiler.ast.DartNode; import com.google.dart.compiler.ast.DartNodeTraverser; import com.google.dart.compiler.ast.DartParameterizedTypeNode; @@ -27,36 +24,26 @@ import java.net.URI; * A visitor that fills in {@link LibraryDeps} for a compilation unit. */ public class LibraryDepsVisitor extends DartNodeTraverser { - /** - * Fill in library dependencies from a compilation unit. - * - * @param unit the unit whose dependencies are to be filled in - * @param deps the target library deps + * Fill in {@link LibraryDeps} from a {@link DartUnit}. */ - static void exec(DartUnit unit, LibraryDeps deps) { - LibraryDepsVisitor v = new LibraryDepsVisitor(); + static void exec(DartUnit unit, LibraryDeps.Source source) { + LibraryDepsVisitor v = new LibraryDepsVisitor(source); unit.accept(v); - - String relPath = unit.getSource().getRelativePath(); - deps.setSource(relPath, v.source); } - private final LibraryDeps.Source source = new LibraryDeps.Source(); + private final LibraryDeps.Source source; private DartClass currentClass; - private LibraryDepsVisitor() { + private LibraryDepsVisitor(LibraryDeps.Source source) { + this.source = source; } @Override public Void visitIdentifier(DartIdentifier node) { Element target = node.getTargetSymbol(); ElementKind kind = ElementKind.of(target); - - // Deal with field and method references: - // - Add explicit dependencies on top-level fields and method. - // - Add "holes" for fields and methods found in a superclass (see LibraryDeps for further - // explanation). + // Add dependency on the field or method. switch (kind) { case FIELD: case METHOD: { @@ -68,13 +55,11 @@ public class LibraryDepsVisitor extends DartNodeTraverser { break; } } - // Add dependency on the computed type of identifiers. switch (kind) { case NONE: case DYNAMIC: break; - default: { Type type = target.getType(); if (type != null) { @@ -86,7 +71,6 @@ public class LibraryDepsVisitor extends DartNodeTraverser { break; } } - return null; } @@ -101,7 +85,7 @@ public class LibraryDepsVisitor extends DartNodeTraverser { return super.visitPropertyAccess(node); } } - // Skip rhs of property accesses, so that all identifiers we visit will be + // Skip rhs of property accesses, so that all identifiers we visit will be // unqualified. return node.getQualifier().accept(this); } @@ -136,46 +120,27 @@ public class LibraryDepsVisitor extends DartNodeTraverser { * Add a 'hole' for the given identifier, if its declaring class is a superclass of the current * class. A 'hole' dependency specifies a name that, if filled by something in the library scope, * would require this unit to be recompiled. - * + * * This situation occurs because names in the library scope bind more strongly than unqualified * superclass members. */ private void addHoleIfSuper(DartIdentifier node, Element holder) { - if (ElementKind.of(holder).equals(ElementKind.CLASS) - && holder != currentClass.getSymbol()) { - source.putHole(node.getTargetName()); + if (ElementKind.of(holder).equals(ElementKind.CLASS) && holder != currentClass.getSymbol()) { + source.addHole(node.getTargetName()); } } /** - * Adds a direct dependency on the given class. + * Adds a direct dependency on the unit providing given {@link Element}. */ private void addElementDependency(Element elem) { DartNode node = elem.getNode(); if (node != null) { - Source nodeSource = node.getSource(); - URI libUri = ((DartSource) nodeSource).getLibrary().getUri(); - LibraryDeps.Dependency dep = new LibraryDeps.Dependency(libUri, - Integer.toString(node.computeHash())); - - String name; - switch (elem.getKind()) { - case CLASS: - name = ((DartClass) node).getClassName(); - break; - case FIELD: - name = ((DartField) node).getName().getTargetName(); - break; - case METHOD: - DartMethodDefinition method = (DartMethodDefinition) node; - DartIdentifier ident = (DartIdentifier) method.getName(); - name = ident.getTargetName(); - break; - default: - throw new AssertionError("Unexpected top-level node type"); - } - - source.putDependency(name, dep); + DartSource unitSource = (DartSource) node.getSource(); + URI libUri = unitSource.getLibrary().getUri(); + LibraryDeps.Dependency dep = + new LibraryDeps.Dependency(libUri, unitSource.getName(), unitSource.getLastModified()); + source.addDep(dep); } } } diff --git a/compiler/java/com/google/dart/compiler/ast/DartClass.java b/compiler/java/com/google/dart/compiler/ast/DartClass.java index 1143e648d14..a8045cd5f28 100644 --- a/compiler/java/com/google/dart/compiler/ast/DartClass.java +++ b/compiler/java/com/google/dart/compiler/ast/DartClass.java @@ -27,8 +27,6 @@ public class DartClass extends DartDeclaration implements HasSym private DartParameterizedTypeNode defaultClass; private final Modifiers modifiers; - private int hash = -1; - // If the Dart class is implemented by a native JS class the nativeName // points to the JS class. Otherwise it is null. private final DartStringLiteral nativeName; @@ -56,14 +54,6 @@ public class DartClass extends DartDeclaration implements HasSym Modifiers.NONE); } - /** - * Set the diet-string hash code for the class - * @param hash the hash code to set - */ - void setHash(int hash) { - this.hash = hash; - } - public DartClass(DartIdentifier name, DartStringLiteral nativeName, DartTypeNode superclass, List interfaces, List members, @@ -215,15 +205,4 @@ public class DartClass extends DartDeclaration implements HasSym public R accept(DartPlainVisitor visitor) { return visitor.visitClass(this); } - - @Override - public int computeHash() { - // TODO(jgw): Remove this altogether in fixing b/5324113. - - // Cache hashes for DartClass, because they're always needed. - if (this.hash == -1) { - this.hash = super.computeHash(); - } - return this.hash; - } } diff --git a/compiler/java/com/google/dart/compiler/ast/DartField.java b/compiler/java/com/google/dart/compiler/ast/DartField.java index 4a2c587fab4..1718ca80b14 100644 --- a/compiler/java/com/google/dart/compiler/ast/DartField.java +++ b/compiler/java/com/google/dart/compiler/ast/DartField.java @@ -77,19 +77,4 @@ public class DartField extends DartClassMember { public R accept(DartPlainVisitor visitor) { return visitor.visitField(this); } - - @Override - public int computeHash() { - // TODO(jgw): Remove this altogether in fixing b/5324113. - - // DartField doesn't include the type-node, so we directly return the hash of its type, which - // is all that matters for the purposes of dependency-tracking. - DartFieldDefinition def = (DartFieldDefinition) getParent(); - DartTypeNode typeNode = def.getTypeNode(); - if (typeNode == null) { - // Use 0 to represent an untyped field. - return 0; - } - return typeNode.computeHash(); - } } diff --git a/compiler/java/com/google/dart/compiler/ast/DartNode.java b/compiler/java/com/google/dart/compiler/ast/DartNode.java index 67cd158ace3..8c30143c89b 100644 --- a/compiler/java/com/google/dart/compiler/ast/DartNode.java +++ b/compiler/java/com/google/dart/compiler/ast/DartNode.java @@ -143,24 +143,6 @@ public abstract class DartNode extends AbstractNode implements DartVisitable { public abstract R accept(DartPlainVisitor visitor); - public int computeHash() { - // TODO(jgw): Remove this altogether in fixing b/5324113. - // - // This computes a "hash" of the class' interface by simply serializing it to diet source and - // computing a hash of the string. This will work for now, but encodes too much information in - // the hash, and is slower than it should be. It should also cache the result and invalidate it - // if anything substantive changes. - // - // Examples of changes incorrectly captured by this hash, which would cause unnecessary - // recompiled include: - // - any change in method/field order would trigger an unnecessary recompile. - // - purely lexical changes such as {int x; int y;} => {int x, y;} - // - DefaultTextOutput out = new DefaultTextOutput(false); - new DartToSourceVisitor(out, true).accept(this); - return out.toString().trim().hashCode(); - } - @Override public DartNode clone() { // TODO (fabiomfv) - Implement proper cloning when strictly needed. diff --git a/compiler/java/com/google/dart/compiler/ast/DartToSourceVisitor.java b/compiler/java/com/google/dart/compiler/ast/DartToSourceVisitor.java index 2a4c25f52c1..059620cb500 100644 --- a/compiler/java/com/google/dart/compiler/ast/DartToSourceVisitor.java +++ b/compiler/java/com/google/dart/compiler/ast/DartToSourceVisitor.java @@ -25,8 +25,6 @@ public class DartToSourceVisitor extends DartVisitor { private List mappings = Lists.newArrayList(); private final boolean isDiet; - private final boolean calculateHash; - public DartToSourceVisitor(TextOutput out) { this(out, false); } @@ -34,13 +32,6 @@ public class DartToSourceVisitor extends DartVisitor { public DartToSourceVisitor(TextOutput out, boolean isDiet) { this.out = out; this.isDiet = isDiet; - this.calculateHash = false; - } - - public DartToSourceVisitor(TextOutput out, boolean isDiet, boolean calculateHash) { - this.out = out; - this.isDiet = isDiet; - this.calculateHash = calculateHash; } public void generateSourceMap(boolean generate) { @@ -132,11 +123,6 @@ public class DartToSourceVisitor extends DartVisitor { @Override public boolean visit(DartClass x, DartContext ctx) { - int start = 0; - if (calculateHash == true) { - start = out.getPosition(); - } - if (x.isInterface()) { p("interface "); } else { @@ -185,9 +171,6 @@ public class DartToSourceVisitor extends DartVisitor { outdent(); p("}"); - if (calculateHash == true) { - x.setHash(out.toString().substring(start, out.getPosition()).hashCode()); - } nl(); nl(); return false; diff --git a/compiler/java/com/google/dart/compiler/ast/DartUnit.java b/compiler/java/com/google/dart/compiler/ast/DartUnit.java index 400a65c1f3f..40faf843fc5 100644 --- a/compiler/java/com/google/dart/compiler/ast/DartUnit.java +++ b/compiler/java/com/google/dart/compiler/ast/DartUnit.java @@ -5,12 +5,14 @@ package com.google.dart.compiler.ast; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.google.dart.compiler.DartSource; import com.google.dart.compiler.util.DefaultTextOutput; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; /** * Represents a Dart compilation unit. @@ -116,7 +118,7 @@ public class DartUnit extends DartNode { public final String toDietSource() { if (dietParse == null) { DefaultTextOutput out = new DefaultTextOutput(false); - new DartToSourceVisitor(out, true, true).accept(this); + new DartToSourceVisitor(out, true).accept(this); dietParse = out.toString(); } return dietParse; @@ -141,4 +143,86 @@ public class DartUnit extends DartNode { } return directives; } + + /** + * @return the names of top-level declarations. + */ + public Set getTopDeclarationNames() { + Set topLevelSymbols = Sets.newHashSet(); + for (DartNode node : getTopLevelNodes()) { + if (node instanceof DartClass) { + DartIdentifier name = ((DartClass) node).getName(); + topLevelSymbols.add(name.getTargetName()); + } + if (node instanceof DartFunctionTypeAlias) { + DartIdentifier name = ((DartFunctionTypeAlias) node).getName(); + topLevelSymbols.add(name.getTargetName()); + } + if (node instanceof DartMethodDefinition) { + DartExpression name = ((DartMethodDefinition) node).getName(); + topLevelSymbols.add(((DartIdentifier) name).getTargetName()); + } + if (node instanceof DartFieldDefinition) { + DartFieldDefinition fieldDefinition = (DartFieldDefinition) node; + List fields = fieldDefinition.getFields(); + for (DartField variable : fields) { + topLevelSymbols.add(variable.getName().getTargetName()); + } + } + } + return topLevelSymbols; + } + + /** + * @return the {@link Set} of names of all declarations. + */ + public Set getDeclarationNames() { + final Set symbols = Sets.newHashSet(); + accept(new DartNodeTraverser() { + @Override + public Void visitFunctionTypeAlias(DartFunctionTypeAlias node) { + symbols.add(node.getName().getTargetName()); + return super.visitFunctionTypeAlias(node); + } + + @Override + public Void visitClass(DartClass node) { + symbols.add(node.getClassName()); + return super.visitClass(node); + } + + @Override + public Void visitTypeParameter(DartTypeParameter node) { + symbols.add(node.getName().getTargetName()); + return super.visitTypeParameter(node); + } + + @Override + public Void visitField(DartField node) { + symbols.add(node.getName().getTargetName()); + return super.visitField(node); + } + + @Override + public Void visitMethodDefinition(DartMethodDefinition node) { + if (node.getName() instanceof DartIdentifier) { + symbols.add(((DartIdentifier) node.getName()).getTargetName()); + } + return super.visitMethodDefinition(node); + } + + @Override + public Void visitParameter(DartParameter node) { + symbols.add(node.getParameterName()); + return super.visitParameter(node); + } + + @Override + public Void visitVariable(DartVariable node) { + symbols.add(node.getVariableName()); + return super.visitVariable(node); + } + }); + return symbols; + } } \ No newline at end of file diff --git a/compiler/java/com/google/dart/compiler/ast/LibraryNode.java b/compiler/java/com/google/dart/compiler/ast/LibraryNode.java index b9f7c9a2133..41227cf5654 100644 --- a/compiler/java/com/google/dart/compiler/ast/LibraryNode.java +++ b/compiler/java/com/google/dart/compiler/ast/LibraryNode.java @@ -7,10 +7,7 @@ package com.google.dart.compiler.ast; import com.google.dart.compiler.common.AbstractNode; /** - * An element in a library or application manifest - * - * TODO(jgw): This class works with both JSON and the new library syntax. It can be greatly - * simplified once support for the JSON syntax is removed. + * An element in a library. */ public class LibraryNode extends AbstractNode { diff --git a/compiler/java/com/google/dart/compiler/ast/LibraryUnit.java b/compiler/java/com/google/dart/compiler/ast/LibraryUnit.java index 0a18d76b65d..195f494141f 100644 --- a/compiler/java/com/google/dart/compiler/ast/LibraryUnit.java +++ b/compiler/java/com/google/dart/compiler/ast/LibraryUnit.java @@ -4,33 +4,22 @@ package com.google.dart.compiler.ast; -import com.google.common.io.CharStreams; import com.google.dart.compiler.DartCompiler; import com.google.dart.compiler.DartCompilerContext; -import com.google.dart.compiler.DartCompilerListener; import com.google.dart.compiler.DartSource; import com.google.dart.compiler.LibraryDeps; import com.google.dart.compiler.LibrarySource; -import com.google.dart.compiler.common.SourceInfo; -import com.google.dart.compiler.metrics.DartEventType; -import com.google.dart.compiler.metrics.Tracer; -import com.google.dart.compiler.metrics.Tracer.TraceEvent; -import com.google.dart.compiler.parser.DartParser; -import com.google.dart.compiler.parser.DartScannerParserContext; import com.google.dart.compiler.resolver.Elements; import com.google.dart.compiler.resolver.LibraryElement; import java.io.IOException; import java.io.Reader; import java.io.Writer; -import java.net.URI; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentSkipListMap; @@ -38,11 +27,6 @@ import java.util.concurrent.ConcurrentSkipListMap; * Represents the parsed source from a {@link LibrarySource}. */ public class LibraryUnit { - - // This is intentionally unparseable as Dart. - private static final String UNIT_SEPARATOR_NAME = "--- unit-name: "; - private static final String UNIT_SEPARATOR_URI = "--- unit-uri: "; - private final LibrarySource libSource; private final LibraryNode selfSourcePath; private final Collection importPaths = new ArrayList(); @@ -56,7 +40,6 @@ public class LibraryUnit { private final LibraryElement element; - private Map topLevelNodes; private LibraryDeps deps; private LibraryNode entryNode; @@ -234,136 +217,6 @@ public class LibraryUnit { return nativePaths; } - /** - * Loads this library's associated api. If the api file exists, this will result in the library - * being populated with "diet" units (i.e., {@link DartUnit#isDiet()} will return - * true). - * - * @return true if the library was loaded from its api - */ - public boolean loadApi(DartCompilerContext context, DartCompilerListener listener) - throws IOException { - TraceEvent parseEvent = - Tracer.canTrace() ? Tracer.start(DartEventType.PARSE_API, "src", getSource().getUri() - .toString()) : null; - try { - final Reader r = context.getArtifactReader(libSource, "", DartCompiler.EXTENSION_API); - if (r == null) { - return false; - } - - // Read the API file. - String srcCode = CharStreams.toString(r); - r.close(); - - // Split it up by unit. - int idx = srcCode.indexOf(UNIT_SEPARATOR_NAME); - while (idx != -1) { - int endIdx; - - // Prepare unit name. - idx += UNIT_SEPARATOR_NAME.length(); - endIdx = srcCode.indexOf('\n', idx); - String unitName = srcCode.substring(idx, endIdx); - idx = endIdx; - - // Prepare unit URI. - idx = srcCode.indexOf(UNIT_SEPARATOR_URI, endIdx); - idx += UNIT_SEPARATOR_URI.length(); - endIdx = srcCode.indexOf('\n', idx); - String unitUri = srcCode.substring(idx, endIdx); - idx = endIdx; - - // Find next unit, may be end string. - endIdx = srcCode.indexOf(UNIT_SEPARATOR_NAME, idx); - - // Parse diet source unit. - String code = endIdx != -1 ? srcCode.substring(idx, endIdx) : srcCode.substring(idx); - parseApiUnit(unitName, unitUri, code, libSource, listener); - - // Process next unit. - idx = endIdx; - } - - return true; - } finally { - Tracer.end(parseEvent); - } - } - - /** - * Saves this library's contents to its associated api file. - */ - public void saveApi(DartCompilerContext context) throws IOException { - Writer w = context.getArtifactWriter(libSource, "", DartCompiler.EXTENSION_API); - for (Entry entry : units.entrySet()) { - String unitName = entry.getKey(); - DartUnit unit = entry.getValue(); - w.write(UNIT_SEPARATOR_NAME + unitName + "\n"); - w.write(UNIT_SEPARATOR_URI + unit.getSource().getUri() + "\n"); - w.write(unit.toDietSource()); - } - w.close(); - } - - /** - * Populates this unit's class map. This can be called only once per unit, and must be called - * before {@link #getTopLevelNode(String)} and {@link #getTopLevelNodes()}. - */ - public void populateTopLevelNodes() { - assert topLevelNodes == null; - topLevelNodes = new HashMap(); - - DartNodeTraverser visitor = new DartNodeTraverser() { - @Override - public Void visitClass(DartClass node) { - topLevelNodes.put(node.getClassName(), node); - return null; - } - - @Override - public Void visitMethodDefinition(DartMethodDefinition node) { - // Method names are always identifiers, except for factories, which cannot appear - // in this context. - DartExpression name = node.getName(); - if(name instanceof DartIdentifier) { - topLevelNodes.put(((DartIdentifier) name).getTargetName(), node); - } else { - // Visit the unknown node to generate a string for our use. - topLevelNodes.put(node.getName().toSource(), node); - } - return null; - } - - @Override - public Void visitField(DartField node) { - topLevelNodes.put(node.getName().getTargetName(), node); - return null; - } - }; - - for (DartUnit unit : units.values()) { - visitor.visitUnit(unit); - } - } - - /** - * Get an unmodifiable collection of the classes in this library. You must call - * {@link #populateTopLevelNodes()} before this method will work. - */ - public Collection getTopLevelNodes() { - return Collections.unmodifiableCollection(topLevelNodes.values()); - } - - /** - * Gets the {@link DartClass} associated with the given name. You must call - * {@link #populateTopLevelNodes()} before this method will work. - */ - public DartNode getTopLevelNode(String name) { - assert topLevelNodes != null; - return topLevelNodes.get(name); - } - /** * Return the declared entry method, if any * @@ -411,65 +264,4 @@ public class LibraryUnit { deps.write(writer); writer.close(); } - - private void parseApiUnit(final String unitName, - final String unitUri, - String srcCode, - final LibrarySource libSrc, - DartCompilerListener listener) { - // Dummy source for the api unit. - DartSource src = new DartSource() { - @Override - public LibrarySource getLibrary() { - return libSrc; - } - - @Override - public String getName() { - return unitName; - } - - @Override - public Reader getSourceReader() { - return null; - } - - @Override - public URI getUri() { - return URI.create(unitUri); - } - - @Override - public boolean exists() { - return true; - } - - @Override - public long getLastModified() { - return 0; - } - - @Override - public String getRelativePath() { - return unitName; - } - }; - - DartScannerParserContext parserContext = new DartScannerParserContext(src, srcCode, listener); - DartParser parser = new DartParser(parserContext, true); - DartUnit unit = parser.parseUnit(src); - - // When parsing from an API file, generate and store the hash for top level - // classes while we have the string available. Reduces the time needed to - // recompute this later with a visitor. - for (DartNode node : unit.getTopLevelNodes()) { - if (node instanceof DartClass) { - SourceInfo nodeInfo = node.getSourceInfo(); - String nodeString = srcCode.substring(nodeInfo.getSourceStart(), - nodeInfo.getSourceStart()+nodeInfo.getSourceLength()); - ((DartClass)node).setHash(nodeString.hashCode()); - } - } - putUnit(unit); - } } diff --git a/compiler/java/com/google/dart/compiler/backend/doc/DartDocumentationGenerator.java b/compiler/java/com/google/dart/compiler/backend/doc/DartDocumentationGenerator.java index c113f71c949..da3b34dc76a 100644 --- a/compiler/java/com/google/dart/compiler/backend/doc/DartDocumentationGenerator.java +++ b/compiler/java/com/google/dart/compiler/backend/doc/DartDocumentationGenerator.java @@ -4,6 +4,7 @@ package com.google.dart.compiler.backend.doc; +import com.google.common.collect.Lists; import com.google.dart.compiler.DartCompilerContext; import com.google.dart.compiler.DartSource; import com.google.dart.compiler.LibrarySource; @@ -80,7 +81,7 @@ public class DartDocumentationGenerator extends AbstractBackend { List exceptions = new ArrayList(10); List fields = new ArrayList(10); List methods = new ArrayList(10); - for (DartNode dartNode : lib.getTopLevelNodes()) { + for (DartNode dartNode : getTopLevelNodes(lib)) { if (dartNode instanceof DartClass) { DartClass dartClass = (DartClass) dartNode; ClassElement classElement = dartClass.getSymbol(); @@ -181,6 +182,18 @@ public class DartDocumentationGenerator extends AbstractBackend { } } + /** + * @return all top-level declarations in the given {@link LibraryUnit}. + */ + private static List getTopLevelNodes(LibraryUnit lib) { + List topLevelNodes = Lists.newArrayList(); + Iterable units = lib.getUnits(); + for (DartUnit unit : units) { + topLevelNodes.addAll(unit.getTopLevelNodes()); + } + return topLevelNodes; + } + @Override public boolean isOutOfDate(DartSource src, DartCompilerContext context) { return true; @@ -214,7 +227,7 @@ public class DartDocumentationGenerator extends AbstractBackend { stream.println("
"); for (LibraryUnit lib : libraries) { if (library == null || library.equals(lib.getName())) { - if (lib.getTopLevelNodes().size() > 0) { + if (!getTopLevelNodes(lib).isEmpty()) { stream.print("

"); stream.print(lib.getName()); stream.println("

"); diff --git a/compiler/java/com/google/dart/compiler/backend/js/ClosureJsErrorCode.java b/compiler/java/com/google/dart/compiler/backend/js/ClosureJsErrorCode.java index e2328b85a9b..f3b37049733 100644 --- a/compiler/java/com/google/dart/compiler/backend/js/ClosureJsErrorCode.java +++ b/compiler/java/com/google/dart/compiler/backend/js/ClosureJsErrorCode.java @@ -41,4 +41,9 @@ public enum ClosureJsErrorCode implements ErrorCode { public SubSystem getSubSystem() { return SubSystem.CLOSURE_BACKEND; } + + @Override + public boolean needsRecompilation() { + return true; + } } \ No newline at end of file diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsErrorCode.java b/compiler/java/com/google/dart/compiler/backend/js/JsErrorCode.java index b429724f366..abdde376fbc 100644 --- a/compiler/java/com/google/dart/compiler/backend/js/JsErrorCode.java +++ b/compiler/java/com/google/dart/compiler/backend/js/JsErrorCode.java @@ -41,4 +41,9 @@ public enum JsErrorCode implements ErrorCode { public SubSystem getSubSystem() { return SubSystem.JS_BACKEND; } + + @Override + public boolean needsRecompilation() { + return true; + } } \ No newline at end of file diff --git a/compiler/java/com/google/dart/compiler/parser/DartParser.java b/compiler/java/com/google/dart/compiler/parser/DartParser.java index db4ff5f24e8..71b5d62ed77 100644 --- a/compiler/java/com/google/dart/compiler/parser/DartParser.java +++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java @@ -170,8 +170,8 @@ public class DartParser extends CompletionHooksParserBase { this(ctx, false); } - public DartParser(ParserContext ctx, Set prefixes) { - this(ctx, false, prefixes); + public DartParser(ParserContext ctx, Set prefixes, boolean isDietParse) { + this(ctx, isDietParse, prefixes); } public DartParser(ParserContext ctx, boolean isDietParse) { @@ -2720,20 +2720,29 @@ public class DartParser extends CompletionHooksParserBase { */ private DartBlock parseFunctionStatementBody(boolean requireSemicolonForArrow) { if (isDietParse) { - expect(Token.LBRACE); DartBlock emptyBlock = new DartBlock(new ArrayList()); - int nesting = 1; - while (nesting > 0) { - Token token = next(); - switch (token) { - case LBRACE: - ++nesting; + if (optional(Token.ARROW)) { + while (true) { + Token token = next(); + if (token == Token.SEMICOLON) { break; - case RBRACE: - --nesting; - break; - case EOS: - return emptyBlock; + } + } + } else { + expect(Token.LBRACE); + int nesting = 1; + while (nesting > 0) { + Token token = next(); + switch (token) { + case LBRACE: + ++nesting; + break; + case RBRACE: + --nesting; + break; + case EOS: + return emptyBlock; + } } } // Return an empty block so we don't generate unparseable code. diff --git a/compiler/java/com/google/dart/compiler/parser/ParserErrorCode.java b/compiler/java/com/google/dart/compiler/parser/ParserErrorCode.java index 93482d41c0b..319c8955563 100644 --- a/compiler/java/com/google/dart/compiler/parser/ParserErrorCode.java +++ b/compiler/java/com/google/dart/compiler/parser/ParserErrorCode.java @@ -116,4 +116,9 @@ public enum ParserErrorCode implements ErrorCode { public SubSystem getSubSystem() { return SubSystem.PARSER; } + + @Override + public boolean needsRecompilation() { + return true; + } } \ No newline at end of file diff --git a/compiler/java/com/google/dart/compiler/resolver/ResolverErrorCode.java b/compiler/java/com/google/dart/compiler/resolver/ResolverErrorCode.java index 6c18e186b6b..af2c280d1f6 100644 --- a/compiler/java/com/google/dart/compiler/resolver/ResolverErrorCode.java +++ b/compiler/java/com/google/dart/compiler/resolver/ResolverErrorCode.java @@ -44,7 +44,8 @@ public enum ResolverErrorCode implements ErrorCode { CONSTRUCTOR_CANNOT_BE_STATIC("A constructor cannot be static"), CONSTRUCTOR_CANNOT_HAVE_RETURN_TYPE("Generative constructors cannot have return type"), CONST_AND_NONCONST_CONSTRUCTOR("Cannot reference to non-const constructor."), - CONST_CLASS_WITH_INHERITED_NONFINAL_FIELDS("Const class %s cannot have non-final, inherited field %s from class %s"), + CONST_CLASS_WITH_INHERITED_NONFINAL_FIELDS( + "Const class %s cannot have non-final, inherited field %s from class %s"), CONST_CLASS_WITH_NONFINAL_FIELDS("Const class %s cannot have non-final field %s"), CONST_CONSTRUCTOR_CANNOT_HAVE_BODY("A const constructor cannot have a body"), CONST_CONSTRUCTOR_MUST_CALL_CONST_SUPER("const constructor must call const super constructor"), @@ -52,8 +53,7 @@ public enum ResolverErrorCode implements ErrorCode { CYCLIC_CLASS("%s causes a cycle in the supertype graph"), DEFAULT_CLASS_MUST_HAVE_SAME_TYPE_PARAMS( "default class must have the same type parameters as declared in the interface"), - DEFAULT_CONSTRUCTOR_UNRESOLVED( - "Can not resolve constructor with name '%s' in default class '%s'"), + DEFAULT_CONSTRUCTOR_UNRESOLVED("Can not resolve constructor with name '%s' in default class '%s'"), DEFAULT_CONSTRUCTOR_NUMBER_OF_REQUIRED_PARAMETERS( "Constructor '%s' in '%s' has %s required parameters, doesn't match '%s' in '%s' with %s"), DEFAULT_CONSTRUCTOR_NAMED_PARAMETERS( @@ -63,19 +63,19 @@ public enum ResolverErrorCode implements ErrorCode { "Deprecated Map literal syntax. Only specify a single value type as a type argument."), DID_YOU_MEAN_NEW("%1$s is a %2$s. Did you mean (new %1$s)?"), DUPLICATED_INTERFACE("%s and %s are duplicated in the supertype graph"), - DUPLICATE_INITIALIZATION(ErrorSeverity.ERROR, "Duplicate initialization of '%s'"), - DUPLICATE_FUNCTION_EXPRESSION(ErrorSeverity.ERROR, "Duplicate function expression '%s'"), + DUPLICATE_INITIALIZATION("Duplicate initialization of '%s'"), + DUPLICATE_FUNCTION_EXPRESSION("Duplicate function expression '%s'"), DUPLICATE_FUNCTION_EXPRESSION_WARNING(ErrorSeverity.WARNING, "Function expression '%s' is hiding '%s' at %s"), - DUPLICATE_LOCAL_VARIABLE_ERROR(ErrorSeverity.ERROR, "Duplicate local variable '%s'"), + DUPLICATE_LOCAL_VARIABLE_ERROR("Duplicate local variable '%s'"), DUPLICATE_LOCAL_VARIABLE_WARNING(ErrorSeverity.WARNING, "Local variable '%s' is hiding '%s' at %s"), DUPLICATE_MEMBER("Duplicate member '%s'"), DUPLICATE_NAMED_ARGUMENT("Duplicate named parameter argument"), - DUPLICATE_PARAMETER(ErrorSeverity.ERROR, "Duplicate parameter '%s'"), + DUPLICATE_PARAMETER("Duplicate parameter '%s'"), DUPLICATE_PARAMETER_WARNING(ErrorSeverity.WARNING, "Parameter '%s' is hiding '%s' at %s"), DUPLICATE_TOP_LEVEL_DEFINITION("duplicate top-level definition '%s'"), - DUPLICATE_TYPE_VARIABLE(ErrorSeverity.ERROR, "Duplicate type variable '%s'"), + DUPLICATE_TYPE_VARIABLE("Duplicate type variable '%s'"), DUPLICATE_TYPE_VARIABLE_WARNING(ErrorSeverity.WARNING, "Type variable '%s' is hiding '%s' at %s"), EXPECTED_AN_INSTANCE_FIELD_IN_SUPER_CLASS( "expected an instance field in the super class, but got %s"), @@ -150,7 +150,7 @@ public enum ResolverErrorCode implements ErrorCode { TYPE_NOT_ASSIGNMENT_COMPATIBLE("%s is not assignable to %s"), TYPE_VARIABLE_DOES_NOT_MATCH("Type variable %s does not match %s in default class %s."), TYPE_PARAMETERS_MUST_MATCH_EXACTLY( - "Type parameters in default declaration must match referenced class exactly"), + "Type parameters in default declaration must match referenced class exactly"), TYPE_VARIABLE_IN_STATIC_CONTEXT("cannot access type variable %s in static context"), TYPE_VARIABLE_NOT_ALLOWED_IN_IDENTIFIER("type variables are not allowed in identifier expressions"), WRONG_NUMBER_OF_TYPE_ARGUMENTS("%s: wrong number of type arguments (%d). Expected %d"); @@ -186,4 +186,9 @@ public enum ResolverErrorCode implements ErrorCode { public SubSystem getSubSystem() { return SubSystem.RESOLVER; } + + @Override + public boolean needsRecompilation() { + return true; + } } \ No newline at end of file diff --git a/compiler/java/com/google/dart/compiler/resolver/TypeErrorCode.java b/compiler/java/com/google/dart/compiler/resolver/TypeErrorCode.java index ec5c0986a46..f9daf8dfa67 100644 --- a/compiler/java/com/google/dart/compiler/resolver/TypeErrorCode.java +++ b/compiler/java/com/google/dart/compiler/resolver/TypeErrorCode.java @@ -13,7 +13,7 @@ import com.google.dart.compiler.SubSystem; public enum TypeErrorCode implements ErrorCode { ABSTRACT_CLASS_WITHOUT_ABSTRACT_MODIFIER( "%s is an abstract class because it does not implement the inherited abstract members: %s"), - CANNOT_BE_RESOLVED("cannot resolve %s"), + CANNOT_BE_RESOLVED("cannot resolve %s", true), CANNOT_OVERRIDE_TYPED_MEMBER("cannot override %s of %s because %s is not assignable to %s"), CANNOT_OVERRIDE_METHOD_NOT_SUBTYPE("cannot override %s of %s because %s is not a subtype of %s"), CYCLIC_REFERENCE_TO_TYPE_VARIABLE( @@ -32,18 +32,18 @@ public enum TypeErrorCode implements ErrorCode { INSTANTIATION_OF_CLASS_WITH_UNIMPLEMENTED_MEMBERS( "instantiation of class %s with the inherited abstract members: %s"), INTERFACE_HAS_NO_METHOD_NAMED("%s has no method named \"%s\""), - INTERNAL_ERROR("internal error: %s"), + INTERNAL_ERROR("internal error: %s", true), IS_STATIC_FIELD_IN("\"%s\" is a static field in \"%s\""), IS_STATIC_METHOD_IN("\"%s\" is a static method in \"%s\""), MEMBER_IS_A_CONSTRUCTOR("%s is a constructor in %s"), MISSING_ARGUMENT("missing argument of type %s"), MISSING_RETURN_VALUE("no return value; expected a value of type %s"), NO_SUCH_NAMED_PARAMETER("no such named parameter \"%s\" defined"), - NO_SUCH_TYPE("no such type \"%s\""), + NO_SUCH_TYPE("no such type \"%s\"", true), NOT_A_FUNCTION("\"%s\" is not a function"), NOT_A_MEMBER_OF("\"%s\" is not a member of %s"), NOT_A_METHOD_IN("\"%s\" is not a method in %s"), - NOT_A_TYPE("type \"%s\" expected, but \"%s\" found"), + NOT_A_TYPE("type \"%s\" expected, but \"%s\" found", true), OPERATOR_WRONG_OPERAND_TYPE("operand of \"%s\" must be assignable to \"%s\""), OVERRIDING_INHERITED_STATIC_MEMBER("overriding inherited static member %s of %s"), SETTER_RETURN_TYPE("Specified return type of setter '%s' is non-void"), @@ -56,22 +56,22 @@ public enum TypeErrorCode implements ErrorCode { VOID("expression does not yield a value"), WRONG_NUMBER_OF_TYPE_ARGUMENTS("%s: wrong number of type arguments (%d), Expected %d"); - private final ErrorSeverity severity; private final String message; + private final boolean needsRecompilation; /** - * Initialize a newly created error code to have the given message and WARNING severity. + * Initialize a newly created error code to have the given message. */ private TypeErrorCode(String message) { - this(ErrorSeverity.WARNING, message); + this(message, false); } /** - * Initialize a newly created error code to have the given severity and message. + * Initialize a newly created error code to have the given message and compilation flag. */ - private TypeErrorCode(ErrorSeverity severity, String message) { - this.severity = severity; + private TypeErrorCode(String message, boolean needsRecompilation) { this.message = message; + this.needsRecompilation = needsRecompilation; } @Override @@ -81,11 +81,16 @@ public enum TypeErrorCode implements ErrorCode { @Override public ErrorSeverity getErrorSeverity() { - return severity; + return ErrorSeverity.WARNING; } @Override public SubSystem getSubSystem() { return SubSystem.STATIC_TYPE; } + + @Override + public boolean needsRecompilation() { + return this.needsRecompilation; + } } \ No newline at end of file diff --git a/compiler/javatests/com/google/dart/compiler/MockBundleLibrarySource.java b/compiler/javatests/com/google/dart/compiler/MockBundleLibrarySource.java index 10ec48d511c..f70cbec85b8 100644 --- a/compiler/javatests/com/google/dart/compiler/MockBundleLibrarySource.java +++ b/compiler/javatests/com/google/dart/compiler/MockBundleLibrarySource.java @@ -155,6 +155,7 @@ public class MockBundleLibrarySource extends UrlLibrarySource implements Library */ public void remapSource(String relPath, String remappedRelPath) { sourceRemapping.put(relPath, remappedRelPath); + touchSource(relPath); } /** diff --git a/compiler/javatests/com/google/dart/compiler/backend/common/TypeHeuristicImplementationTest.java b/compiler/javatests/com/google/dart/compiler/backend/common/TypeHeuristicImplementationTest.java index 89f28cc5c6d..c2da30d4604 100644 --- a/compiler/javatests/com/google/dart/compiler/backend/common/TypeHeuristicImplementationTest.java +++ b/compiler/javatests/com/google/dart/compiler/backend/common/TypeHeuristicImplementationTest.java @@ -851,9 +851,13 @@ public class TypeHeuristicImplementationTest extends CompilerTestCase { } private DartClass getClass(DartUnit unit, String name) { - DartNode node = unit.getLibrary().getTopLevelNode(name); - if (node instanceof DartClass) { - return (DartClass) node; + for (DartNode topLevelNode : unit.getTopLevelNodes()) { + if (topLevelNode instanceof DartClass) { + DartClass dartClass = (DartClass) topLevelNode; + if (dartClass.getName().getTargetName().equals(name)) { + return dartClass; + } + } } return null; } diff --git a/compiler/javatests/com/google/dart/compiler/common/ErrorExpectation.java b/compiler/javatests/com/google/dart/compiler/common/ErrorExpectation.java index 8033bc1d629..e10948e6b80 100644 --- a/compiler/javatests/com/google/dart/compiler/common/ErrorExpectation.java +++ b/compiler/javatests/com/google/dart/compiler/common/ErrorExpectation.java @@ -1,7 +1,6 @@ // Copyright (c) 2011, 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. - package com.google.dart.compiler.common; import com.google.dart.compiler.DartCompilationError; @@ -12,58 +11,88 @@ import junit.framework.Assert; import java.util.List; public class ErrorExpectation { + private final String sourceName; final ErrorCode errorCode; final int line; final int column; final int length; - public ErrorExpectation(ErrorCode errorCode, int line, int column, int length) { + public ErrorExpectation(String sourceName, ErrorCode errorCode, int line, int column, int length) { + this.sourceName = sourceName; this.errorCode = errorCode; this.line = line; this.column = column; this.length = length; } - public static ErrorExpectation errEx(ErrorCode errorCode, int line, int column, int length) { - return new ErrorExpectation(errorCode, line, column, length); + public static ErrorExpectation errEx(String sourceName, + ErrorCode errorCode, + int line, + int column, + int length) { + sourceName = sourceName != null ? sourceName : ""; + return new ErrorExpectation(sourceName, errorCode, line, column, length); } - public static void formatExpectations(StringBuffer out, List errors, - ErrorExpectation[] expectedErrors) { + public static ErrorExpectation errEx(ErrorCode errorCode, int line, int column, int length) { + return new ErrorExpectation("", errorCode, line, column, length); + } + + public static void formatExpectations(StringBuffer out, + List errors, + ErrorExpectation[] expectedErrors) { out.append(String.format("Expected %d errors\n", expectedErrors.length)); - for (ErrorExpectation errEx : expectedErrors) { - out.append(String.format(" %s (%d,%d/%d)\n", errEx.errorCode.toString(), - errEx.line, errEx.column, errEx.length)); + boolean hasExpectedSourceName = false; + for (ErrorExpectation expected : expectedErrors) { + hasExpectedSourceName |= expected.sourceName.length() != 0; + out.append(String.format( + " %s %s (%d,%d/%d)\n", + expected.sourceName, + expected.errorCode.toString(), + expected.line, + expected.column, + expected.length)); } out.append(String.format("Encountered %d errors\n", errors.size())); - for (DartCompilationError error : errors) { - out.append(String.format(" %s (%d,%d/%d): %s\n", error.getErrorCode().toString(), - error.getLineNumber(), error.getColumnNumber(), - error.getLength(), error.getMessage())); + for (DartCompilationError actual : errors) { + String sourceName = + hasExpectedSourceName && actual.getSource() != null ? actual.getSource().getName() : ""; + out.append(String.format( + " %s %s (%d,%d/%d): %s\n", + sourceName, + actual.getErrorCode().toString(), + actual.getLineNumber(), + actual.getColumnNumber(), + actual.getLength(), + actual.getMessage())); } } + /** * Asserts that given list of {@link DartCompilationError} is exactly same as expected. */ public static void assertErrors(List errors, - ErrorExpectation... expectedErrors) { + ErrorExpectation... expectedErrors) { StringBuffer errorMessage = new StringBuffer(); // count of errors if (errors.size() != expectedErrors.length) { - errorMessage.append(String.format("Wrong number of errors encountered\n", - expectedErrors.length, - errors.size())); - + errorMessage.append(String.format( + "Wrong number of errors encountered\n", + expectedErrors.length, + errors.size())); formatExpectations(errorMessage, errors, expectedErrors); } else { // content of errors for (int i = 0; i < expectedErrors.length; i++) { - ErrorExpectation expectedError = expectedErrors[i]; - DartCompilationError actualError = errors.get(i); - if (actualError.getErrorCode() != expectedError.errorCode - || actualError.getLineNumber() != expectedError.line - || actualError.getColumnNumber() != expectedError.column - || actualError.getLength() != expectedError.length) { + ErrorExpectation expected = expectedErrors[i]; + DartCompilationError actual = errors.get(i); + String expectedSourceName = expected.sourceName; + String actualSourceName = actual.getSource() != null ? actual.getSource().getName() : ""; + if (actual.getErrorCode() != expected.errorCode + || actual.getLineNumber() != expected.line + || actual.getColumnNumber() != expected.column + || actual.getLength() != expected.length + || !(expectedSourceName.length() == 0 || expectedSourceName.equals(actualSourceName))) { errorMessage.append(String.format("Expected errors didn't match actual\n")); formatExpectations(errorMessage, errors, expectedErrors); break; diff --git a/compiler/javatests/com/google/dart/compiler/end2end/End2EndTests.java b/compiler/javatests/com/google/dart/compiler/end2end/End2EndTests.java index ca78c2dd27e..fe86fbcf457 100644 --- a/compiler/javatests/com/google/dart/compiler/end2end/End2EndTests.java +++ b/compiler/javatests/com/google/dart/compiler/end2end/End2EndTests.java @@ -4,6 +4,7 @@ package com.google.dart.compiler.end2end; +import com.google.dart.compiler.end2end.inc.IncrementalCompilation2Test; import com.google.dart.compiler.end2end.inc.IncrementalCompilationTest; import com.google.dart.compiler.end2end.inc.IncrementalCompilationWithPrefixTest; @@ -23,6 +24,7 @@ public class End2EndTests extends TestSetup { suite.addTestSuite(BasicTest.class); suite.addTestSuite(MainMethodTest.class); suite.addTestSuite(IncrementalCompilationTest.class); + suite.addTestSuite(IncrementalCompilation2Test.class); suite.addTestSuite(IncrementalCompilationWithPrefixTest.class); return new End2EndTests(suite); } diff --git a/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilation2Test.java b/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilation2Test.java new file mode 100644 index 00000000000..3ea5e90495b --- /dev/null +++ b/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilation2Test.java @@ -0,0 +1,561 @@ +// Copyright (c) 2011, 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. +package com.google.dart.compiler.end2end.inc; + +import static com.google.dart.compiler.DartCompiler.EXTENSION_DEPS; +import static com.google.dart.compiler.backend.js.AbstractJsBackend.EXTENSION_APP_JS; +import static com.google.dart.compiler.backend.js.AbstractJsBackend.EXTENSION_JS; +import static com.google.dart.compiler.common.ErrorExpectation.assertErrors; +import static com.google.dart.compiler.common.ErrorExpectation.errEx; + +import com.google.common.collect.Lists; +import com.google.dart.compiler.CompilerTestCase; +import com.google.dart.compiler.DartCompilationError; +import com.google.dart.compiler.DartCompiler; +import com.google.dart.compiler.DartCompilerListener; +import com.google.dart.compiler.DefaultCompilerConfiguration; +import com.google.dart.compiler.LibrarySource; +import com.google.dart.compiler.MockArtifactProvider; +import com.google.dart.compiler.Source; +import com.google.dart.compiler.backend.js.JavascriptBackend; +import com.google.dart.compiler.resolver.ResolverErrorCode; +import com.google.dart.compiler.resolver.TypeErrorCode; + +import junit.framework.AssertionFailedError; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.Writer; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +public class IncrementalCompilation2Test extends CompilerTestCase { + private static final String APP = "Application.dart"; + + private static class IncMockArtifactProvider extends MockArtifactProvider { + Set reads = new ConcurrentSkipListSet(); + Set writes = new ConcurrentSkipListSet(); + + @Override + public Reader getArtifactReader(Source source, String part, String extension) { + reads.add(source.getName() + "/" + extension); + return super.getArtifactReader(source, part, extension); + } + + @Override + public Writer getArtifactWriter(Source source, String part, String extension) { + writes.add(source.getName() + "/" + extension); + return super.getArtifactWriter(source, part, extension); + } + + void resetReadsAndWrites() { + reads.clear(); + writes.clear(); + } + } + + private DefaultCompilerConfiguration config; + private IncMockArtifactProvider provider; + private MemoryLibrarySource appSource; + private long appSourceLastModified = 0; + private String appSourceContent = makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "#library('application');", + "#source('A.dart');", + "#source('B.dart');", + "#source('C.dart');", + ""); + private final List errors = Lists.newArrayList(); + + @Override + protected void setUp() throws Exception { + config = new DefaultCompilerConfiguration(new JavascriptBackend()) { + @Override + public boolean incremental() { + return true; + } + }; + provider = new IncMockArtifactProvider(); + appSource = new MemoryLibrarySource(APP, "") { + @Override + public long getLastModified() { + return appSourceLastModified; + } + + @Override + public Reader getSourceReader() throws IOException { + return new StringReader(appSourceContent); + } + }; + appSource.setContent("A.dart", ""); + appSource.setContent("B.dart", ""); + appSource.setContent("C.dart", ""); + } + + @Override + protected void tearDown() { + config = null; + provider = null; + appSource = null; + } + + /** + * "not_hole" is referenced using "super" qualifier, so is not affected by declaring top-level + * field with same name. + */ + public void test_useQualifiedFieldReference_ignoreTopLevelDeclaration() { + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class A {", + " int not_hole;", + "}", + "")); + appSource.setContent( + "C.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class B extends A {", + " int bar() {", + " return super.not_hole;", // qualified reference + " }", + "}", + "")); + compile(); + assertErrors(errors); + // Update units and compile. + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "int not_hole;", + "")); + compile(); + // TODO(scheglov) Fix this after 1159 + //assertErrors(errors, errEx(ResolverErrorCode.DUPLICATE_LOCAL_VARIABLE_WARNING, -1, 7, 20)); + // B should be compiled because it now conflicts with A. + // C should not be compiled, because it reference "not_hole" field, not top-level variable. + didWrite("A.dart", EXTENSION_JS); + didWrite("B.dart", EXTENSION_JS); + didNotWrite("C.dart", EXTENSION_JS); + assertAppBuilt(); + } + + /** + * Referenced "hole" identifier can not be resolved, but when we declare it in A, then B should be + * recompiled and error message disappear. + */ + public void test_useUnresolvedField_recompileOnTopLevelDeclaration() { + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class A {", + " int foo() {", + " return hole;", // no such field + " }", + "}", + "")); + compile(); + assertErrors(errors, errEx(TypeErrorCode.CANNOT_BE_RESOLVED, 4, 12, 4)); + // Update units and compile. + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "int hole;", + "")); + compile(); + // A and B should be compiled. + didWrite("A.dart", EXTENSION_JS); + didWrite("B.dart", EXTENSION_JS); + assertAppBuilt(); + // "hole" was filled with top-level field. + assertErrors(errors); + } + + /** + * Test for "hole" feature. If we use unqualified invocation and add/remove top-level method, this + * should cause compilation of invocation unit. + */ + public void test_isMethodHole_useUnqualifiedInvocation() { + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class A {", + " foo() {}", + "}", + "")); + appSource.setContent( + "C.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class B extends A {", + " int bar() {", + " foo();", // unqualified invocation + " }", + "}", + "")); + compile(); + assertErrors(errors); + // Declare top-level foo(), now invocation of foo() in B should be bound to this top-level. + { + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "foo() {}", + "")); + compile(); + // B should be compiled because it also declares foo(), so produces "shadow" conflict. + // C should be compiled because it has unqualified invocation which was declared in A. + didWrite("A.dart", EXTENSION_JS); + didWrite("B.dart", EXTENSION_JS); + didWrite("C.dart", EXTENSION_JS); + assertAppBuilt(); + } + // Remove top-level foo(), so invocation of foo() in B should be bound to the super class. + { + appSource.setContent("A.dart", ""); + compile(); + // B should be compiled because it also declares foo(), so produces "shadow" conflict. + // C should be compiled because it has unqualified invocation which was declared in A. + didWrite("A.dart", EXTENSION_JS); + didWrite("B.dart", EXTENSION_JS); + didWrite("C.dart", EXTENSION_JS); + } + } + + /** + * Test for "hole" feature. If we use qualified invocation and add/remove top-level method, this + * should not cause compilation of invocation unit. + */ + public void test_notMethodHole_useQualifiedInvocation() { + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class A {", + " foo() {}", + "}", + "")); + appSource.setContent( + "C.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class B extends A {", + " int bar() {", + " super.foo();", // qualified invocation + " }", + "}", + "")); + compile(); + assertErrors(errors); + // Declare top-level foo(), but it is ignored. + { + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "foo() {}", + "")); + compile(); + // B should be compiled because it also declares foo(), so produces "shadow" conflict. + // C should not be compiled because. + didWrite("A.dart", EXTENSION_JS); + didWrite("B.dart", EXTENSION_JS); + didNotWrite("C.dart", EXTENSION_JS); + assertAppBuilt(); + } + } + + /** + * Test for "hole" feature. If we use unqualified access and add/remove top-level field, this + * should cause compilation of invocation unit. + */ + public void test_fieldHole_useUnqualifiedAccess() { + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class A {", + " var foo;", + "}", + "")); + appSource.setContent( + "C.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class B extends A {", + " int bar() {", + " foo = 0;", // unqualified access + " }", + "}", + "")); + compile(); + assertErrors(errors); + // Declare top-level "foo", now access to "foo" in B should be bound to this top-level. + { + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "var foo;", + "")); + compile(); + // B should be compiled because it also declares "foo", so produces "shadow" conflict. + // C should be compiled because it has unqualified invocation which was declared in A. + didWrite("A.dart", EXTENSION_JS); + didWrite("B.dart", EXTENSION_JS); + didWrite("C.dart", EXTENSION_JS); + assertAppBuilt(); + } + // Remove top-level "foo", so access to "foo" in B should be bound to the super class. + { + appSource.setContent("A.dart", ""); + compile(); + // B should be compiled because it also declares "foo", so produces "shadow" conflict. + // C should be compiled because it has unqualified access which was declared in A. + didWrite("A.dart", EXTENSION_JS); + didWrite("B.dart", EXTENSION_JS); + didWrite("C.dart", EXTENSION_JS); + } + } + + /** + * Test for "hole" feature. If we use qualified access and add/remove top-level field, this should + * not cause compilation of invocation unit. + */ + public void test_gieldHole_useQualifiedAccess() { + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class A {", + " var foo;", + "}", + "")); + appSource.setContent( + "C.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class B extends A {", + " int bar() {", + " super.foo = 0;", // qualified access + " }", + "}", + "")); + compile(); + assertErrors(errors); + // Declare top-level "foo", but it is ignored. + { + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "var foo;", + "")); + compile(); + // B should be compiled because it also declares "foo", so produces "shadow" conflict. + // C should not be compiled because it has qualified access to "foo". + didWrite("A.dart", EXTENSION_JS); + didWrite("B.dart", EXTENSION_JS); + didNotWrite("C.dart", EXTENSION_JS); + assertAppBuilt(); + } + } + + public void test_declareTopLevel_conflictWithLocalVariable() { + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "methodB() {", + " var symbolDependency_foo;", + "}")); + compile(); + assertErrors(errors); + // Update units and compile. + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "var symbolDependency_foo;")); + compile(); + // Now there is top-level declarations conflict between A and B. + // So, B should be compiled. + didWrite("B.dart", EXTENSION_JS); + // But application should be build. + assertAppBuilt(); + // Because B was compiled, it has warning. + assertErrors(errors, errEx(ResolverErrorCode.DUPLICATE_LOCAL_VARIABLE_WARNING, 3, 7, 20)); + } + + public void test_undeclareTopLevel_conflictWithLocalVariable() { + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "var duplicate;")); + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "bar() {", + " var duplicate;", + "}")); + compile(); + assertErrors(errors, errEx(ResolverErrorCode.DUPLICATE_LOCAL_VARIABLE_WARNING, 3, 7, 9)); + // Update units and compile. + appSource.setContent("A.dart", ""); + compile(); + // Top-level declaration in A was removed, so no conflict. + // So: + // ... B should be recompiled. + didWrite("B.dart", EXTENSION_JS); + // ... but application should be rebuild. + assertAppBuilt(); + // Because B was recompiled, it has no warning. + assertErrors(errors); + } + + /** + * Removes A, so changes set of top level units and forces compilation. + */ + public void test_removeOneSource() { + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "var duplicate;")); + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "bar() {", + " var duplicate;", + "}")); + compile(); + assertErrors(errors, errEx(ResolverErrorCode.DUPLICATE_LOCAL_VARIABLE_WARNING, 3, 7, 9)); + // Exclude A and compile. + appSourceLastModified++; + appSourceContent = + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "#library('app');", + "#source('B.dart');", + ""); + compile(); + // Now there is top-level declarations conflict between A and B. + // So: + // ... B should be recompiled. + didWrite("B.dart", EXTENSION_JS); + // ... but application should be rebuild. + didWrite(APP, EXTENSION_DEPS); + didWrite(APP, EXTENSION_APP_JS); + // Because B was recompiled, it has no warning. + assertErrors(errors); + } + + public void test_declareField_conflictWithLocalVariable() { + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class A {", + "}", + "")); + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class B extends A {", + " foo() {", + " var bar;", + " }", + "}", + "")); + compile(); + assertErrors(errors); + // Update units and compile. + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "class A {", + " var bar;", + "}", + "")); + compile(); + // B depends on A class, so compiled. + didWrite("B.dart", EXTENSION_JS); + assertAppBuilt(); + // Because B was compiled, it has warning. + assertErrors(errors, errEx(ResolverErrorCode.DUPLICATE_LOCAL_VARIABLE_WARNING, 4, 9, 3)); + } + + public void test_declareTopLevelVariable_conflictOtherTopLevelVariable() { + appSource.setContent( + "A.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "var conflict;", + "")); + compile(); + assertErrors(errors); + // Update units and compile. + appSource.setContent( + "B.dart", + makeCode( + "// filler filler filler filler filler filler filler filler filler filler filler", + "var conflict;", + "")); + compile(); + // A symbols intersect with new B symbols, so we compile A too. + // Both A and B have errors. + assertErrors( + errors, + errEx("A.dart", ResolverErrorCode.DUPLICATE_TOP_LEVEL_DEFINITION, 2, 5, 8), + errEx("B.dart", ResolverErrorCode.DUPLICATE_TOP_LEVEL_DEFINITION, 2, 5, 8)); + } + + private void assertAppBuilt() { + didWrite(APP, EXTENSION_DEPS); + didWrite(APP, EXTENSION_APP_JS); + } + + private void compile() { + compile(appSource); + } + + private void compile(LibrarySource lib) { + try { + provider.resetReadsAndWrites(); + errors.clear(); + DartCompilerListener listener = new DartCompilerListener.Empty() { + @Override + public void onError(DartCompilationError event) { + errors.add(event); + } + }; + DartCompiler.compileLib(lib, config, provider, listener); + } catch (IOException e) { + throw new AssertionFailedError("Unexpected IOException: " + e.getMessage()); + } + } + + private void didWrite(String sourceName, String extension) { + String spec = sourceName + "/" + extension; + assertTrue("Expected write: " + spec, provider.writes.contains(spec)); + } + + private void didNotWrite(String sourceName, String extension) { + String spec = sourceName + "/" + extension; + assertFalse("Didn't expect write: " + spec, provider.writes.contains(spec)); + } +} diff --git a/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilationTest.java b/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilationTest.java index 05273388398..457cae7c2c7 100644 --- a/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilationTest.java +++ b/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilationTest.java @@ -4,15 +4,15 @@ package com.google.dart.compiler.end2end.inc; -import static com.google.dart.compiler.DartCompiler.EXTENSION_API; import static com.google.dart.compiler.DartCompiler.EXTENSION_DEPS; -import static com.google.dart.compiler.backend.js.JavascriptBackend.EXTENSION_APP_JS; -import static com.google.dart.compiler.backend.js.JavascriptBackend.EXTENSION_JS; +import static com.google.dart.compiler.backend.js.AbstractJsBackend.EXTENSION_APP_JS; +import static com.google.dart.compiler.backend.js.AbstractJsBackend.EXTENSION_JS; +import com.google.common.collect.Lists; import com.google.dart.compiler.CompilerTestCase; +import com.google.dart.compiler.DartCompilationError; import com.google.dart.compiler.DartCompiler; import com.google.dart.compiler.DartCompilerListener; -import com.google.dart.compiler.DartCompilerListenerTest; import com.google.dart.compiler.DefaultCompilerConfiguration; import com.google.dart.compiler.LibrarySource; import com.google.dart.compiler.MockArtifactProvider; @@ -25,7 +25,7 @@ import junit.framework.AssertionFailedError; import java.io.IOException; import java.io.Reader; import java.io.Writer; -import java.net.URISyntaxException; +import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentSkipListSet; @@ -63,6 +63,8 @@ public class IncrementalCompilationTest extends CompilerTestCase { private MockBundleLibrarySource someLibSource; private MockBundleLibrarySource someImplLibSource; + private final List errors = Lists.newArrayList(); + @Override protected void setUp() throws Exception { config = new DefaultCompilerConfiguration(new JavascriptBackend()) { @@ -88,7 +90,7 @@ public class IncrementalCompilationTest extends CompilerTestCase { someImplLibSource = null; } - public void testRemoveDeps() throws URISyntaxException { + public void testRemoveDeps() throws Exception { compile(); MockBundleLibrarySource myNuke5AppSource = new MockBundleLibrarySource( @@ -98,28 +100,25 @@ public class IncrementalCompilationTest extends CompilerTestCase { myNuke5AppSource.remapSource("my.dart", "my.no5ref.dart"); myNuke5AppSource.removeSource("myother5.dart"); - compile(myNuke5AppSource, null); + compile(myNuke5AppSource); } public void testFullCompile() { compile(); // Assert that all artifacts are written. - didWrite("someimpl.dart", EXTENSION_JS, provider); - didWrite("someimpl.lib.dart", EXTENSION_API, provider); - didWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didWrite("someimpl.dart", EXTENSION_JS); + didWrite("someimpl.lib.dart", EXTENSION_DEPS); - didWrite("some.dart", EXTENSION_JS, provider); - didWrite("some.lib.dart", EXTENSION_API, provider); - didWrite("some.lib.dart", EXTENSION_DEPS, provider); + didWrite("some.dart", EXTENSION_JS); + didWrite("some.lib.dart", EXTENSION_DEPS); - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother0.dart", EXTENSION_JS, provider); - didWrite("myother1.dart", EXTENSION_JS, provider); - didWrite("myother2.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_JS, provider); + didWrite("my.dart", EXTENSION_JS); + didWrite("myother0.dart", EXTENSION_JS); + didWrite("myother1.dart", EXTENSION_JS); + didWrite("myother2.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_JS); } public void testNoOpRecompile() { @@ -129,21 +128,18 @@ public class IncrementalCompilationTest extends CompilerTestCase { compile(); // Assert we didn't write anything. - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("my.dart", EXTENSION_JS, provider); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); - didNotWrite("my.app.dart", EXTENSION_API, provider); - didNotWrite("my.app.dart", EXTENSION_DEPS, provider); - didNotWrite("my.app.dart", EXTENSION_JS, provider); + didNotWrite("my.dart", EXTENSION_JS); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); + didNotWrite("my.app.dart", EXTENSION_DEPS); + didNotWrite("my.app.dart", EXTENSION_JS); } public void testTouchOneSource() { @@ -155,23 +151,20 @@ public class IncrementalCompilationTest extends CompilerTestCase { // We just bumped the timestamp on my.dart, so only my.dart.js and my.app.js should be changed. // At present, the app's deps and api will be rewritten. This might be optimized later. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); + didWrite("my.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_APP_JS); + didWrite("my.app.dart", EXTENSION_DEPS); // Nothing else should have changed. - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testNormalizationTracking() { @@ -190,24 +183,21 @@ public class IncrementalCompilationTest extends CompilerTestCase { // We just bumped the timestamp on myother7.dart, so only myother7.dart.js and my.app.js should // be changed. At present, the app's deps and api will be rewritten. - didWrite("myother7.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); + didWrite("myother7.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_APP_JS); + didWrite("my.app.dart", EXTENSION_DEPS); // Nothing else should have changed. - didNotWrite("my.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("my.dart", EXTENSION_JS); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testKnockout_jsArtifact() { @@ -219,372 +209,293 @@ public class IncrementalCompilationTest extends CompilerTestCase { // At present, knocking out a js artifact will force an update of the library's api and // deps. This could be optimized. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); + didWrite("my.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_APP_JS); + didWrite("my.app.dart", EXTENSION_DEPS); // Assert that everything else was left alone. - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); - } - - public void testKnockout_intfArtifact() { - compile(); - - provider.resetReadsAndWrites(); - provider.removeArtifact("my.app.dart", "", EXTENSION_API); - compile(); - - // At present, knocking out an api artifact will force an update of the library's units - // and deps. This could be optimized. - didWrite("my.app.dart", EXTENSION_APP_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother0.dart", EXTENSION_JS, provider); - didWrite("myother1.dart", EXTENSION_JS, provider); - didWrite("myother2.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - - // Assert that everything else was left alone. - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testChangeImplementation_methodBody() { compile(); provider.resetReadsAndWrites(); - someImplLibSource.touchSource("someimpl.dart"); someImplLibSource.remapSource("someimpl.dart", "someimpl.bodychange.dart"); compile(); - // Changed someimpl.dart, so it, its library, and the compiled app should be written, but not - // units that depend upon it. - didWrite("someimpl.dart", EXTENSION_JS, provider); - didWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didWrite("someimpl.lib.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Changed someimpl.dart, so it, its library, and the compiled app should be written. + didWrite("someimpl.dart", EXTENSION_JS); + didWrite("someimpl.lib.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + // We've switched to (unit -> unit) dependency, so should be recompiled too. + didWrite("some.dart", EXTENSION_JS); + didWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("my.dart", EXTENSION_JS, provider); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); - didNotWrite("my.app.dart", EXTENSION_API, provider); - didNotWrite("my.app.dart", EXTENSION_DEPS, provider); + didNotWrite("my.dart", EXTENSION_JS); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); + didNotWrite("my.app.dart", EXTENSION_DEPS); } public void testChangeApi_newStaticMethod() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother0.dart"); myAppSource.remapSource("myother0.dart", "myother0.newstaticmethod.dart"); compile(); - // Added a new static method to Other0, which should force a recompile of my.dart, because the - // latter contains a reference to one of its static methods. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother0.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Added a new static method to Other0, which should force a recompile of my.dart, + // because the latter contains a reference to one of its static methods. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother0.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testChangeApi_staticFieldRef() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother3.dart"); myAppSource.remapSource("myother3.dart", "myother3.newstaticfield.dart"); compile(); - // Added a new static method to Other0, which should force a recompile of my.dart, because the - // latter contains a reference to one of its static methods. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother3.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Added a new static field to Other0, which should force a recompile of my.dart, + // because the latter contains a reference to one of its static methods. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother3.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testChangeApi_viaTypeParamBound() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother4.dart"); myAppSource.remapSource("myother4.dart", "myother4.newstaticfield.dart"); compile(); - // Added a new static method to Other0, which should force a recompile of my.dart, because the - // latter contains a reference to one of its static methods. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother4.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Added a new static field to Other0, which should force a recompile of my.dart, + // because the latter contains a reference to one of its static methods. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother4.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testChangeApi_returnTypeChange() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother0.dart"); myAppSource.remapSource("myother0.dart", "myother0.returntypechange.dart"); compile(); - // Changed a return type in Other0, which should force a recompile of my.dart, because - // the latter contains a reference to one of its static methods. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother0.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Changed a return type in Other0, which should force a recompile of my.dart, + // because the latter contains a reference to one of its static methods. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother0.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testChangeApi_globalVarChange() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother0.dart"); myAppSource.remapSource("myother0.dart", "myother0.globalvarchange.dart"); compile(); - // Changed a return type in Other0, which should force a recompile of my.dart, because - // the latter contains a reference to one of its static methods. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother0.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Changed a top-level variable type in Other0, which should force a recompile of my.dart, + // because the latter contains a reference to one of its static methods. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother0.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); } public void testChangeApi_globalFunctionChange() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother0.dart"); myAppSource.remapSource("myother0.dart", "myother0.globalfunctionchange.dart"); compile(); - // Changed a return type in Other0, which should force a recompile of my.dart, because - // the latter contains a reference to one of its static methods. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother0.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Changed a return type in Other0, which should force a recompile of my.dart, + // because the latter contains a reference to one of its static methods. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother0.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); } public void testChangeApi_viaNew() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother1.dart"); myAppSource.remapSource("myother1.dart", "myother1.change.dart"); compile(); - // Changed the api of Other1, which should force a recompile of my.dart, because the - // latter intantiates one of its classes. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother1.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Changed the api of Other1, which should force a recompile of my.dart, + // because the latter instantiates one of its classes. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother1.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testChangeApi_viaSubclassing() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother2.dart"); myAppSource.remapSource("myother2.dart", "myother2.change.dart"); compile(); - // Changed the api of Other2, which should force a recompile of my.dart, because the - // latter subclasses one of its classes. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother2.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Changed the api of Other2, which should force a recompile of my.dart, + // because the latter subclasses one of its classes. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother2.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); } public void testChangeApi_inLibrary() { compile(); provider.resetReadsAndWrites(); - someLibSource.touchSource("some.dart"); someLibSource.remapSource("some.dart", "some.newmethod.dart"); - someImplLibSource.touchSource("someimpl.dart"); someImplLibSource.remapSource("someimpl.dart", "someimpl.change.dart"); compile(); // We changed both the interface and implementation libraries, so almost everything should have // been recompiled. - didWrite("someimpl.dart", EXTENSION_JS, provider); - didWrite("someimpl.lib.dart", EXTENSION_API, provider); - didWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didWrite("someimpl.dart", EXTENSION_JS); + didWrite("someimpl.lib.dart", EXTENSION_DEPS); - didWrite("some.dart", EXTENSION_JS, provider); - didWrite("some.lib.dart", EXTENSION_API, provider); - didWrite("some.lib.dart", EXTENSION_DEPS, provider); + didWrite("some.dart", EXTENSION_JS); + didWrite("some.lib.dart", EXTENSION_DEPS); - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + didWrite("my.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); // Except the "others", which have no dependency on the library. - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); - - // And the app's api, which also hasn't changed. - didNotWrite("my.app.dart", EXTENSION_API, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testChangeApi_inImplLibrary() { compile(); provider.resetReadsAndWrites(); - someImplLibSource.touchSource("someimpl.dart"); someImplLibSource.remapSource("someimpl.dart", "someimpl.change.dart"); compile(); // Assert that only the interface and implementation library were recompiled. - didWrite("someimpl.dart", EXTENSION_JS, provider); - didWrite("someimpl.lib.dart", EXTENSION_API, provider); - didWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didWrite("someimpl.dart", EXTENSION_JS); + didWrite("someimpl.lib.dart", EXTENSION_DEPS); - didWrite("some.dart", EXTENSION_JS, provider); - didWrite("some.lib.dart", EXTENSION_DEPS, provider); + didWrite("some.dart", EXTENSION_JS); + didWrite("some.lib.dart", EXTENSION_DEPS); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + didWrite("my.app.dart", EXTENSION_APP_JS); // The app should remain untouched. - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); - didNotWrite("my.dart", EXTENSION_JS, provider); - didNotWrite("my.app.dart", EXTENSION_API, provider); - didNotWrite("my.app.dart", EXTENSION_DEPS, provider); - - // As should the api of some.lib. - didNotWrite("some.lib.dart", EXTENSION_API, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); + didNotWrite("my.dart", EXTENSION_JS); + didNotWrite("my.app.dart", EXTENSION_DEPS); } public void testChangeApi_inInterface() { compile(); provider.resetReadsAndWrites(); - someLibSource.touchSource("some.dart"); someLibSource.remapSource("some.dart", "some.intfchange.dart"); compile(); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); - didNotWrite("my.app.dart", EXTENSION_API, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); // Assert we recompiled both some.dart and someimpl.dart, as well as my.dart. // (someimpl.dart is recompiled because its interface in some.dart changed) - didWrite("someimpl.dart", EXTENSION_JS, provider); - didWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didWrite("someimpl.dart", EXTENSION_JS); + didWrite("someimpl.lib.dart", EXTENSION_DEPS); - didWrite("some.dart", EXTENSION_JS, provider); - didWrite("some.lib.dart", EXTENSION_API, provider); - didWrite("some.lib.dart", EXTENSION_DEPS, provider); + didWrite("some.dart", EXTENSION_JS); + didWrite("some.lib.dart", EXTENSION_DEPS); - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + didWrite("my.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); } // TODO(jgw): Bug 5319907. @@ -592,169 +503,148 @@ public class IncrementalCompilationTest extends CompilerTestCase { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother0.dart"); myAppSource.remapSource("myother0.dart", "myother0.fillthehole.dart"); compile(); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); // Both myother0.dart and my.dart should be recompiled. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother0.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); + didWrite("my.dart", EXTENSION_JS); + didWrite("myother0.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_APP_JS); + didWrite("my.app.dart", EXTENSION_DEPS); } public void testMethodHole() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother0.dart"); myAppSource.remapSource("myother0.dart", "myother0.fillthemethodhole.dart"); - compile("my.dart", "methodHole is a class. Did you mean (new methodHole)?", 48, 5); - } - - public void testTheNotHole() { compile(); - - provider.resetReadsAndWrites(); - myAppSource.touchSource("myother0.dart"); - myAppSource.remapSource("myother0.dart", "myother0.fillthenothole.dart"); - compile(); - - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); - - didNotWrite("my.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); - - // Only myother0.dart should be recompiled. - didWrite("myother0.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); } public void testQualifiedFieldRef() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother5.dart"); myAppSource.remapSource("myother5.dart", "myother5.change.dart"); compile(); - // Changed the api of Other5, which should force a recompile of my.dart, because the - // latter includes a qualified reference to one of its instance fields. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother5.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Changed the api of Other5, which should force a recompile of my.dart, + // because the latter includes a qualified reference to one of its instance fields. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother5.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testQualifiedMethodRef() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother6.dart"); myAppSource.remapSource("myother6.dart", "myother6.change.dart"); compile(); - // Changed the api of Other6, which should force a recompile of my.dart, because the - // latter includes a qualified reference to one of its instance methods. - didWrite("my.dart", EXTENSION_JS, provider); - didWrite("myother6.dart", EXTENSION_JS, provider); - didWrite("my.app.dart", EXTENSION_API, provider); - didWrite("my.app.dart", EXTENSION_DEPS, provider); - didWrite("my.app.dart", EXTENSION_APP_JS, provider); + // Changed the api of Other6, which should force a recompile of my.dart, + // because the latter includes a qualified reference to one of its instance methods. + didWrite("my.dart", EXTENSION_JS); + didWrite("myother6.dart", EXTENSION_JS); + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); - didNotWrite("someimpl.dart", EXTENSION_JS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_DEPS, provider); - didNotWrite("someimpl.lib.dart", EXTENSION_API, provider); + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); - didNotWrite("some.dart", EXTENSION_JS, provider); - didNotWrite("some.lib.dart", EXTENSION_API, provider); - didNotWrite("some.lib.dart", EXTENSION_DEPS, provider); + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); - didNotWrite("myother0.dart", EXTENSION_JS, provider); - didNotWrite("myother1.dart", EXTENSION_JS, provider); - didNotWrite("myother2.dart", EXTENSION_JS, provider); + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } public void testRemoveDepClass() { compile(); provider.resetReadsAndWrites(); - myAppSource.touchSource("myother5.dart"); myAppSource.remapSource("myother5.dart", "myother5.change.dart"); - myAppSource.touchSource("myother6.dart"); myAppSource.remapSource("myother6.dart", "myother6.removeclass.dart"); compile(); - // TODO + // Changed myother6.dart, which should force a recompile of myother5.dart, + // because the latter had a qualified reference to one of its classes. + didWrite("myother5.dart", EXTENSION_JS); + didWrite("myother6.dart", EXTENSION_JS); + + didWrite("my.dart", EXTENSION_JS); + // Because of the previous changes my.app.dart is also recompile. + didWrite("my.app.dart", EXTENSION_DEPS); + didWrite("my.app.dart", EXTENSION_APP_JS); + + // No changes in not related units. + didNotWrite("someimpl.dart", EXTENSION_JS); + didNotWrite("someimpl.lib.dart", EXTENSION_DEPS); + + didNotWrite("some.dart", EXTENSION_JS); + didNotWrite("some.lib.dart", EXTENSION_DEPS); + + didNotWrite("myother0.dart", EXTENSION_JS); + didNotWrite("myother1.dart", EXTENSION_JS); + didNotWrite("myother2.dart", EXTENSION_JS); } - public void testMergeFiles() throws URISyntaxException { + public void testMergeFiles() throws Exception { compile(); MockBundleLibrarySource myMergedAppSource = new MockBundleLibrarySource( IncrementalCompilationTest.class.getClassLoader(), TEST_BASE_PATH, "my.merged.app.dart", "my.app.dart"); - compile(myMergedAppSource, null); + compile(myMergedAppSource); } private void compile() { - compile(null); + compile(myAppSource); } - private void compile(String srcName, Object... errors) { - compile(myAppSource, srcName, errors); - } - - private void compile(LibrarySource lib, String srcName, Object... errors) { + private void compile(LibrarySource lib) { try { - DartCompilerListener listener = new DartCompilerListenerTest(srcName, errors); + errors.clear(); + DartCompilerListener listener = new DartCompilerListener.Empty() { + @Override + public void onError(DartCompilationError event) { + errors.add(event); + } + }; DartCompiler.compileLib(lib, config, provider, listener); } catch (IOException e) { throw new AssertionFailedError("Unexpected IOException: " + e.getMessage()); } } - private void didWrite(String sourceName, String extension, IncMockArtifactProvider provider) { + private void didWrite(String sourceName, String extension) { String spec = sourceName + "/" + extension; assertTrue("Expected write: " + spec, provider.writes.contains(spec)); } - private void didNotWrite(String sourceName, String extension, IncMockArtifactProvider provider) { + private void didNotWrite(String sourceName, String extension) { String spec = sourceName + "/" + extension; assertFalse("Didn't expect write: " + spec, provider.writes.contains(spec)); } diff --git a/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilationWithPrefixTest.java b/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilationWithPrefixTest.java index 41148f62be7..680108d410d 100644 --- a/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilationWithPrefixTest.java +++ b/compiler/javatests/com/google/dart/compiler/end2end/inc/IncrementalCompilationWithPrefixTest.java @@ -4,7 +4,6 @@ package com.google.dart.compiler.end2end.inc; -import static com.google.dart.compiler.DartCompiler.EXTENSION_API; import static com.google.dart.compiler.DartCompiler.EXTENSION_DEPS; import static com.google.dart.compiler.backend.js.AbstractJsBackend.EXTENSION_APP_JS; import static com.google.dart.compiler.backend.js.AbstractJsBackend.EXTENSION_JS; @@ -98,12 +97,11 @@ public class IncrementalCompilationWithPrefixTest extends CompilerTestCase { someLibSource.remapSource("some.prefixable.lib.dart", "some.prefixable.modified.lib.dart"); compile(); - didWrite("my.unprefixed.app.dart", EXTENSION_JS, provider); - didWrite("my.unprefixed.app.dart", EXTENSION_APP_JS, provider); - didWrite("my.unprefixed.app.dart", EXTENSION_DEPS, provider); - didWrite("some.prefixable.lib.dart", EXTENSION_JS, provider); - didWrite("some.prefixable.lib.dart", EXTENSION_DEPS, provider); - didWrite("some.prefixable.lib.dart", EXTENSION_API, provider); + didWrite("my.unprefixed.app.dart", EXTENSION_JS); + didWrite("my.unprefixed.app.dart", EXTENSION_APP_JS); + didWrite("my.unprefixed.app.dart", EXTENSION_DEPS); + didWrite("some.prefixable.lib.dart", EXTENSION_JS); + didWrite("some.prefixable.lib.dart", EXTENSION_DEPS); } public void testModifyPrefixedLib() { @@ -122,12 +120,11 @@ public class IncrementalCompilationWithPrefixTest extends CompilerTestCase { someLibSource.remapSource("some.prefixable.lib.dart", "some.prefixable.modified.lib.dart"); compile(); - didWrite("my.prefixed.app.dart", EXTENSION_JS, provider); - didWrite("my.prefixed.app.dart", EXTENSION_APP_JS, provider); - didWrite("my.prefixed.app.dart", EXTENSION_DEPS, provider); - didWrite("some.prefixable.lib.dart", EXTENSION_JS, provider); - didWrite("some.prefixable.lib.dart", EXTENSION_DEPS, provider); - didWrite("some.prefixable.lib.dart", EXTENSION_API, provider); + didWrite("my.prefixed.app.dart", EXTENSION_JS); + didWrite("my.prefixed.app.dart", EXTENSION_APP_JS); + didWrite("my.prefixed.app.dart", EXTENSION_DEPS); + didWrite("some.prefixable.lib.dart", EXTENSION_JS); + didWrite("some.prefixable.lib.dart", EXTENSION_DEPS); } private void compile() { @@ -147,13 +144,8 @@ public class IncrementalCompilationWithPrefixTest extends CompilerTestCase { } } - private void didWrite(String sourceName, String extension, IncMockArtifactProvider provider) { + private void didWrite(String sourceName, String extension) { String spec = sourceName + "/" + extension; assertTrue("Expected write: " + spec, provider.writes.contains(spec)); } - - private void didNotWrite(String sourceName, String extension, IncMockArtifactProvider provider) { - String spec = sourceName + "/" + extension; - assertFalse("Didn't expect write: " + spec, provider.writes.contains(spec)); - } } diff --git a/compiler/javatests/com/google/dart/compiler/end2end/inc/MemoryLibrarySource.java b/compiler/javatests/com/google/dart/compiler/end2end/inc/MemoryLibrarySource.java new file mode 100644 index 00000000000..e0469f23fb1 --- /dev/null +++ b/compiler/javatests/com/google/dart/compiler/end2end/inc/MemoryLibrarySource.java @@ -0,0 +1,108 @@ +// Copyright (c) 2011, 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. +package com.google.dart.compiler.end2end.inc; + +import com.google.common.collect.Maps; +import com.google.dart.compiler.DartSource; +import com.google.dart.compiler.LibrarySource; +import com.google.dart.compiler.Source; +import com.google.dart.compiler.UrlDartSource; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Date; +import java.util.Map; + +/** + * {@link LibrarySource} which provides content for all {@link Source}s from memory. + */ +public class MemoryLibrarySource implements LibrarySource { + private final String libName; + private final String libContent; + private final Map sourceContentMap = Maps.newHashMap(); + private final Map sourceLastModifiedMap = Maps.newHashMap(); + + public MemoryLibrarySource(String libName, String libContent) throws URISyntaxException { + this.libName = libName; + this.libContent = libContent; + } + + @Override + public boolean exists() { + return true; + } + + @Override + public String getName() { + return libName; + } + + @Override + public URI getUri() { + return URI.create(libName); + } + + @Override + public long getLastModified() { + return 0; + } + + @Override + public Reader getSourceReader() throws IOException { + return new StringReader(libContent); + } + + @Override + public LibrarySource getImportFor(String relPath) throws IOException { + // Not implemented for now, tests which use it don't work with imports. + return null; + } + + @Override + public DartSource getSourceFor(final String relPath) { + final String content; + final Long sourceLastModified; + if (sourceContentMap.containsKey(relPath)) { + content = sourceContentMap.get(relPath); + sourceLastModified = sourceLastModifiedMap.get(relPath); + } else { + content = ""; + sourceLastModified = Long.valueOf(0); + } + // Return fake UrlDateSource with in-memory content. + URI uri = URI.create(relPath); + return new UrlDartSource(uri, relPath, this) { + @Override + public String getName() { + return relPath; + } + + @Override + public boolean exists() { + return true; + } + + @Override + public long getLastModified() { + return sourceLastModified.longValue(); + } + + @Override + public Reader getSourceReader() throws IOException { + return new StringReader(content); + } + }; + } + + /** + * Sets the given content for the source. + */ + public void setContent(String relPath, String content) { + sourceContentMap.put(relPath, content); + sourceLastModifiedMap.put(relPath, new Date().getTime()); + } +} diff --git a/compiler/javatests/com/google/dart/compiler/end2end/inc/my.app.dart b/compiler/javatests/com/google/dart/compiler/end2end/inc/my.app.dart index e02fbc69ba5..8a01c7486af 100644 --- a/compiler/javatests/com/google/dart/compiler/end2end/inc/my.app.dart +++ b/compiler/javatests/com/google/dart/compiler/end2end/inc/my.app.dart @@ -12,4 +12,4 @@ #source("myother4.dart"); #source("myother5.dart"); #source("myother6.dart"); -#source("myother7.dart"); \ No newline at end of file +#source("myother7.dart"); diff --git a/compiler/javatests/com/google/dart/compiler/parser/AbstractParserTest.java b/compiler/javatests/com/google/dart/compiler/parser/AbstractParserTest.java index cb49d74204c..7bc8f840c1e 100644 --- a/compiler/javatests/com/google/dart/compiler/parser/AbstractParserTest.java +++ b/compiler/javatests/com/google/dart/compiler/parser/AbstractParserTest.java @@ -158,8 +158,8 @@ public abstract class AbstractParserTest extends CompilerTestCase { @Override protected DartParser makeParser(ParserContext context) { - Set set = new HashSet(); - set.add("prefix"); - return new DartParser(context, set); + Set prefixes = new HashSet(); + prefixes.add("prefix"); + return new DartParser(context, prefixes, false); } } diff --git a/compiler/javatests/com/google/dart/compiler/parser/NegativeParserTest.java b/compiler/javatests/com/google/dart/compiler/parser/NegativeParserTest.java index 1987e6ddea7..003235ee79e 100644 --- a/compiler/javatests/com/google/dart/compiler/parser/NegativeParserTest.java +++ b/compiler/javatests/com/google/dart/compiler/parser/NegativeParserTest.java @@ -12,6 +12,8 @@ import com.google.dart.compiler.ast.DartIdentifier; import com.google.dart.compiler.ast.DartMethodDefinition; import com.google.dart.compiler.ast.DartUnit; +import java.util.Set; + /** * Negative Parser/Syntax tests. */ @@ -541,4 +543,93 @@ public class NegativeParserTest extends CompilerTestCase { "}"), parserRunner.getDartUnit().toSource()); } + + /** + * Test for {@link DartUnit#getTopDeclarationNames()}. + */ + public void test_getTopDeclarationNames() throws Exception { + DartParserRunner parserRunner = + parseSource(Joiner.on("\n").join( + "// filler filler filler filler filler filler filler filler filler filler", + "class MyClass {}", + "class MyInterface {}", + "topLevelMethod() {}", + "int get topLevelGetter() {return 0;}", + "void set topLevelSetter(int v) {}", + "typedef void MyTypeDef();", + "")); + DartUnit unit = parserRunner.getDartUnit(); + // Check top level declarations. + Set names = unit.getTopDeclarationNames(); + assertEquals(6, names.size()); + assertTrue(names.contains("MyClass")); + assertTrue(names.contains("MyInterface")); + assertTrue(names.contains("topLevelMethod")); + assertTrue(names.contains("topLevelGetter")); + assertTrue(names.contains("topLevelSetter")); + assertTrue(names.contains("MyTypeDef")); + } + + /** + * Test for {@link DartUnit#getDeclarationNames()}. + */ + public void test_getDeclarationNames() throws Exception { + DartParserRunner parserRunner = + parseSource(Joiner.on("\n").join( + "// filler filler filler filler filler filler filler filler filler filler", + "class MyClass {", + " myMethod(int pA, int pB) {", + " int varA;", + " try {", + " } catch(var ex) {", + " }", + " }", + "}", + "topLevelMethod() {}", + "int get topLevelGetter() {return 0;}", + "void set topLevelSetter(int setterParam) {}", + "typedef void MyTypeDef();", + "")); + DartUnit unit = parserRunner.getDartUnit(); + // Check all declarations. + Set names = unit.getDeclarationNames(); + assertEquals(12, names.size()); + assertTrue(names.contains("MyClass")); + assertTrue(names.contains("TypeVar")); + assertTrue(names.contains("myMethod")); + assertTrue(names.contains("pA")); + assertTrue(names.contains("pB")); + assertTrue(names.contains("varA")); + assertTrue(names.contains("ex")); + assertTrue(names.contains("topLevelMethod")); + assertTrue(names.contains("topLevelGetter")); + assertTrue(names.contains("topLevelSetter")); + assertTrue(names.contains("setterParam")); + assertTrue(names.contains("MyTypeDef")); + } + + /** + * There was bug in diet parser, it did not understand new "arrow" syntax of function definition. + */ + public void test_dietParser_functionArrow() { + DartParserRunner parserRunner = + DartParserRunner.parse( + getName(), + Joiner.on("\n").join( + "class ClassWithVeryLongNameEnoughToForceLineWrapping {", + " foo() => return 0;", + "}", + ""), + true); + assertErrors(parserRunner.getErrors()); + assertEquals( + Joiner.on("\n").join( + "// unit " + getName(), + "class ClassWithVeryLongNameEnoughToForceLineWrapping {", + "", + " foo() {", + " }", + "}"), + parserRunner.getDartUnit().toSource().trim()); + } } diff --git a/compiler/javatests/com/google/dart/compiler/resolver/NegativeResolverTest.java b/compiler/javatests/com/google/dart/compiler/resolver/NegativeResolverTest.java index 82993a7f864..eac32375f49 100644 --- a/compiler/javatests/com/google/dart/compiler/resolver/NegativeResolverTest.java +++ b/compiler/javatests/com/google/dart/compiler/resolver/NegativeResolverTest.java @@ -314,6 +314,16 @@ public class NegativeResolverTest extends CompilerTestCase { checkNumErrors("ConstVariableInitializationNegativeTest2.dart", 1); } + public void test_nameShadow_topLevel_method_class() { + checkSourceErrors( + makeCode( + "// filler filler filler filler filler filler filler filler filler filler", + "foo() {}", + "class foo {}"), + errEx(ResolverErrorCode.DUPLICATE_TOP_LEVEL_DEFINITION, 2, 1, 3), + errEx(ResolverErrorCode.DUPLICATE_TOP_LEVEL_DEFINITION, 3, 7, 3)); + } + public void test_nameShadow_topLevel_getterSetter_class() { checkSourceErrors( makeCode( diff --git a/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java b/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java index 11e487a90a3..cc0992d9c17 100644 --- a/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java +++ b/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java @@ -11,6 +11,7 @@ import com.google.common.collect.Iterables; import com.google.dart.compiler.CompilerTestCase; import com.google.dart.compiler.DartCompilationError; import com.google.dart.compiler.ast.DartClass; +import com.google.dart.compiler.ast.DartExprStmt; import com.google.dart.compiler.ast.DartExpression; import com.google.dart.compiler.ast.DartField; import com.google.dart.compiler.ast.DartFieldDefinition; @@ -23,6 +24,8 @@ import com.google.dart.compiler.ast.DartNode; import com.google.dart.compiler.ast.DartNodeTraverser; import com.google.dart.compiler.ast.DartParameter; import com.google.dart.compiler.ast.DartUnit; +import com.google.dart.compiler.ast.DartUnqualifiedInvocation; +import com.google.dart.compiler.common.Symbol; import com.google.dart.compiler.parser.ParserErrorCode; import com.google.dart.compiler.resolver.ClassElement; import com.google.dart.compiler.resolver.Element; @@ -728,4 +731,35 @@ public class TypeAnalyzerCompilerTest extends CompilerTestCase { "}")); assertErrors(libraryResult.getTypeErrors()); } + + public void test_bindToLibraryFunctionFirst() throws Exception { + AnalyzeLibraryResult libraryResult = + analyzeLibrary( + getName(), + makeCode( + "// filler filler filler filler filler filler filler filler filler filler", + "foo() {}", + "class A {", + " foo() {}", + "}", + "class B extends A {", + " bar() {", + " foo();", + " }", + "}", + "")); + DartUnit unit = libraryResult.getLibraryUnitResult().getUnit(getName()); + // Find foo() invocation. + DartUnqualifiedInvocation invocation; + { + DartClass classB = (DartClass) unit.getTopLevelNodes().get(2); + DartMethodDefinition methodBar = (DartMethodDefinition) classB.getMembers().get(0); + DartExprStmt stmt = (DartExprStmt) methodBar.getFunction().getBody().getStatements().get(0); + invocation = (DartUnqualifiedInvocation) stmt.getExpression(); + } + // Check that unqualified foo() invocation is resolved to the top-level (library) function. + Symbol symbol = invocation.getTarget().getSymbol(); + assertNotNull(symbol); + assertSame(unit, symbol.getNode().getParent()); + } }