Using 'interface' and 'abstract' for methods should produce error
R=brianwilkerson@google.com BUG= Review URL: https://codereview.chromium.org//11314019 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@14165 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -332,6 +332,13 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
} else if (peekPseudoKeyword(0, INTERFACE_KEYWORD) && peek(1).equals(Token.IDENTIFIER)) {
|
||||
consume(Token.IDENTIFIER);
|
||||
isParsingInterface = true;
|
||||
// TODO(scheglov) remove after http://code.google.com/p/dart/issues/detail?id=6318
|
||||
if (!Elements.isCoreLibrarySource(source)
|
||||
&& !Elements.isLibrarySource(source, "/isolate/isolate.dart")
|
||||
&& !Elements.isLibrarySource(source, "crypto/crypto.dart")
|
||||
&& !Elements.isDart2JsLibrarySource(source)) {
|
||||
reportError(position(), ParserErrorCode.DEPRECATED_INTERFACE);
|
||||
}
|
||||
node = done(parseClass());
|
||||
} else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
|
||||
&& (peek(1).equals(Token.IDENTIFIER) || peek(1).equals(Token.VOID) || peek(1).equals(Token.AS))) {
|
||||
@@ -1258,9 +1265,6 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
}
|
||||
}
|
||||
if (optionalPseudoKeyword(ABSTRACT_KEYWORD)) {
|
||||
if (isParsingInterface) {
|
||||
reportError(position(), ParserErrorCode.ABSTRACT_MEMBER_IN_INTERFACE);
|
||||
}
|
||||
if (modifiers.isStatic()) {
|
||||
reportError(position(), ParserErrorCode.STATIC_MEMBERS_CANNOT_BE_ABSTRACT);
|
||||
}
|
||||
@@ -1291,6 +1295,22 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
reportError(position(), ParserErrorCode.DISALLOWED_FACTORY_KEYWORD);
|
||||
}
|
||||
}
|
||||
|
||||
// report "abstract" warning after all other checks to don't hide error with warning
|
||||
// we ignore problems if there was already reported problem after given position
|
||||
if (modifiers.isAbstract()) {
|
||||
// TODO(scheglov) remove after http://code.google.com/p/dart/issues/detail?id=6322
|
||||
// TODO(scheglov) remove after http://code.google.com/p/dart/issues/detail?id=6323
|
||||
if (!Elements.isCoreLibrarySource(source)
|
||||
&& !Elements.isLibrarySource(source, "html/dartium/html_dartium.dart")
|
||||
&& !Elements.isLibrarySource(source, "/math/math.dart")
|
||||
&& !Elements.isLibrarySource(source, "/io/io_runtime.dart")
|
||||
&& !Elements.isLibrarySource(source, "/crypto/crypto.dart")
|
||||
&& !Elements.isLibrarySource(source, "/utf/utf.dart")
|
||||
&& !Elements.isDart2JsLibrarySource(source)) {
|
||||
reportError(position(), ParserErrorCode.DEPRECATED_ABSTRACT_METHOD);
|
||||
}
|
||||
}
|
||||
|
||||
if (modifiers.isFactory()) {
|
||||
if (!isParsingClass) {
|
||||
|
||||
@@ -33,8 +33,10 @@ public enum ParserErrorCode implements ErrorCode {
|
||||
DEFAULT_POSITIONAL_PARAMETER("Positional parameters cannot have default values"),
|
||||
DEPRECATED_CATCH("This style of catch clause has been deprecated. Please use the 'on' <type> " +
|
||||
"'catch' '(' <identifier> (',' <identifier>)? ')' form."),
|
||||
DEPRECATED_ABSTRACT_METHOD(ErrorSeverity.WARNING, "Modifier 'abstract' is deprecated for methods without body. Remove it."),
|
||||
DEPRECATED_GETTER("The presence of parentheses after the name of the getter "
|
||||
+ "has been deprecated and will soon be disallowed. Please remove the parentheses."),
|
||||
DEPRECATED_INTERFACE("Deprecated declaration of the 'interface', use abstract 'class' instead"),
|
||||
DEPRECATED_USE_OF_FACTORY_KEYWORD("Deprecated use of the 'factory' keyword: use 'default' instead"),
|
||||
DEPRECATED_RAW_STRING("The use of '@' to prefix a raw string has been deprecated; use 'r' instead"),
|
||||
DEPRECATED_RESOURCE_DIRECTIVE("The #resource directive has been deprecated and will soon be disallowed"),
|
||||
@@ -73,9 +75,9 @@ public enum ParserErrorCode implements ErrorCode {
|
||||
EXPECTED_TOKEN("Unexpected token '%s' (expected '%s')"),
|
||||
// TODO(zundel): error message needs JUnit test
|
||||
EXPECTED_VAR_FINAL_OR_TYPE("Expected 'var', 'final' or type"),
|
||||
EXTERNAL_ABSTRACT("External methods cannot be abstract"),
|
||||
EXTERNAL_ONLY_METHOD("Only a top-level function, a method, a getter, a setter or an non-redirecting constructor can be specified as external"),
|
||||
EXTERNAL_METHOD_BODY("External methods cannot have body"),
|
||||
EXTERNAL_ABSTRACT("External methods cannot be abstract"),
|
||||
INVALID_SEPARATOR_FOR_NAMED("Use ':' between a named parameter and its value"),
|
||||
INVALID_SEPARATOR_FOR_OPTIONAL("Use '=' between an optional parameter and its value"),
|
||||
// TODO(zundel): this error message is out of date
|
||||
|
||||
@@ -727,6 +727,21 @@ static FieldElementImplementation fieldFromNode(DartField node,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if given {@link Source} represents library with given name.
|
||||
*/
|
||||
public static boolean isDart2JsLibrarySource(Source source) {
|
||||
if (source instanceof DartSource) {
|
||||
DartSource dartSource = (DartSource) source;
|
||||
LibrarySource library = dartSource.getLibrary();
|
||||
if (library != null) {
|
||||
String libraryName = library.getName();
|
||||
return libraryName.contains("lib/compiler/implementation/");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if given {@link Source} represents code library declaration or
|
||||
|
||||
@@ -84,7 +84,6 @@ import com.google.dart.compiler.type.Type;
|
||||
import com.google.dart.compiler.type.TypeKind;
|
||||
import com.google.dart.compiler.type.TypeVariable;
|
||||
import com.google.dart.compiler.type.Types;
|
||||
import com.google.dart.compiler.util.apache.StringUtils;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
@@ -379,14 +378,6 @@ public class Resolver {
|
||||
|
||||
// Make sure the default class matches the interface type parameters
|
||||
checkInterfaceTypeParamsToDefault(classElement, defaultClass);
|
||||
|
||||
// Check that interface constructors have corresponding methods in default class.
|
||||
checkInterfaceConstructors(classElement);
|
||||
} else if (classElement.isInterface() && classElement.getConstructors() != null) {
|
||||
for (ConstructorElement interfaceConstructor : classElement.getConstructors()) {
|
||||
onError(interfaceConstructor.getNameLocation(),
|
||||
ResolverErrorCode.ILLEGAL_CONSTRUCTOR_NO_DEFAULT_IN_INTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!classElement.isInterface() && Elements.needsImplicitDefaultConstructor(classElement)) {
|
||||
@@ -549,73 +540,6 @@ public class Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that interface constructors have corresponding methods in default class.
|
||||
*/
|
||||
private void checkInterfaceConstructors(ClassElement interfaceElement) {
|
||||
String interfaceClassName = interfaceElement.getName();
|
||||
String defaultClassName = interfaceElement.getDefaultClass().getElement().getName();
|
||||
|
||||
for (ConstructorElement interfaceConstructor : interfaceElement.getConstructors()) {
|
||||
ConstructorElement defaultConstructor =
|
||||
resolveInterfaceConstructorInDefaultClass(
|
||||
interfaceConstructor,
|
||||
interfaceConstructor);
|
||||
if (defaultConstructor != null) {
|
||||
// Remember for TypeAnalyzer.
|
||||
interfaceConstructor.setDefaultConstructor(defaultConstructor);
|
||||
// Validate number of required parameters.
|
||||
{
|
||||
int numReqInterface = Elements.getNumberOfRequiredParameters(interfaceConstructor);
|
||||
int numReqDefault = Elements.getNumberOfRequiredParameters(defaultConstructor);
|
||||
if (numReqInterface != numReqDefault) {
|
||||
onError(
|
||||
interfaceConstructor,
|
||||
ResolverErrorCode.DEFAULT_CONSTRUCTOR_NUMBER_OF_REQUIRED_PARAMETERS,
|
||||
Elements.getRawMethodName(interfaceConstructor),
|
||||
interfaceClassName,
|
||||
numReqInterface,
|
||||
Elements.getRawMethodName(defaultConstructor),
|
||||
defaultClassName,
|
||||
numReqDefault);
|
||||
}
|
||||
}
|
||||
// Validate number of required parameters.
|
||||
{
|
||||
int numInterface = Elements.getNumberOfOptionalPositionalParameters(interfaceConstructor);
|
||||
int numDefault = Elements.getNumberOfOptionalPositionalParameters(defaultConstructor);
|
||||
if (numInterface != numDefault) {
|
||||
onError(
|
||||
interfaceConstructor,
|
||||
ResolverErrorCode.DEFAULT_CONSTRUCTOR_OPTIONAL_POSITIONAL_PARAMETERS,
|
||||
Elements.getRawMethodName(interfaceConstructor),
|
||||
interfaceClassName,
|
||||
numInterface,
|
||||
Elements.getRawMethodName(defaultConstructor),
|
||||
defaultClassName,
|
||||
numDefault);
|
||||
}
|
||||
}
|
||||
// Validate names of named parameters.
|
||||
{
|
||||
List<String> interfaceNames = Elements.getNamedParameters(interfaceConstructor);
|
||||
List<String> defaultNames = Elements.getNamedParameters(defaultConstructor);
|
||||
if (!interfaceNames.equals(defaultNames)) {
|
||||
onError(
|
||||
interfaceConstructor,
|
||||
ResolverErrorCode.DEFAULT_CONSTRUCTOR_NAMED_PARAMETERS,
|
||||
Elements.getRawMethodName(interfaceConstructor),
|
||||
interfaceClassName,
|
||||
interfaceNames,
|
||||
Elements.getRawMethodName(defaultConstructor),
|
||||
defaultClassName,
|
||||
defaultNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the {@link ClassElement} has an implicit or a declared
|
||||
* default constructor.
|
||||
@@ -1717,9 +1641,6 @@ public class Resolver {
|
||||
// Will check that element is not null.
|
||||
ConstructorElement constructor = checkIsConstructor(x, element);
|
||||
|
||||
// try to lookup the constructor in the default class.
|
||||
constructor = resolveInterfaceConstructorInDefaultClass(x.getConstructor(), constructor);
|
||||
|
||||
// Check constructor.
|
||||
if (constructor != null) {
|
||||
boolean constConstructor = constructor.getModifiers().isConstant();
|
||||
@@ -1742,87 +1663,6 @@ public class Resolver {
|
||||
return recordElement(x, constructor);
|
||||
}
|
||||
|
||||
/**
|
||||
* If given {@link ConstructorElement} is declared in interface, try to resolve it in
|
||||
* corresponding default class.
|
||||
*
|
||||
* @return the resolved {@link ConstructorElement}, or same as given.
|
||||
*/
|
||||
private ConstructorElement resolveInterfaceConstructorInDefaultClass(HasSourceInfo errorTarget,
|
||||
ConstructorElement constructor) {
|
||||
// If no default class, use existing constructor.
|
||||
if (constructor == null || constructor.getConstructorType().getDefaultClass() == null) {
|
||||
return constructor;
|
||||
}
|
||||
// Prepare elements and names for classes.
|
||||
ClassElement originalClass = constructor.getConstructorType();
|
||||
ClassElement defaultClass = originalClass.getDefaultClass().getElement();
|
||||
String originalClassName = originalClass.getName();
|
||||
String defaultClassName = defaultClass.getName();
|
||||
// Prepare "qualifier.name" for original constructor.
|
||||
String rawOriginalMethodName = Elements.getRawMethodName(constructor);
|
||||
int originalDotIndex = rawOriginalMethodName.indexOf('.');
|
||||
String originalQualifier = StringUtils.substringBefore(rawOriginalMethodName, ".");
|
||||
String originalName = StringUtils.substringAfter(rawOriginalMethodName, ".");
|
||||
// Separate checks for cases when factory implements interface and not.
|
||||
boolean factoryImplementsInterface = Elements.implementsType(defaultClass, originalClass);
|
||||
if (factoryImplementsInterface) {
|
||||
for (ConstructorElement defaultConstructor : defaultClass.getConstructors()) {
|
||||
String rawDefaultMethodName = Elements.getRawMethodName(defaultConstructor);
|
||||
// kI == nI and kF == nF
|
||||
if (rawOriginalMethodName.equals(originalClassName)
|
||||
&& rawDefaultMethodName.equals(defaultClassName)) {
|
||||
return defaultConstructor;
|
||||
}
|
||||
// kI == nI.name and kF == nF.name
|
||||
if (originalDotIndex != -1) {
|
||||
int defaultDotIndex = rawDefaultMethodName.indexOf('.');
|
||||
if (defaultDotIndex != -1) {
|
||||
String defaultQualifier = StringUtils.substringBefore(rawDefaultMethodName, ".");
|
||||
String defaultName = StringUtils.substringAfter(rawDefaultMethodName, ".");
|
||||
if (defaultQualifier.equals(defaultClassName)
|
||||
&& originalQualifier.equals(originalClassName)
|
||||
&& defaultName.equals(originalName)) {
|
||||
return defaultConstructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (ConstructorElement defaultConstructor : defaultClass.getConstructors()) {
|
||||
String rawDefaultMethodName = Elements.getRawMethodName(defaultConstructor);
|
||||
if (rawDefaultMethodName.equals(rawOriginalMethodName)) {
|
||||
return defaultConstructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If constructor not found, try implicit default constructor of the default class.
|
||||
if (Elements.isDefaultConstructor(constructor)
|
||||
&& (Elements.isSyntheticConstructor(constructor) || factoryImplementsInterface)
|
||||
&& Elements.needsImplicitDefaultConstructor(defaultClass)) {
|
||||
return new SyntheticDefaultConstructorElement(null, defaultClass, typeProvider);
|
||||
}
|
||||
// Factory constructor not resolved, report error with specific message for each case.
|
||||
{
|
||||
String expectedFactoryConstructorName;
|
||||
if (factoryImplementsInterface) {
|
||||
if (originalDotIndex == -1) {
|
||||
expectedFactoryConstructorName = defaultClassName;
|
||||
} else {
|
||||
expectedFactoryConstructorName = defaultClassName + "." + originalName;
|
||||
}
|
||||
} else {
|
||||
expectedFactoryConstructorName = rawOriginalMethodName;
|
||||
}
|
||||
onError(
|
||||
errorTarget,
|
||||
ResolverErrorCode.DEFAULT_CONSTRUCTOR_UNRESOLVED,
|
||||
expectedFactoryConstructorName,
|
||||
defaultClassName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element visitGotoStatement(DartGotoStatement x) {
|
||||
// Don't bother unless there's a target.
|
||||
|
||||
@@ -125,8 +125,6 @@ public enum ResolverErrorCode implements ErrorCode {
|
||||
ILLEGAL_ACCESS_TO_PRIVATE("'%s' is private and not defined in this library"),
|
||||
// TODO(zundel): error message needs JUnit test - how to test #imports in junit?
|
||||
ILLEGAL_ACCESS_TO_PRIVATE_MEMBER("\"%s\" refers to \"%s\" which is in a different library"),
|
||||
ILLEGAL_CONSTRUCTOR_NO_DEFAULT_IN_INTERFACE(
|
||||
"Illegal constructor declaration. No default clause in interface"),
|
||||
ILLEGAL_FIELD_ACCESS_FROM_STATIC("Illegal access of instance field %s from static scope"),
|
||||
ILLEGAL_METHOD_ACCESS_FROM_STATIC("Illegal access of instance method %s from static scope"),
|
||||
INIT_FIELD_ONLY_IMMEDIATELY_SURROUNDING_CLASS(
|
||||
|
||||
Reference in New Issue
Block a user