/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.engine.context;
import com.google.dart.engine.element.ClassElement;
import com.google.dart.engine.element.ConstructorElement;
import com.google.dart.engine.element.FunctionElement;
import com.google.dart.engine.element.LibraryElement;
import com.google.dart.engine.element.MethodElement;
import com.google.dart.engine.element.ParameterElement;
import com.google.dart.engine.element.PropertyAccessorElement;
import com.google.dart.engine.element.TopLevelVariableElement;
import com.google.dart.engine.internal.context.AnalysisContextImpl;
import com.google.dart.engine.internal.context.TimestampedData;
import com.google.dart.engine.internal.element.ClassElementImpl;
import com.google.dart.engine.internal.element.CompilationUnitElementImpl;
import com.google.dart.engine.internal.element.ConstructorElementImpl;
import com.google.dart.engine.internal.element.FunctionTypeAliasElementImpl;
import com.google.dart.engine.internal.element.LibraryElementImpl;
import com.google.dart.engine.internal.element.ParameterElementImpl;
import com.google.dart.engine.internal.element.TopLevelVariableElementImpl;
import com.google.dart.engine.internal.resolver.TestTypeProvider;
import com.google.dart.engine.internal.sdk.LibraryMap;
import com.google.dart.engine.internal.sdk.SdkLibraryImpl;
import com.google.dart.engine.internal.type.FunctionTypeImpl;
import com.google.dart.engine.sdk.DartSdk;
import com.google.dart.engine.sdk.DirectoryBasedDartSdk;
import com.google.dart.engine.source.DartUriResolver;
import com.google.dart.engine.source.FileUriResolver;
import com.google.dart.engine.source.Source;
import com.google.dart.engine.source.SourceFactory;
import com.google.dart.engine.type.InterfaceType;
import com.google.dart.engine.type.Type;
import com.google.dart.engine.utilities.dart.ParameterKind;
import static com.google.dart.engine.ast.AstFactory.libraryIdentifier;
import static com.google.dart.engine.element.ElementFactory.classElement;
import static com.google.dart.engine.element.ElementFactory.constructorElement;
import static com.google.dart.engine.element.ElementFactory.functionElement;
import static com.google.dart.engine.element.ElementFactory.getterElement;
import static com.google.dart.engine.element.ElementFactory.methodElement;
import static com.google.dart.engine.element.ElementFactory.methodElementWithParameters;
import static com.google.dart.engine.element.ElementFactory.namedParameter;
import static com.google.dart.engine.element.ElementFactory.positionalParameter;
import static com.google.dart.engine.element.ElementFactory.requiredParameter;
import static com.google.dart.engine.element.ElementFactory.topLevelVariableElement;
import junit.framework.Assert;
import java.io.File;
import java.util.HashMap;
/**
* The class {@code AnalysisContextFactory} defines utility methods used to create analysis contexts
* for testing purposes.
*/
public final class AnalysisContextFactory {
/**
* Instances of the class {@code AnalysisContextForTests} implement an analysis context that has a
* fake SDK that is much smaller and faster for testing purposes.
*/
public static class AnalysisContextForTests extends AnalysisContextImpl {
@Override
public boolean exists(Source source) {
return super.exists(source) || getSourceFactory().getDartSdk().getContext().exists(source);
}
@Override
public TimestampedData<CharSequence> getContents(Source source) throws Exception {
if (source.isInSystemLibrary()) {
return getSourceFactory().getDartSdk().getContext().getContents(source);
}
return super.getContents(source);
}
@Override
public long getModificationStamp(Source source) {
if (source.isInSystemLibrary()) {
return getSourceFactory().getDartSdk().getContext().getModificationStamp(source);
}
return super.getModificationStamp(source);
}
@Override
public void setAnalysisOptions(AnalysisOptions options) {
AnalysisOptions currentOptions = getAnalysisOptions();
boolean needsRecompute = currentOptions.getAnalyzeFunctionBodies() != options.getAnalyzeFunctionBodies()
|| currentOptions.getGenerateSdkErrors() != options.getGenerateSdkErrors()
|| currentOptions.getEnableAsync() != options.getEnableAsync()
|| currentOptions.getEnableDeferredLoading() != options.getEnableDeferredLoading()
|| currentOptions.getEnableEnum() != options.getEnableEnum()
|| currentOptions.getDart2jsHint() != options.getDart2jsHint()
|| (currentOptions.getHint() && !options.getHint())
|| currentOptions.getPreserveComments() != options.getPreserveComments();
if (needsRecompute) {
Assert.fail("Cannot set options that cause the sources to be reanalyzed in a test context");
}
super.setAnalysisOptions(options);
}
/**
* Set the analysis options, even if they would force re-analysis. This method should only be
* invoked before the fake SDK is initialized.
*
* @param options the analysis options to be set
*/
private void internalSetAnalysisOptions(AnalysisOptions options) {
super.setAnalysisOptions(options);
}
}
private static final String DART_MATH = "dart:math";
private static final String DART_INTERCEPTORS = "dart:_interceptors";
private static final String DART_JS_HELPER = "dart:_js_helper";
/**
* The fake SDK used by all of the contexts created by this factory.
*/
private static DirectoryBasedDartSdk FAKE_SDK;
/**
* Create an analysis context that has a fake core library already resolved.
*
* @return the analysis context that was created
*/
public static AnalysisContextImpl contextWithCore() {
AnalysisContextForTests context = new AnalysisContextForTests();
return initContextWithCore(context);
}
/**
* Create an analysis context that uses the given options and has a fake core library already
* resolved.
*
* @param options the options to be applied to the context
* @return the analysis context that was created
*/
public static AnalysisContextImpl contextWithCoreAndOptions(AnalysisOptions options) {
AnalysisContextForTests context = new AnalysisContextForTests();
context.internalSetAnalysisOptions(options);
return initContextWithCore(context);
}
/**
* Initialize the given analysis context with a fake core library already resolved.
*
* @param context the context to be initialized (not {@code null})
* @return the analysis context that was created
*/
public static AnalysisContextImpl initContextWithCore(AnalysisContextImpl context) {
DirectoryBasedDartSdk sdk = new DirectoryBasedDartSdk(new File("/fake/sdk")) {
@Override
protected LibraryMap initialLibraryMap(boolean useDart2jsPaths) {
LibraryMap map = new LibraryMap();
addLibrary(map, DART_ASYNC, false, "async.dart");
addLibrary(map, DART_CORE, false, "core.dart");
addLibrary(map, DART_HTML, false, "html_dartium.dart");
addLibrary(map, DART_MATH, false, "math.dart");
addLibrary(map, DART_INTERCEPTORS, true, "_interceptors.dart");
addLibrary(map, DART_JS_HELPER, true, "_js_helper.dart");
return map;
}
private void addLibrary(LibraryMap map, String uri, boolean isInternal, String path) {
SdkLibraryImpl library = new SdkLibraryImpl(uri);
if (isInternal) {
library.setCategory("Internal");
}
library.setPath(path);
map.setLibrary(uri, library);
}
};
SourceFactory sourceFactory = new SourceFactory(new DartUriResolver(sdk), new FileUriResolver());
context.setSourceFactory(sourceFactory);
AnalysisContext coreContext = sdk.getContext();
//
// dart:core
//
TestTypeProvider provider = new TestTypeProvider();
CompilationUnitElementImpl coreUnit = new CompilationUnitElementImpl("core.dart");
Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE);
coreContext.setContents(coreSource, "");
coreUnit.setSource(coreSource);
ClassElementImpl proxyClassElement = classElement("_Proxy");
coreUnit.setTypes(new ClassElement[] {
provider.getBoolType().getElement(), provider.getDeprecatedType().getElement(),
provider.getDoubleType().getElement(), provider.getFunctionType().getElement(),
provider.getIntType().getElement(), provider.getIterableType().getElement(),
provider.getListType().getElement(), provider.getMapType().getElement(),
provider.getNullType().getElement(), provider.getNumType().getElement(),
provider.getObjectType().getElement(), proxyClassElement,
provider.getStackTraceType().getElement(), provider.getStringType().getElement(),
provider.getSymbolType().getElement(), provider.getTypeType().getElement()});
coreUnit.setFunctions(new FunctionElement[] {functionElement(
"identical",
provider.getBoolType().getElement(),
new ClassElement[] {
provider.getObjectType().getElement(), provider.getObjectType().getElement()},
null)});
TopLevelVariableElement proxyTopLevelVariableElt = topLevelVariableElement(
"proxy",
true,
false,
proxyClassElement.getType());
TopLevelVariableElement deprecatedTopLevelVariableElt = topLevelVariableElement(
"deprecated",
true,
false,
provider.getDeprecatedType());
coreUnit.setAccessors(new PropertyAccessorElement[] {
proxyTopLevelVariableElt.getGetter(), proxyTopLevelVariableElt.getSetter(),
deprecatedTopLevelVariableElt.getGetter(), deprecatedTopLevelVariableElt.getSetter()});
coreUnit.setTopLevelVariables(new TopLevelVariableElement[] {
proxyTopLevelVariableElt, deprecatedTopLevelVariableElt});
LibraryElementImpl coreLibrary = new LibraryElementImpl(coreContext, libraryIdentifier(
"dart",
"core"));
coreLibrary.setDefiningCompilationUnit(coreUnit);
//
// dart:async
//
CompilationUnitElementImpl asyncUnit = new CompilationUnitElementImpl("async.dart");
Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
coreContext.setContents(asyncSource, "");
asyncUnit.setSource(asyncSource);
// Future
ClassElementImpl futureElement = classElement("Future", "T");
InterfaceType futureType = futureElement.getType();
// factory Future.value([value])
ConstructorElementImpl futureConstructor = constructorElement(futureElement, "value");
futureConstructor.setParameters(new ParameterElement[] {positionalParameter(
"value",
provider.getDynamicType())});
futureConstructor.setFactory(true);
((FunctionTypeImpl) futureConstructor.getType()).setTypeArguments(futureElement.getType().getTypeArguments());
futureElement.setConstructors(new ConstructorElement[] {futureConstructor});
// Future then(onValue(T value), { Function onError });
ParameterElement[] parameters = new ParameterElement[] {requiredParameter(
"value",
futureElement.getTypeParameters()[0].getType())};
FunctionTypeAliasElementImpl aliasElement = new FunctionTypeAliasElementImpl(null);
aliasElement.setSynthetic(true);
aliasElement.shareParameters(parameters);
aliasElement.setReturnType(provider.getDynamicType());
FunctionTypeImpl aliasType = new FunctionTypeImpl(aliasElement);
aliasElement.shareTypeParameters(futureElement.getTypeParameters());
aliasType.setTypeArguments(futureElement.getType().getTypeArguments());
MethodElement thenMethod = methodElementWithParameters(
"then",
futureElement.getType().getTypeArguments(),
futureType,
requiredParameter("onValue", aliasType),
namedParameter("onError", provider.getFunctionType()));
futureElement.setMethods(new MethodElement[] {thenMethod});
// Completer
ClassElementImpl completerElement = classElement("Completer", "T");
ConstructorElementImpl completerConstructor = constructorElement(completerElement, null);
((FunctionTypeImpl) completerConstructor.getType()).setTypeArguments(completerElement.getType().getTypeArguments());
completerElement.setConstructors(new ConstructorElement[] {completerConstructor});
asyncUnit.setTypes(new ClassElement[] {
completerElement, futureElement, classElement("Stream", "T")});
LibraryElementImpl asyncLibrary = new LibraryElementImpl(coreContext, libraryIdentifier(
"dart",
"async"));
asyncLibrary.setDefiningCompilationUnit(asyncUnit);
//
// dart:html
//
CompilationUnitElementImpl htmlUnit = new CompilationUnitElementImpl("html_dartium.dart");
Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML);
coreContext.setContents(htmlSource, "");
htmlUnit.setSource(htmlSource);
ClassElementImpl elementElement = classElement("Element");
InterfaceType elementType = elementElement.getType();
ClassElementImpl canvasElement = classElement("CanvasElement", elementType);
ClassElementImpl contextElement = classElement("CanvasRenderingContext");
InterfaceType contextElementType = contextElement.getType();
ClassElementImpl context2dElement = classElement("CanvasRenderingContext2D", contextElementType);
canvasElement.setMethods(new MethodElement[] {methodElement(
"getContext",
contextElementType,
provider.getStringType())});
canvasElement.setAccessors(new PropertyAccessorElement[] {getterElement(
"context2D",
false,
context2dElement.getType())});
ClassElementImpl documentElement = classElement("Document", elementType);
ClassElementImpl htmlDocumentElement = classElement("HtmlDocument", documentElement.getType());
htmlDocumentElement.setMethods(new MethodElement[] {methodElement(
"query",
elementType,
new Type[] {provider.getStringType()})});
htmlUnit.setTypes(new ClassElement[] {
classElement("AnchorElement", elementType), classElement("BodyElement", elementType),
classElement("ButtonElement", elementType), canvasElement, contextElement,
context2dElement, classElement("DivElement", elementType), documentElement, elementElement,
htmlDocumentElement, classElement("InputElement", elementType),
classElement("SelectElement", elementType)});
htmlUnit.setFunctions(new FunctionElement[] {functionElement(
"query",
elementElement,
new ClassElement[] {provider.getStringType().getElement()},
ClassElementImpl.EMPTY_ARRAY)});
TopLevelVariableElementImpl document = topLevelVariableElement(
"document",
false,
true,
htmlDocumentElement.getType());
htmlUnit.setTopLevelVariables(new TopLevelVariableElement[] {document});
htmlUnit.setAccessors(new PropertyAccessorElement[] {document.getGetter()});
LibraryElementImpl htmlLibrary = new LibraryElementImpl(coreContext, libraryIdentifier(
"dart",
"dom",
"html"));
htmlLibrary.setDefiningCompilationUnit(htmlUnit);
//
// dart:math
//
CompilationUnitElementImpl mathUnit = new CompilationUnitElementImpl("math.dart");
Source mathSource = sourceFactory.forUri(DART_MATH);
coreContext.setContents(mathSource, "");
mathUnit.setSource(mathSource);
FunctionElement cosElement = functionElement(
"cos",
provider.getDoubleType().getElement(),
new ClassElement[] {provider.getNumType().getElement()},
new ClassElement[] {});
TopLevelVariableElement ln10Element = topLevelVariableElement(
"LN10",
true,
false,
provider.getDoubleType());
TopLevelVariableElement piElement = topLevelVariableElement(
"PI",
true,
false,
provider.getDoubleType());
ClassElementImpl randomElement = classElement("Random");
randomElement.setAbstract(true);
ConstructorElementImpl randomConstructor = constructorElement(randomElement, null);
randomConstructor.setFactory(true);
ParameterElementImpl seedParam = new ParameterElementImpl("seed", 0);
seedParam.setParameterKind(ParameterKind.POSITIONAL);
seedParam.setType(provider.getIntType());
randomConstructor.setParameters(new ParameterElement[] {seedParam});
randomElement.setConstructors(new ConstructorElement[] {randomConstructor});
FunctionElement sinElement = functionElement(
"sin",
provider.getDoubleType().getElement(),
new ClassElement[] {provider.getNumType().getElement()},
new ClassElement[] {});
FunctionElement sqrtElement = functionElement(
"sqrt",
provider.getDoubleType().getElement(),
new ClassElement[] {provider.getNumType().getElement()},
new ClassElement[] {});
mathUnit.setAccessors(new PropertyAccessorElement[] {
ln10Element.getGetter(), piElement.getGetter()});
mathUnit.setFunctions(new FunctionElement[] {cosElement, sinElement, sqrtElement});
mathUnit.setTopLevelVariables(new TopLevelVariableElement[] {ln10Element, piElement});
mathUnit.setTypes(new ClassElement[] {randomElement});
LibraryElementImpl mathLibrary = new LibraryElementImpl(coreContext, libraryIdentifier(
"dart",
"math"));
mathLibrary.setDefiningCompilationUnit(mathUnit);
//
// Set empty sources for the rest of the libraries.
//
Source source = sourceFactory.forUri(DART_INTERCEPTORS);
coreContext.setContents(source, "");
source = sourceFactory.forUri(DART_JS_HELPER);
coreContext.setContents(source, "");
//
// Record the elements.
//
HashMap<Source, LibraryElement> elementMap = new HashMap<Source, LibraryElement>();
elementMap.put(coreSource, coreLibrary);
elementMap.put(asyncSource, asyncLibrary);
elementMap.put(htmlSource, htmlLibrary);
elementMap.put(mathSource, mathLibrary);
context.recordLibraryElements(elementMap);
return context;
}
/**
* Prevent the creation of instances of this class.
*/
private AnalysisContextFactory() {
}
}