Fix analyzer-CFE integration of illegal references to instance members from static contexts.

In particular, we want to make sure the element is resolved, in case
the user wants to navigate to it to make it static.

Change-Id: I0707145281858fbf084c6b2af32bb48bfed457f9
Reviewed-on: https://dart-review.googlesource.com/66820
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Paul Berry
2018-07-26 22:59:56 +00:00
committed by commit-bot@chromium.org
parent d5b5736a47
commit 1a5f94a0a4
9 changed files with 265 additions and 14 deletions
@@ -30,6 +30,12 @@ class AnalysisDriverResolutionTest_Kernel extends AnalysisDriverResolutionTest {
return super.test_closure_generic();
}
@override
@failingTest
test_illegal_call_to_static_member() {
return super.test_illegal_call_to_static_member();
}
@override
@failingTest
test_invalid_annotation_on_variable_declaration_for() async {
@@ -964,6 +964,23 @@ main() {
expect(xReference.staticType.toString(), useCFE ? 'dynamic' : 'int');
}
test_assignment_to_illegal_static_access() async {
addTestFile('''
class C {
int x;
static f(int y) {
x = y;
}
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.field('x');
assertElement(findNode.simple('x ='), xElement.setter);
var yElement = findElement.parameter('y');
assertElement(findNode.simple('y;'), yElement);
}
test_assignment_to_non_generator() async {
addTestFile('''
f() {}
@@ -2081,6 +2098,23 @@ var v = (() => 42)();
expect(closureElement.enclosingElement, same(variableInitializer));
}
test_compound_assignment_to_illegal_static_access() async {
addTestFile('''
class C {
int x;
static f(int y) {
x += y;
}
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.field('x');
assertElement(findNode.simple('x +='), xElement.setter);
var yElement = findElement.parameter('y');
assertElement(findNode.simple('y;'), yElement);
}
test_compound_assignment_to_postfix_increment() async {
addTestFile('''
f(int x, int y) {
@@ -2860,6 +2894,23 @@ main() {
assertElement(tRef, functionType.typeFormals[0]);
}
test_illegal_call_to_static_member() async {
addTestFile('''
class C {
f() {}
static g() {
f();
}
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var fElement = findElement.method('f');
var fReference = findNode.simple('f();');
assertElement(fReference, fElement);
}
test_indexExpression() async {
String content = r'''
main() {
@@ -6519,6 +6570,23 @@ void f<T, U>(T a, U b) {}
}
}
test_null_aware_assignment_to_illegal_static_access() async {
addTestFile('''
class C {
int x;
static f(int y) {
x ??= y;
}
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.field('x');
assertElement(findNode.simple('x ??='), xElement.setter);
var yElement = findElement.parameter('y');
assertElement(findNode.simple('y;'), yElement);
}
test_null_aware_assignment_to_postfix_increment() async {
addTestFile('''
f(int x, int y) {
@@ -6546,6 +6614,21 @@ f(int y) {
assertElement(findNode.simple('y;'), yElement);
}
test_postfix_increment_of_illegal_static_access() async {
addTestFile('''
class C {
int x;
static f() {
x++;
}
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.field('x');
assertElement(findNode.simple('x++'), xElement.setter);
}
test_postfix_increment_of_non_generator() async {
addTestFile('''
f() {}
@@ -6643,6 +6726,21 @@ class C {
}
}
test_prefix_increment_of_illegal_static_access() async {
addTestFile('''
class C {
int x;
static f() {
++x; // usage
}
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
var xElement = findElement.field('x');
assertElement(findNode.simple('x; // usage'), xElement.setter);
}
test_prefix_increment_of_non_generator() async {
addTestFile('''
f() {}
@@ -9755,13 +9853,24 @@ class FindElement {
ParameterElement parameter(String name) {
ParameterElement parameterElement;
void considerParameter(ParameterElement parameter) {
if (parameter.name == name) {
if (parameterElement != null) {
throw new StateError('Parameter name $name is not unique.');
}
parameterElement = parameter;
}
}
for (var function in unitElement.functions) {
for (var parameter in function.parameters) {
if (parameter.name == name) {
if (parameterElement != null) {
throw new StateError('Parameter name $name is not unique.');
}
parameterElement = parameter;
considerParameter(parameter);
}
}
for (var class_ in unitElement.types) {
for (var method in class_.methods) {
for (var parameter in method.parameters) {
considerParameter(parameter);
}
}
}
@@ -77,6 +77,7 @@ import 'expression_generator.dart'
DelayedAssignment,
DelayedPostfixIncrement,
Generator,
IllegalThisPropertyAccessGenerator,
IncompleteErrorGenerator,
IncompletePropertyAccessGenerator,
IncompleteSendGenerator,
@@ -1518,11 +1519,9 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
return new IncompleteErrorGenerator(this, token, declaration.target,
fasta.templateThisAccessInFieldInitializer.withArguments(name));
}
if (declaration == null ||
(!isInstanceContext && declaration.isInstanceMember)) {
if (declaration == null) {
Name n = new Name(name, library.library);
if (!isQualified && isInstanceContext) {
assert(declaration == null);
if (constantContext != ConstantContext.none || member.isField) {
return new UnresolvedNameGenerator(this, token, n);
}
@@ -1588,7 +1587,12 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
getter = declaration.target;
setter = lookupInstanceMember(n, isSetter: true);
}
return new ThisPropertyAccessGenerator(this, token, n, getter, setter);
if (isInstanceContext) {
return new ThisPropertyAccessGenerator(this, token, n, getter, setter);
} else {
return new IllegalThisPropertyAccessGenerator(
this, token, n, getter, setter);
}
} else if (declaration.isRegularMethod) {
assert(declaration.isStatic || declaration.isTopLevel);
return new StaticAccessGenerator(this, token, declaration.target, null);
@@ -908,6 +908,56 @@ abstract class ErroneousExpressionGenerator implements Generator {
}
}
abstract class IllegalThisPropertyAccessGenerator
implements ErroneousExpressionGenerator {
factory IllegalThisPropertyAccessGenerator(ExpressionGeneratorHelper helper,
Token token, Name name, Member getter, Member setter) {
return helper.forest.illegalThisPropertyAccessGenerator(
helper, token, name, getter, setter);
}
@override
Generator asLvalue() {
return new NonLvalueGenerator(
helper,
token,
buildError(new Arguments([]),
isSetter: true, offset: offsetForToken(token)),
buildSimpleWrite());
}
/// Builds an [Expression] representing a write to the generator.
Expression buildSimpleWrite();
@override
String get debugName => "IllegalThisPropertyAccessGenerator";
@override
Expression doInvocation(int charOffset, Arguments arguments) {
return new UnresolvedTargetInvocationJudgment(
buildError(arguments, offset: charOffset), arguments)
..fileOffset = arguments.fileOffset;
}
@override
Expression buildError(Arguments arguments,
{bool isGetter: false, bool isSetter: false, int offset}) {
offset ??= offsetForToken(this.token);
return helper.throwNoSuchMethodError(
forest.literalNull(null)..fileOffset = offset,
plainNameForRead ?? '',
arguments,
offset,
isGetter: isGetter,
isSetter: isSetter);
}
@override
/* Expression | Generator */ Object prefixedLookup(Token name) {
throw new UnimplementedError('TODO(paulberry)');
}
}
abstract class UnresolvedNameGenerator implements ErroneousExpressionGenerator {
factory UnresolvedNameGenerator(
ExpressionGeneratorHelper helper, Token token, Name name) {
@@ -48,6 +48,7 @@ import 'kernel_expression_generator.dart'
KernelDeferredAccessGenerator,
KernelDelayedAssignment,
KernelDelayedPostfixIncrement,
KernelIllegalThisPropertyAccessGenerator,
KernelIndexedAccessGenerator,
KernelLargeIntAccessGenerator,
KernelLoadLibraryGenerator,
@@ -683,6 +684,16 @@ class Fangorn extends Forest {
helper, token, name, getter, setter);
}
KernelIllegalThisPropertyAccessGenerator illegalThisPropertyAccessGenerator(
ExpressionGeneratorHelper helper,
Token token,
Name name,
Member getter,
Member setter) {
return new KernelIllegalThisPropertyAccessGenerator(
helper, token, name, getter, setter);
}
@override
KernelNullAwarePropertyAccessGenerator nullAwarePropertyAccessGenerator(
ExpressionGeneratorHelper helper,
@@ -376,6 +376,9 @@ abstract class Forest {
Generator thisPropertyAccessGenerator(ExpressionGeneratorHelper helper,
Token location, Name name, Member getter, Member setter);
Generator illegalThisPropertyAccessGenerator(ExpressionGeneratorHelper helper,
Token location, Name name, Member getter, Member setter);
Generator nullAwarePropertyAccessGenerator(
ExpressionGeneratorHelper helper,
Token location,
@@ -90,6 +90,7 @@ export 'kernel_shadow_ast.dart'
IfNullJudgment,
IfJudgment,
IllegalAssignmentJudgment,
IllegalPropertySetJudgment,
IndexAssignmentJudgment,
InvalidConstructorInvocationJudgment,
InvalidPropertyGetJudgment,
@@ -11,15 +11,15 @@ import '../constant_context.dart' show ConstantContext;
import '../fasta_codes.dart'
show
Message,
LocatedMessage,
Message,
messageCannotAssignToParenthesizedExpression,
messageInvalidUseOfNullAwareAccess,
messageLoadLibraryTakesNoArguments,
messageNotAConstantExpression,
messageCannotAssignToParenthesizedExpression,
templateNotConstantExpression,
messageSuperAsExpression,
templateThisOrSuperAccessInFieldInitializer,
messageInvalidUseOfNullAwareAccess;
templateNotConstantExpression,
templateThisOrSuperAccessInFieldInitializer;
import '../messages.dart' show Message, noLength;
@@ -44,6 +44,7 @@ import 'expression_generator.dart'
ErroneousExpressionGenerator,
ExpressionGenerator,
Generator,
IllegalThisPropertyAccessGenerator,
IndexedAccessGenerator,
LargeIntAccessGenerator,
LoadLibraryGenerator,
@@ -78,6 +79,7 @@ import 'kernel_ast_api.dart'
Constructor,
DartType,
Field,
IllegalPropertySetJudgment,
IndexAssignmentJudgment,
Initializer,
InvalidPropertyGetJudgment,
@@ -1441,6 +1443,49 @@ class KernelLargeIntAccessGenerator extends KernelGenerator
}
}
class KernelIllegalThisPropertyAccessGenerator extends KernelGenerator
with ErroneousExpressionGenerator, IllegalThisPropertyAccessGenerator {
@override
final Name name;
final Member getter;
final Member setter;
KernelIllegalThisPropertyAccessGenerator(ExpressionGeneratorHelper helper,
Token token, this.name, this.getter, this.setter)
: super(helper, token);
@override
Expression buildSimpleRead() {
Expression error = buildError(forest.argumentsEmpty(token), isGetter: true);
return new InvalidPropertyGetJudgment(error, getter)
..fileOffset = token.charOffset;
}
Expression buildSimpleWrite() {
Expression error = buildError(forest.argumentsEmpty(token), isSetter: true);
return new IllegalPropertySetJudgment(error, token.isSynthetic, setter)
..fileOffset = token.charOffset;
}
DartType buildTypeWithBuiltArguments(List<DartType> arguments,
{bool nonInstanceAccessIsError: false, TypeInferrer typeInferrer}) {
var type = super.buildTypeWithBuiltArguments(arguments,
nonInstanceAccessIsError: nonInstanceAccessIsError,
typeInferrer: typeInferrer);
typeInferrer.storeTypeReference(
token.offset, token.isSynthetic, null, null, type);
return type;
}
@override
void printOn(StringSink sink) {
sink.write(", name: ");
sink.write(name.name);
}
}
class KernelUnresolvedNameGenerator extends KernelGenerator
with ErroneousExpressionGenerator, UnresolvedNameGenerator {
@override
@@ -1716,6 +1716,28 @@ class IndexAssignmentJudgment extends ComplexAssignmentJudgmentWithReceiver {
}
}
class IllegalPropertySetJudgment extends SyntheticExpressionJudgment {
final bool forSyntheticToken;
final Member setter;
IllegalPropertySetJudgment(
Expression desugared, this.forSyntheticToken, this.setter)
: super(desugared);
@override
Expression infer<Expression, Statement, Initializer, Type>(
ShadowTypeInferrer inferrer,
Factory<Expression, Statement, Initializer, Type> factory,
DartType typeContext) {
_replaceWithDesugared();
inferredType = const DynamicType();
inferrer.listener.propertyAssign(
this, fileOffset, setter, setter.setterType, null, inferredType);
return null;
}
}
/// Common base class for shadow objects representing initializers in kernel
/// form.
abstract class InitializerJudgment implements Initializer {