b2e15e7451
This is preparation for avoiding calling Element.getNode() during analysis. R=brianwilkerson@google.com,zundel@google.com BUG= TEST= Review URL: https://chromiumcodereview.appspot.com//9651004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@5208 260f80e4-7a28-3924-810f-c04153c831b5
314 lines
8.8 KiB
Java
314 lines
8.8 KiB
Java
// 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.Writer;
|
|
import java.net.URI;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
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, 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 unitName;
|
|
private final long lastModified;
|
|
|
|
public Dependency(URI libUri, String unitName, long lastModified) {
|
|
this.libUri = libUri;
|
|
this.unitName = unitName;
|
|
this.lastModified = lastModified;
|
|
}
|
|
|
|
@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;
|
|
}
|
|
}
|
|
|
|
public static class Source {
|
|
private final Set<Dependency> deps = Sets.newHashSet();
|
|
private final Set<String> topSymbols = Sets.newHashSet();
|
|
private final Set<String> allSymbols = Sets.newHashSet();
|
|
private final Set<String> holes = Sets.newHashSet();
|
|
private boolean shouldRecompileOnAnyTopLevelChange = false;
|
|
|
|
/**
|
|
* @return the {@link Set} of {@link Dependency}s.
|
|
*/
|
|
public Set<Dependency> getDeps() {
|
|
return deps;
|
|
}
|
|
|
|
/**
|
|
* @return the names of top-level elements, such as methods and classes.
|
|
*/
|
|
public Set<String> getTopSymbols() {
|
|
return topSymbols;
|
|
}
|
|
|
|
/**
|
|
* @return the names of all elements in unit, such as names of local variables, fields, etc.
|
|
*/
|
|
public Set<String> getAllSymbols() {
|
|
return allSymbols;
|
|
}
|
|
|
|
/**
|
|
* @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<String> getHoles() {
|
|
return holes;
|
|
}
|
|
|
|
/**
|
|
* @return <code>true</code> 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) {
|
|
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);
|
|
// 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<String> topSymbols = Splitter.on(' ').omitEmptyStrings().split(line);
|
|
Iterables.addAll(source.topSymbols, topSymbols);
|
|
}
|
|
// Read all symbols.
|
|
{
|
|
String line = buf.readLine();
|
|
Iterable<String> allSymbols = Splitter.on(' ').omitEmptyStrings().split(line);
|
|
Iterables.addAll(source.allSymbols, allSymbols);
|
|
}
|
|
// Read holes.
|
|
{
|
|
String line = buf.readLine();
|
|
Iterable<String> 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(" ");
|
|
source.deps.add(new Dependency(new URI(parts[0]), parts[1], Long.parseLong(parts[2])));
|
|
}
|
|
// Remember dependencies for current unit.
|
|
deps.sources.put(relPath, source);
|
|
}
|
|
return deps;
|
|
}
|
|
|
|
private final Map<String, Source> sources = Maps.newHashMap();
|
|
|
|
public LibraryDeps() {
|
|
}
|
|
|
|
/**
|
|
* @return the relative paths of all units with remembered dependencies.
|
|
*/
|
|
public Set<String> getUnitPaths() {
|
|
return sources.keySet();
|
|
}
|
|
|
|
/**
|
|
* @return all {@link Source} descriptions for all units in this library.
|
|
*/
|
|
public Iterable<Source> getSources() {
|
|
return sources.values();
|
|
}
|
|
|
|
/**
|
|
* @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();
|
|
DartSource unitSource = (DartSource) unit.getSourceInfo().getSource();
|
|
String relPath = unitSource.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<DartCompilationError> sourceErrors = context.getSourceErrors(unitSource);
|
|
for (DartCompilationError error : sourceErrors) {
|
|
if (error.getErrorCode().needsRecompilation()) {
|
|
source.shouldRecompileOnAnyTopLevelChange = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void write(Writer writer) throws IOException {
|
|
// Write version.
|
|
writer.write(VERSION);
|
|
writer.write('\n');
|
|
// Write entries.
|
|
for (Entry<String, Source> entry : sources.entrySet()) {
|
|
String relPath = entry.getKey();
|
|
Source source = entry.getValue();
|
|
// Unit name.
|
|
writer.write(relPath);
|
|
writer.write('\n');
|
|
// 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');
|
|
}
|
|
}
|
|
}
|