Chromium Code Reviews| Index: pkg/analysis_services/lib/src/correction/fix.dart |
| diff --git a/pkg/analysis_services/lib/src/correction/fix.dart b/pkg/analysis_services/lib/src/correction/fix.dart |
| index fe24a149c11e9aefea5e54efb1de33a92b2bc858..0c2fa0a091ef7dc81b77bd49848e170695e39b13 100644 |
| --- a/pkg/analysis_services/lib/src/correction/fix.dart |
| +++ b/pkg/analysis_services/lib/src/correction/fix.dart |
| @@ -13,12 +13,14 @@ import 'package:analysis_services/search/search_engine.dart'; |
| import 'package:analysis_services/src/correction/name_suggestion.dart'; |
| import 'package:analysis_services/src/correction/source_buffer.dart'; |
| import 'package:analysis_services/src/correction/source_range.dart' as rf; |
| +import 'package:analysis_services/src/correction/strings.dart'; |
| import 'package:analysis_services/src/correction/util.dart'; |
| import 'package:analyzer/src/generated/ast.dart'; |
| import 'package:analyzer/src/generated/element.dart'; |
| import 'package:analyzer/src/generated/error.dart'; |
| import 'package:analyzer/src/generated/java_core.dart'; |
| import 'package:analyzer/src/generated/parser.dart'; |
| +import 'package:analyzer/src/generated/scanner.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| @@ -28,13 +30,17 @@ import 'package:analyzer/src/generated/utilities_dart.dart'; |
| */ |
| class FixProcessor { |
| final SearchEngine searchEngine; |
| + final Source source; |
| final String file; |
| final CompilationUnit unit; |
| final AnalysisError error; |
| + CompilationUnitElement unitElement; |
| + LibraryElement unitLibraryElement; |
| final List<Edit> edits = <Edit>[]; |
| final Map<String, LinkedPositionGroup> linkedPositionGroups = <String, |
| LinkedPositionGroup>{}; |
| + Position endPosition = null; |
| final List<Fix> fixes = <Fix>[]; |
| CorrectionUtils utils; |
| @@ -45,7 +51,13 @@ class FixProcessor { |
| AstNode coveredNode; |
| - FixProcessor(this.searchEngine, this.file, this.unit, this.error); |
| + FixProcessor(this.searchEngine, this.source, this.file, this.unit, this.error) |
| + { |
| + unitElement = unit.element; |
| + unitLibraryElement = unitElement.library; |
| + } |
| + |
| + DartType get coreTypeBool => _getCoreType("bool"); |
| List<Fix> compute() { |
| utils = new CorrectionUtils(unit); |
| @@ -69,11 +81,10 @@ class FixProcessor { |
| CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT) { |
| _addFix_createConstructorSuperExplicit(); |
| } |
| -// if (identical( |
| -// errorCode, |
| -// CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT)) { |
| -// _addFix_createConstructorSuperImplicit(); |
| -// } |
| + if (errorCode == |
| + CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT) { |
| + _addFix_createConstructorSuperImplicit(); |
| + } |
| if (errorCode == |
| CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT) { |
| _addFix_createConstructorSuperExplicit(); |
| @@ -139,11 +150,11 @@ class FixProcessor { |
| _addFix_createClass(); |
| _addFix_undefinedClass_useSimilar(); |
| } |
| -// if (identical(errorCode, StaticWarningCode.UNDEFINED_IDENTIFIER)) { |
| -// _addFix_createFunction_forFunctionType(); |
| -// _addFix_importLibrary_withType(); |
| -// _addFix_importLibrary_withTopLevelVariable(); |
| -// } |
| + if (errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER) { |
| + _addFix_createFunction_forFunctionType(); |
| + _addFix_importLibrary_withType(); |
| + _addFix_importLibrary_withTopLevelVariable(); |
| + } |
| if (errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER) { |
| _addFix_useStaticAccess_method(); |
| _addFix_useStaticAccess_property(); |
| @@ -156,15 +167,15 @@ class FixProcessor { |
| // _addFix_undefinedFunction_useSimilar(); |
| // _addFix_undefinedFunction_create(); |
| // } |
| -// if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_GETTER)) { |
| -// _addFix_createFunction_forFunctionType(); |
| -// } |
| -// if (identical(errorCode, HintCode.UNDEFINED_METHOD) || |
| -// identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) { |
| -// _addFix_undefinedMethod_useSimilar(); |
| -// _addFix_undefinedMethod_create(); |
| -// _addFix_undefinedFunction_create(); |
| -// } |
| + if (errorCode == StaticTypeWarningCode.UNDEFINED_GETTER) { |
| + _addFix_createFunction_forFunctionType(); |
| + } |
| + if (errorCode == HintCode.UNDEFINED_METHOD || |
| + errorCode == StaticTypeWarningCode.UNDEFINED_METHOD) { |
| + _addFix_undefinedMethod_useSimilar(); |
| + _addFix_undefinedMethod_create(); |
| + _addFix_undefinedFunction_create(); |
| + } |
| // done |
| return fixes; |
| } |
| @@ -181,9 +192,14 @@ class FixProcessor { |
| change.add(fileEdit); |
| linkedPositionGroups.values.forEach( |
| (group) => change.addLinkedPositionGroup(group)); |
| + change.endPosition = endPosition; |
| // add Fix |
| Fix fix = new Fix(kind, change); |
| fixes.add(fix); |
| + // clear |
| + edits.clear(); |
| + linkedPositionGroups.clear(); |
| + endPosition = null; |
| } |
| void _addFix_addPackageDependency() { |
| @@ -208,6 +224,7 @@ class FixProcessor { |
| // } |
| } |
| + |
| void _addFix_boolInsteadOfBoolean() { |
| SourceRange range = rf.rangeError(error); |
| _addReplaceEdit(range, "bool"); |
| @@ -250,7 +267,6 @@ class FixProcessor { |
| } |
| } |
| - |
| void _addFix_createConstructorSuperExplicit() { |
| ConstructorDeclaration targetConstructor = |
| node.parent as ConstructorDeclaration; |
| @@ -319,79 +335,76 @@ class FixProcessor { |
| } |
| void _addFix_createConstructorSuperImplicit() { |
| - // TODO(scheglov) implement |
| -// ClassDeclaration targetClassNode = node.parent as ClassDeclaration; |
| -// ClassElement targetClassElement = targetClassNode.element; |
| -// ClassElement superClassElement = targetClassElement.supertype.element; |
| -// String targetClassName = targetClassElement.name; |
| -// // add proposals for all super constructors |
| -// List<ConstructorElement> superConstructors = superClassElement.constructors; |
| -// for (ConstructorElement superConstructor in superConstructors) { |
| -// String constructorName = superConstructor.name; |
| -// // skip private |
| -// if (Identifier.isPrivateName(constructorName)) { |
| -// continue; |
| -// } |
| -// // prepare parameters and arguments |
| -// JavaStringBuilder parametersBuffer = new JavaStringBuilder(); |
| -// JavaStringBuilder argumentsBuffer = new JavaStringBuilder(); |
| -// bool firstParameter = true; |
| -// for (ParameterElement parameter in superConstructor.parameters) { |
| -// // skip non-required parameters |
| -// if (parameter.parameterKind != ParameterKind.REQUIRED) { |
| -// break; |
| -// } |
| -// // comma |
| -// if (firstParameter) { |
| -// firstParameter = false; |
| -// } else { |
| -// parametersBuffer.append(", "); |
| -// argumentsBuffer.append(", "); |
| -// } |
| -// // name |
| -// String parameterName = parameter.displayName; |
| -// if (parameterName.length > 1 && parameterName.startsWith("_")) { |
| -// parameterName = parameterName.substring(1); |
| -// } |
| -// // parameter & argument |
| -// _appendParameterSource(parametersBuffer, parameter.type, parameterName); |
| -// argumentsBuffer.append(parameterName); |
| -// } |
| -// // add proposal |
| -// String eol = utils.endOfLine; |
| -// QuickFixProcessorImpl_NewConstructorLocation targetLocation = |
| -// _prepareNewConstructorLocation(targetClassNode, eol); |
| -// SourceBuilder sb = new SourceBuilder.con1(targetLocation._offset); |
| -// { |
| -// String indent = utils.getIndent(1); |
| -// sb.append(targetLocation._prefix); |
| -// sb.append(indent); |
| -// sb.append(targetClassName); |
| -// if (!constructorName.isEmpty) { |
| -// sb.startPosition("NAME"); |
| -// sb.append("."); |
| -// sb.append(constructorName); |
| -// sb.endPosition(); |
| -// } |
| -// sb.append("("); |
| -// sb.append(parametersBuffer.toString()); |
| -// sb.append(") : super"); |
| -// if (!constructorName.isEmpty) { |
| -// sb.append("."); |
| -// sb.append(constructorName); |
| -// } |
| -// sb.append("("); |
| -// sb.append(argumentsBuffer.toString()); |
| -// sb.append(");"); |
| -// sb.append(targetLocation._suffix); |
| -// } |
| -// _addInsertEdit3(sb); |
| -// // add proposal |
| -// String proposalName = _getConstructorProposalName(superConstructor); |
| -// _addFix( |
| -// FixKind.CREATE_CONSTRUCTOR_SUPER, |
| -// [proposalName]); |
| -// } |
| + ClassDeclaration targetClassNode = node.parent as ClassDeclaration; |
| + ClassElement targetClassElement = targetClassNode.element; |
| + ClassElement superClassElement = targetClassElement.supertype.element; |
| + String targetClassName = targetClassElement.name; |
| + // add proposals for all super constructors |
| + List<ConstructorElement> superConstructors = superClassElement.constructors; |
| + for (ConstructorElement superConstructor in superConstructors) { |
| + String constructorName = superConstructor.name; |
| + // skip private |
| + if (Identifier.isPrivateName(constructorName)) { |
| + continue; |
| + } |
| + // prepare parameters and arguments |
| + StringBuffer parametersBuffer = new StringBuffer(); |
| + StringBuffer argumentsBuffer = new StringBuffer(); |
| + bool firstParameter = true; |
| + for (ParameterElement parameter in superConstructor.parameters) { |
| + // skip non-required parameters |
| + if (parameter.parameterKind != ParameterKind.REQUIRED) { |
| + break; |
| + } |
| + // comma |
| + if (firstParameter) { |
| + firstParameter = false; |
| + } else { |
| + parametersBuffer.write(', '); |
| + argumentsBuffer.write(', '); |
| + } |
| + // name |
| + String parameterName = parameter.displayName; |
| + if (parameterName.length > 1 && parameterName.startsWith('_')) { |
| + parameterName = parameterName.substring(1); |
| + } |
| + // parameter & argument |
| + _appendParameterSource(parametersBuffer, parameter.type, parameterName); |
| + argumentsBuffer.write(parameterName); |
| + } |
| + // add proposal |
| + String eol = utils.endOfLine; |
|
Paul Berry
2014/07/25 00:28:46
With my suggestion about eol below, this line coul
scheglov
2014/07/25 03:20:50
Done.
|
| + QuickFixProcessorImpl_NewConstructorLocation targetLocation = |
| + _prepareNewConstructorLocation(targetClassNode, eol); |
| + SourceBuilder sb = new SourceBuilder(file, targetLocation._offset); |
| + { |
| + String indent = utils.getIndent(1); |
| + sb.append(targetLocation._prefix); |
| + sb.append(indent); |
| + sb.append(targetClassName); |
| + if (!constructorName.isEmpty) { |
| + sb.startPosition('NAME'); |
|
Paul Berry
2014/07/25 00:28:45
Are the strings passed to startPosition things tha
scheglov
2014/07/25 03:20:51
These strings are IDs of linked position groups.
T
|
| + sb.append('.'); |
| + sb.append(constructorName); |
| + sb.endPosition(); |
| + } |
| + sb.append("("); |
| + sb.append(parametersBuffer.toString()); |
| + sb.append(') : super'); |
| + if (!constructorName.isEmpty) { |
| + sb.append('.'); |
| + sb.append(constructorName); |
| + } |
| + sb.append('('); |
| + sb.append(argumentsBuffer.toString()); |
| + sb.append(');'); |
| + sb.append(targetLocation._suffix); |
| + } |
| + _insertBuilder(sb); |
| + // add proposal |
| + String proposalName = _getConstructorProposalName(superConstructor); |
| + _addFix(FixKind.CREATE_CONSTRUCTOR_SUPER, [proposalName]); |
| + } |
| } |
| void _addFix_createConstructor_insteadOfSyntheticDefault() { |
| @@ -527,171 +540,167 @@ class FixProcessor { |
| } |
| void _addFix_createFunction_forFunctionType() { |
| - // TODO(scheglov) implement |
| -// if (node is SimpleIdentifier) { |
| -// SimpleIdentifier nameNode = node as SimpleIdentifier; |
| -// // prepare argument expression (to get parameter) |
| -// ClassElement targetElement; |
| -// Expression argument; |
| -// { |
| -// Expression target = CorrectionUtils.getQualifiedPropertyTarget(node); |
| -// if (target != null) { |
| -// DartType targetType = target.bestType; |
| -// if (targetType != null && targetType.element is ClassElement) { |
| -// targetElement = targetType.element as ClassElement; |
| -// argument = target.parent as Expression; |
| -// } else { |
| -// return; |
| -// } |
| -// } else { |
| -// ClassDeclaration enclosingClass = |
| -// node.getAncestor((node) => node is ClassDeclaration); |
| -// targetElement = enclosingClass != null ? |
| -// enclosingClass.element : |
| -// null; |
| -// argument = nameNode; |
| -// } |
| -// } |
| -// // should be argument of some invocation |
| -// ParameterElement parameterElement = argument.bestParameterElement; |
| -// if (parameterElement == null) { |
| -// return; |
| -// } |
| -// // should be parameter of function type |
| -// DartType parameterType = parameterElement.type; |
| -// if (parameterType is! FunctionType) { |
| -// return; |
| -// } |
| -// FunctionType functionType = parameterType as FunctionType; |
| -// // add proposal |
| -// if (targetElement != null) { |
| -// _addProposal_createFunction_method(targetElement, functionType); |
| -// } else { |
| -// _addProposal_createFunction_function(functionType); |
| -// } |
| -// } |
| + if (node is SimpleIdentifier) { |
| + SimpleIdentifier nameNode = node as SimpleIdentifier; |
| + // prepare argument expression (to get parameter) |
| + ClassElement targetElement; |
| + Expression argument; |
| + { |
| + Expression target = getQualifiedPropertyTarget(node); |
| + if (target != null) { |
| + DartType targetType = target.bestType; |
| + if (targetType != null && targetType.element is ClassElement) { |
| + targetElement = targetType.element as ClassElement; |
| + argument = target.parent as Expression; |
| + } else { |
| + return; |
| + } |
| + } else { |
| + ClassDeclaration enclosingClass = |
| + node.getAncestor((node) => node is ClassDeclaration); |
| + targetElement = enclosingClass != null ? |
| + enclosingClass.element : |
| + null; |
| + argument = nameNode; |
| + } |
| + } |
| + // should be argument of some invocation |
| + ParameterElement parameterElement = argument.bestParameterElement; |
| + if (parameterElement == null) { |
| + return; |
| + } |
| + // should be parameter of function type |
| + DartType parameterType = parameterElement.type; |
| + if (parameterType is! FunctionType) { |
| + return; |
| + } |
| + FunctionType functionType = parameterType as FunctionType; |
| + // add proposal |
| + if (targetElement != null) { |
| + _addProposal_createFunction_method(targetElement, functionType); |
| + } else { |
| + _addProposal_createFunction_function(functionType); |
| + } |
| + } |
| } |
| void |
| _addFix_createMissingOverrides(List<ExecutableElement> missingOverrides) { |
| - // TODO(scheglov) implement |
| -// // sort by name |
| -// missingOverrides.sort( |
| -// (Element firstElement, Element secondElement) => |
| -// ObjectUtils.compare(firstElement.displayName, secondElement.displayName)); |
| -// // add elements |
| -// ClassDeclaration targetClass = node.parent as ClassDeclaration; |
| -// bool isFirst = true; |
| -// for (ExecutableElement missingOverride in missingOverrides) { |
| -// _addFix_createMissingOverrides_single( |
| -// targetClass, |
| -// missingOverride, |
| -// isFirst); |
| -// isFirst = false; |
| -// } |
| -// // add proposal |
| -// _addFix( |
| -// FixKind.CREATE_MISSING_OVERRIDES, |
| -// [missingOverrides.length]); |
| + // sort by name |
| + missingOverrides.sort((Element firstElement, Element secondElement) { |
| + return compareStrings( |
| + firstElement.displayName, |
| + secondElement.displayName); |
| + }); |
| + // add elements |
| + ClassDeclaration targetClass = node.parent as ClassDeclaration; |
| + bool isFirst = true; |
| + for (ExecutableElement missingOverride in missingOverrides) { |
| + _addFix_createMissingOverrides_single( |
| + targetClass, |
| + missingOverride, |
| + isFirst); |
| + isFirst = false; |
| + } |
| + // add proposal |
| + _addFix(FixKind.CREATE_MISSING_OVERRIDES, [missingOverrides.length]); |
| } |
| void _addFix_createMissingOverrides_single(ClassDeclaration targetClass, |
| ExecutableElement missingOverride, bool isFirst) { |
| - // TODO(scheglov) implement |
| -// // prepare environment |
| -// String eol = utils.endOfLine; |
| -// String prefix = utils.getIndent(1); |
| -// String prefix2 = utils.getIndent(2); |
| -// int insertOffset = targetClass.end - 1; |
| -// // prepare source |
| -// JavaStringBuilder sb = new JavaStringBuilder(); |
| -// // may be empty line |
| -// if (!isFirst || !targetClass.members.isEmpty) { |
| -// sb.append(eol); |
| -// } |
| -// // may be property |
| -// ElementKind elementKind = missingOverride.kind; |
| -// bool isGetter = elementKind == ElementKind.GETTER; |
| -// bool isSetter = elementKind == ElementKind.SETTER; |
| -// bool isMethod = elementKind == ElementKind.METHOD; |
| -// bool isOperator = isMethod && (missingOverride as MethodElement).isOperator; |
| -// sb.append(prefix); |
| -// if (isGetter) { |
| -// sb.append("// TODO: implement ${missingOverride.displayName}"); |
| -// sb.append(eol); |
| -// sb.append(prefix); |
| -// } |
| -// // @override |
| -// { |
| -// sb.append("@override"); |
| -// sb.append(eol); |
| -// sb.append(prefix); |
| -// } |
| -// // return type |
| -// _appendType(sb, missingOverride.type.returnType); |
| -// if (isGetter) { |
| -// sb.append("get "); |
| -// } else if (isSetter) { |
| -// sb.append("set "); |
| -// } else if (isOperator) { |
| -// sb.append("operator "); |
| -// } |
| -// // name |
| -// sb.append(missingOverride.displayName); |
| -// // parameters + body |
| -// if (isGetter) { |
| -// sb.append(" => null;"); |
| -// } else if (isMethod || isSetter) { |
| -// List<ParameterElement> parameters = missingOverride.parameters; |
| -// _appendParameters(sb, parameters); |
| -// sb.append(" {"); |
| -// // TO-DO |
| -// sb.append(eol); |
| -// sb.append(prefix2); |
| -// if (isMethod) { |
| -// sb.append("// TODO: implement ${missingOverride.displayName}"); |
| -// } else { |
| -// sb.append("// TODO: implement ${missingOverride.displayName}"); |
| -// } |
| -// sb.append(eol); |
| -// // close method |
| -// sb.append(prefix); |
| -// sb.append("}"); |
| -// } |
| -// sb.append(eol); |
| -// // done |
| -// _addInsertEdit(insertOffset, sb.toString()); |
| -// // maybe set end range |
| -// if (_endRange == null) { |
| -// _endRange = SourceRangeFactory.rangeStartLength(insertOffset, 0); |
| -// } |
| + // prepare environment |
| + String eol = utils.endOfLine; |
| + String prefix = utils.getIndent(1); |
| + String prefix2 = utils.getIndent(2); |
| + int insertOffset = targetClass.end - 1; |
| + // prepare source |
| + StringBuffer sb = new StringBuffer(); |
| + // may be empty line |
| + if (!isFirst || !targetClass.members.isEmpty) { |
| + sb.write(eol); |
| + } |
| + // may be property |
| + ElementKind elementKind = missingOverride.kind; |
| + bool isGetter = elementKind == ElementKind.GETTER; |
| + bool isSetter = elementKind == ElementKind.SETTER; |
| + bool isMethod = elementKind == ElementKind.METHOD; |
| + bool isOperator = isMethod && (missingOverride as MethodElement).isOperator; |
| + sb.write(prefix); |
| + if (isGetter) { |
| + sb.write('// TODO: implement ${missingOverride.displayName}'); |
| + sb.write(eol); |
| + sb.write(prefix); |
| + } |
| + // @override |
| + { |
| + sb.write('@override'); |
| + sb.write(eol); |
| + sb.write(prefix); |
| + } |
| + // return type |
| + _appendType(sb, missingOverride.type.returnType); |
| + if (isGetter) { |
| + sb.write('get '); |
| + } else if (isSetter) { |
| + sb.write('set '); |
| + } else if (isOperator) { |
| + sb.write('operator '); |
| + } |
| + // name |
| + sb.write(missingOverride.displayName); |
| + // parameters + body |
| + if (isGetter) { |
| + sb.write(' => null;'); |
| + } else if (isMethod || isSetter) { |
|
Paul Berry
2014/07/25 00:28:45
Any reason this couldn't just be "} else {"?
scheglov
2014/07/25 03:20:51
Done.
|
| + List<ParameterElement> parameters = missingOverride.parameters; |
| + _appendParameters(sb, parameters, _getDefaultValueMap(parameters)); |
| + sb.write(' {'); |
| + // TO-DO |
| + sb.write(eol); |
| + sb.write(prefix2); |
| + if (isMethod) { |
|
Paul Berry
2014/07/25 00:28:45
This if test is unnecessary, since we do the same
scheglov
2014/07/25 03:20:51
Done.
|
| + sb.write('// TODO: implement ${missingOverride.displayName}'); |
| + } else { |
| + sb.write('// TODO: implement ${missingOverride.displayName}'); |
| + } |
| + sb.write(eol); |
| + // close method |
| + sb.write(prefix); |
| + sb.write('}'); |
| + } |
| + sb.write(eol); |
| + // done |
| + _addInsertEdit(insertOffset, sb.toString()); |
| + // maybe set end range |
| + if (endPosition == null) { |
| + endPosition = new Position(file, insertOffset, 0); |
| + } |
| } |
| void _addFix_createNoSuchMethod() { |
| - // TODO(scheglov) implement |
| -// ClassDeclaration targetClass = node.parent as ClassDeclaration; |
| -// // prepare environment |
| -// String eol = utils.endOfLine; |
| -// String prefix = utils.getIndent(1); |
| -// int insertOffset = targetClass.end - 1; |
| -// // prepare source |
| -// SourceBuilder sb = new SourceBuilder.con1(insertOffset); |
| -// { |
| -// // insert empty line before existing member |
| -// if (!targetClass.members.isEmpty) { |
| -// sb.append(eol); |
| -// } |
| -// // append method |
| -// sb.append(prefix); |
| -// sb.append( |
| -// "noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);"); |
| -// sb.append(eol); |
| -// } |
| -// // done |
| -// _addInsertEdit3(sb); |
| -// _endRange = SourceRangeFactory.rangeStartLength(insertOffset, 0); |
| -// // add proposal |
| -// _addFix(FixKind.CREATE_NO_SUCH_METHOD, []); |
| + ClassDeclaration targetClass = node.parent as ClassDeclaration; |
| + // prepare environment |
| + String eol = utils.endOfLine; |
| + String prefix = utils.getIndent(1); |
| + int insertOffset = targetClass.end - 1; |
| + // prepare source |
| + SourceBuilder sb = new SourceBuilder(file, insertOffset); |
| + { |
| + // insert empty line before existing member |
| + if (!targetClass.members.isEmpty) { |
| + sb.append(eol); |
| + } |
| + // append method |
| + sb.append(prefix); |
| + sb.append( |
| + "noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);"); |
| + sb.append(eol); |
| + } |
| + // done |
| + _insertBuilder(sb); |
| + endPosition = new Position(file, insertOffset, 0); |
| + // add proposal |
| + _addFix(FixKind.CREATE_NO_SUCH_METHOD, []); |
| } |
| void _addFix_createPart() { |
| @@ -727,6 +736,7 @@ class FixProcessor { |
| // } |
| } |
| + |
| void _addFix_importLibrary(FixKind kind, String importPath) { |
| // TODO(scheglov) implement |
| // CompilationUnitElement libraryUnitElement = |
| @@ -1151,97 +1161,93 @@ class FixProcessor { |
| } |
| void _addFix_undefinedMethod_create() { |
| - // TODO(scheglov) implement |
| -// if (node is SimpleIdentifier && node.parent is MethodInvocation) { |
| -// String name = (node as SimpleIdentifier).name; |
| -// MethodInvocation invocation = node.parent as MethodInvocation; |
| -// // prepare environment |
| -// String eol = utils.endOfLine; |
| -// Source targetSource; |
| -// String prefix; |
| -// int insertOffset; |
| -// String sourcePrefix; |
| -// String sourceSuffix; |
| -// bool staticModifier = false; |
| -// Expression target = invocation.realTarget; |
| -// if (target == null) { |
| -// targetSource = _source; |
| -// ClassMember enclosingMember = |
| -// node.getAncestor((node) => node is ClassMember); |
| -// staticModifier = _inStaticMemberContext2(enclosingMember); |
| -// prefix = utils.getNodePrefix(enclosingMember); |
| -// insertOffset = enclosingMember.end; |
| -// sourcePrefix = "${eol}${prefix}${eol}"; |
| -// sourceSuffix = ""; |
| -// } else { |
| -// // prepare target interface type |
| -// DartType targetType = target.bestType; |
| -// if (targetType is! InterfaceType) { |
| -// return; |
| -// } |
| -// ClassElement targetElement = targetType.element as ClassElement; |
| -// targetSource = targetElement.source; |
| -// // may be static |
| -// if (target is Identifier) { |
| -// staticModifier = target.bestElement.kind == ElementKind.CLASS; |
| -// } |
| -// // prepare insert offset |
| -// ClassDeclaration targetClass = targetElement.node; |
| -// prefix = " "; |
| -// insertOffset = targetClass.end - 1; |
| -// if (targetClass.members.isEmpty) { |
| -// sourcePrefix = ""; |
| -// } else { |
| -// sourcePrefix = "${prefix}${eol}"; |
| -// } |
| -// sourceSuffix = eol; |
| -// } |
| -// // build method source |
| -// SourceBuilder sb = new SourceBuilder.con1(insertOffset); |
| -// { |
| -// sb.append(sourcePrefix); |
| -// sb.append(prefix); |
| -// // may be "static" |
| -// if (staticModifier) { |
| -// sb.append("static "); |
| -// } |
| -// // may be return type |
| -// { |
| -// DartType type = |
| -// _addFix_undefinedMethod_create_getReturnType(invocation); |
| -// if (type != null) { |
| -// String typeSource = utils.getTypeSource2(type); |
| -// if (typeSource != "dynamic") { |
| -// sb.startPosition("RETURN_TYPE"); |
| -// sb.append(typeSource); |
| -// sb.endPosition(); |
| -// sb.append(" "); |
| -// } |
| -// } |
| -// } |
| -// // append name |
| -// { |
| -// sb.startPosition("NAME"); |
| -// sb.append(name); |
| -// sb.endPosition(); |
| -// } |
| -// _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList); |
| -// sb.append(") {${eol}${prefix}}"); |
| -// sb.append(sourceSuffix); |
| -// } |
| -// // insert source |
| -// _addInsertEdit(insertOffset, sb.toString()); |
| -// // add linked positions |
| -// if (targetSource == _source) { |
| -// _addLinkedPosition("NAME", sb, SourceRangeFactory.rangeNode(node)); |
| -// } |
| -// _addLinkedPositions(sb); |
| -// // add proposal |
| -// _addUnitCorrectionProposal2( |
| -// targetSource, |
| -// FixKind.CREATE_METHOD, |
| -// [name]); |
| -// } |
| + if (node is SimpleIdentifier && node.parent is MethodInvocation) { |
| + String name = (node as SimpleIdentifier).name; |
| + MethodInvocation invocation = node.parent as MethodInvocation; |
| + // prepare environment |
| + String eol = utils.endOfLine; |
| + Source targetSource; |
| + String prefix; |
| + int insertOffset; |
| + String sourcePrefix; |
| + String sourceSuffix; |
| + bool staticModifier = false; |
| + Expression target = invocation.realTarget; |
| + if (target == null) { |
| + targetSource = source; |
| + ClassMember enclosingMember = |
| + node.getAncestor((node) => node is ClassMember); |
| + staticModifier = _inStaticMemberContext2(enclosingMember); |
| + prefix = utils.getNodePrefix(enclosingMember); |
| + insertOffset = enclosingMember.end; |
| + sourcePrefix = "${eol}${prefix}${eol}"; |
| + sourceSuffix = ""; |
| + } else { |
| + // prepare target interface type |
| + DartType targetType = target.bestType; |
| + if (targetType is! InterfaceType) { |
| + return; |
| + } |
| + ClassElement targetElement = targetType.element as ClassElement; |
| + targetSource = targetElement.source; |
| + // may be static |
| + if (target is Identifier) { |
| + staticModifier = target.bestElement.kind == ElementKind.CLASS; |
| + } |
| + // prepare insert offset |
| + ClassDeclaration targetClass = targetElement.node; |
| + prefix = " "; |
| + insertOffset = targetClass.end - 1; |
| + if (targetClass.members.isEmpty) { |
| + sourcePrefix = ""; |
| + } else { |
| + sourcePrefix = "${prefix}${eol}"; |
| + } |
| + sourceSuffix = eol; |
| + } |
| + String targetFile = targetSource.fullName; |
| + // build method source |
| + SourceBuilder sb = new SourceBuilder(targetFile, insertOffset); |
| + { |
| + sb.append(sourcePrefix); |
| + sb.append(prefix); |
| + // may be "static" |
| + if (staticModifier) { |
| + sb.append("static "); |
| + } |
| + // may be return type |
| + { |
| + DartType type = |
| + _addFix_undefinedMethod_create_getReturnType(invocation); |
| + if (type != null) { |
| + String typeSource = utils.getTypeSource(type); |
| + if (typeSource != "dynamic") { |
|
Paul Berry
2014/07/25 00:28:46
It seems weird that we use a string comparison her
scheglov
2014/07/25 03:20:50
Done.
|
| + sb.startPosition("RETURN_TYPE"); |
| + sb.append(typeSource); |
| + sb.endPosition(); |
| + sb.append(" "); |
| + } |
| + } |
| + } |
| + // append name |
| + { |
| + sb.startPosition("NAME"); |
| + sb.append(name); |
| + sb.endPosition(); |
| + } |
| + _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList); |
| + sb.append(") {${eol}${prefix}}"); |
| + sb.append(sourceSuffix); |
| + } |
| + // insert source |
| + _insertBuilder(sb); |
| + // add linked positions |
| + if (targetSource == source) { |
| + _addLinkedPosition3('NAME', sb, rf.rangeNode(node)); |
| + } |
| + // add proposal |
| + _addFix(FixKind.CREATE_METHOD, [name], fixFile: targetFile); |
| + } |
| } |
| /** |
| @@ -1249,113 +1255,111 @@ class FixProcessor { |
| */ |
| DartType |
| _addFix_undefinedMethod_create_getReturnType(MethodInvocation invocation) { |
| - // TODO(scheglov) implement |
| -// AstNode parent = invocation.parent; |
| -// // myFunction(); |
| -// if (parent is ExpressionStatement) { |
| -// return VoidTypeImpl.instance; |
| -// } |
| -// // return myFunction(); |
| -// if (parent is ReturnStatement) { |
| -// ExecutableElement executable = |
| -// CorrectionUtils.getEnclosingExecutableElement(invocation); |
| -// return executable != null ? executable.returnType : null; |
| -// } |
| -// // int v = myFunction(); |
| -// if (parent is VariableDeclaration) { |
| -// VariableDeclaration variableDeclaration = parent; |
| -// if (identical(variableDeclaration.initializer, invocation)) { |
| -// VariableElement variableElement = variableDeclaration.element; |
| -// if (variableElement != null) { |
| -// return variableElement.type; |
| -// } |
| -// } |
| -// } |
| -// // v = myFunction(); |
| -// if (parent is AssignmentExpression) { |
| -// AssignmentExpression assignment = parent; |
| -// if (identical(assignment.rightHandSide, invocation)) { |
| -// if (assignment.operator.type == TokenType.EQ) { |
| -// // v = myFunction(); |
| -// Expression lhs = assignment.leftHandSide; |
| -// if (lhs != null) { |
| -// return lhs.bestType; |
| -// } |
| -// } else { |
| -// // v += myFunction(); |
| -// MethodElement method = assignment.bestElement; |
| -// if (method != null) { |
| -// List<ParameterElement> parameters = method.parameters; |
| -// if (parameters.length == 1) { |
| -// return parameters[0].type; |
| -// } |
| -// } |
| -// } |
| -// } |
| -// } |
| -// // v + myFunction(); |
| -// if (parent is BinaryExpression) { |
| -// BinaryExpression binary = parent; |
| -// MethodElement method = binary.bestElement; |
| -// if (method != null) { |
| -// if (identical(binary.rightOperand, invocation)) { |
| -// List<ParameterElement> parameters = method.parameters; |
| -// return parameters.length == 1 ? parameters[0].type : null; |
| -// } |
| -// } |
| -// } |
| -// // foo( myFunction() ); |
| -// if (parent is ArgumentList) { |
| -// ParameterElement parameter = invocation.bestParameterElement; |
| -// return parameter != null ? parameter.type : null; |
| -// } |
| -// // bool |
| -// { |
| -// // assert( myFunction() ); |
| -// if (parent is AssertStatement) { |
| -// AssertStatement statement = parent; |
| -// if (identical(statement.condition, invocation)) { |
| -// return coreTypeBool; |
| -// } |
| -// } |
| -// // if ( myFunction() ) {} |
| -// if (parent is IfStatement) { |
| -// IfStatement statement = parent; |
| -// if (identical(statement.condition, invocation)) { |
| -// return coreTypeBool; |
| -// } |
| -// } |
| -// // while ( myFunction() ) {} |
| -// if (parent is WhileStatement) { |
| -// WhileStatement statement = parent; |
| -// if (identical(statement.condition, invocation)) { |
| -// return coreTypeBool; |
| -// } |
| -// } |
| -// // do {} while ( myFunction() ); |
| -// if (parent is DoStatement) { |
| -// DoStatement statement = parent; |
| -// if (identical(statement.condition, invocation)) { |
| -// return coreTypeBool; |
| -// } |
| -// } |
| -// // !myFunction() |
| -// if (parent is PrefixExpression) { |
| -// PrefixExpression prefixExpression = parent; |
| -// if (prefixExpression.operator.type == TokenType.BANG) { |
| -// return coreTypeBool; |
| -// } |
| -// } |
| -// // binary expression '&&' or '||' |
| -// if (parent is BinaryExpression) { |
| -// BinaryExpression binaryExpression = parent; |
| -// TokenType operatorType = binaryExpression.operator.type; |
| -// if (operatorType == TokenType.AMPERSAND_AMPERSAND || |
| -// operatorType == TokenType.BAR_BAR) { |
| -// return coreTypeBool; |
| -// } |
| -// } |
| -// } |
| + AstNode parent = invocation.parent; |
| + // myFunction(); |
| + if (parent is ExpressionStatement) { |
| + return VoidTypeImpl.instance; |
| + } |
| + // return myFunction(); |
| + if (parent is ReturnStatement) { |
| + ExecutableElement executable = getEnclosingExecutableElement(invocation); |
| + return executable != null ? executable.returnType : null; |
| + } |
| + // int v = myFunction(); |
| + if (parent is VariableDeclaration) { |
| + VariableDeclaration variableDeclaration = parent; |
| + if (identical(variableDeclaration.initializer, invocation)) { |
| + VariableElement variableElement = variableDeclaration.element; |
| + if (variableElement != null) { |
| + return variableElement.type; |
| + } |
| + } |
| + } |
| + // v = myFunction(); |
| + if (parent is AssignmentExpression) { |
| + AssignmentExpression assignment = parent; |
| + if (identical(assignment.rightHandSide, invocation)) { |
| + if (assignment.operator.type == TokenType.EQ) { |
| + // v = myFunction(); |
| + Expression lhs = assignment.leftHandSide; |
| + if (lhs != null) { |
| + return lhs.bestType; |
| + } |
| + } else { |
| + // v += myFunction(); |
| + MethodElement method = assignment.bestElement; |
| + if (method != null) { |
| + List<ParameterElement> parameters = method.parameters; |
| + if (parameters.length == 1) { |
| + return parameters[0].type; |
| + } |
| + } |
| + } |
| + } |
| + } |
| + // v + myFunction(); |
| + if (parent is BinaryExpression) { |
| + BinaryExpression binary = parent; |
| + MethodElement method = binary.bestElement; |
| + if (method != null) { |
| + if (identical(binary.rightOperand, invocation)) { |
| + List<ParameterElement> parameters = method.parameters; |
| + return parameters.length == 1 ? parameters[0].type : null; |
| + } |
| + } |
| + } |
| + // foo( myFunction() ); |
| + if (parent is ArgumentList) { |
| + ParameterElement parameter = invocation.bestParameterElement; |
| + return parameter != null ? parameter.type : null; |
| + } |
| + // bool |
| + { |
| + // assert( myFunction() ); |
| + if (parent is AssertStatement) { |
| + AssertStatement statement = parent; |
| + if (identical(statement.condition, invocation)) { |
| + return coreTypeBool; |
| + } |
| + } |
| + // if ( myFunction() ) {} |
| + if (parent is IfStatement) { |
| + IfStatement statement = parent; |
| + if (identical(statement.condition, invocation)) { |
| + return coreTypeBool; |
| + } |
| + } |
| + // while ( myFunction() ) {} |
| + if (parent is WhileStatement) { |
| + WhileStatement statement = parent; |
| + if (identical(statement.condition, invocation)) { |
| + return coreTypeBool; |
| + } |
| + } |
| + // do {} while ( myFunction() ); |
| + if (parent is DoStatement) { |
| + DoStatement statement = parent; |
| + if (identical(statement.condition, invocation)) { |
| + return coreTypeBool; |
| + } |
| + } |
| + // !myFunction() |
| + if (parent is PrefixExpression) { |
| + PrefixExpression prefixExpression = parent; |
| + if (prefixExpression.operator.type == TokenType.BANG) { |
| + return coreTypeBool; |
| + } |
| + } |
| + // binary expression '&&' or '||' |
| + if (parent is BinaryExpression) { |
| + BinaryExpression binaryExpression = parent; |
| + TokenType operatorType = binaryExpression.operator.type; |
| + if (operatorType == TokenType.AMPERSAND_AMPERSAND || |
| + operatorType == TokenType.BAR_BAR) { |
| + return coreTypeBool; |
| + } |
| + } |
| + } |
| // we don't know |
| return null; |
| } |
| @@ -1517,6 +1521,156 @@ class FixProcessor { |
| } |
| /** |
| + * Adds a single linked position to [groupId]. |
| + */ |
| + void _addLinkedPosition3(String groupId, SourceBuilder sb, |
| + SourceRange range) { |
| + if (sb.offset < range.offset) { |
| + int delta = sb.length; |
| + range = range.getTranslated(delta); |
| + } |
| + _addLinkedPosition(groupId, range); |
| + } |
| + |
| + /** |
| + * Prepares proposal for creating function corresponding to the given [FunctionType]. |
| + */ |
| + void _addProposal_createFunction(FunctionType functionType, String name, |
|
Paul Berry
2014/07/25 00:28:46
It seems like there's a lot in common between this
|
| + Source targetSource, int insertOffset, bool isStatic, String eol, String prefix, |
| + String sourcePrefix, String sourceSuffix) { |
| + // build method source |
| + String targetFile = targetSource.fullName; |
| + SourceBuilder sb = new SourceBuilder(targetFile, insertOffset); |
| + { |
| + sb.append(sourcePrefix); |
| + sb.append(prefix); |
| + // may be static |
| + if (isStatic) { |
| + sb.append("static "); |
| + } |
| + // may be return type |
| + { |
| + DartType returnType = functionType.returnType; |
| + if (returnType != null) { |
| + String typeSource = utils.getTypeSource(returnType); |
| + if (typeSource != "dynamic") { |
|
Paul Berry
2014/07/25 00:28:46
Use returnType.isDynamic here too.
scheglov
2014/07/25 03:20:50
Done.
|
| + sb.startPosition("RETURN_TYPE"); |
| + sb.append(typeSource); |
| + sb.endPosition(); |
| + sb.append(" "); |
| + } |
| + } |
| + } |
| + // append name |
| + { |
| + sb.startPosition("NAME"); |
| + sb.append(name); |
| + sb.endPosition(); |
| + } |
| + // append parameters |
| + sb.append("("); |
| + List<ParameterElement> parameters = functionType.parameters; |
| + for (int i = 0; i < parameters.length; i++) { |
| + ParameterElement parameter = parameters[i]; |
| + // append separator |
| + if (i != 0) { |
| + sb.append(", "); |
| + } |
| + // append type name |
| + DartType type = parameter.type; |
| + String typeSource = utils.getTypeSource(type); |
| + { |
|
Paul Berry
2014/07/25 00:28:45
Should we guard this with "if (!type.isDynamic)",
scheglov
2014/07/25 03:20:50
Done.
I've also added a test.
|
| + sb.startPosition("TYPE${i}"); |
| + sb.append(typeSource); |
| + _addSuperTypeProposals(sb, new Set(), type); |
| + sb.endPosition(); |
| + } |
| + sb.append(" "); |
| + // append parameter name |
| + { |
| + sb.startPosition("ARG${i}"); |
| + sb.append(parameter.displayName); |
| + sb.endPosition(); |
| + } |
| + } |
| + sb.append(")"); |
| + // close method |
| + sb.append(" {${eol}${prefix}}"); |
|
Paul Berry
2014/07/25 00:28:46
Space before $eol seems unnecessary.
scheglov
2014/07/25 03:20:50
The space is before "{", which opens the body bloc
|
| + sb.append(sourceSuffix); |
| + } |
| + // insert source |
| + _insertBuilder(sb); |
| + // add linked positions |
| + if (targetSource == source) { |
| + _addLinkedPosition3("NAME", sb, rf.rangeNode(node)); |
| + } |
| + } |
| + |
| + /** |
| + * Adds proposal for creating method corresponding to the given [FunctionType] in the given |
| + * [ClassElement]. |
| + */ |
| + void _addProposal_createFunction_function(FunctionType functionType) { |
| + String name = (node as SimpleIdentifier).name; |
| + // prepare environment |
| + String eol = utils.endOfLine; |
| + int insertOffset = unit.end; |
| + // prepare prefix |
| + String prefix = ""; |
| + String sourcePrefix = "${eol}"; |
| + String sourceSuffix = eol; |
| + _addProposal_createFunction( |
| + functionType, |
| + name, |
| + source, |
| + insertOffset, |
| + false, |
| + eol, |
| + prefix, |
| + sourcePrefix, |
| + sourceSuffix); |
| + // add proposal |
| + _addFix(FixKind.CREATE_FUNCTION, [name], fixFile: file); |
| + } |
| + |
| + /** |
| + * Adds proposal for creating method corresponding to the given [FunctionType] in the given |
| + * [ClassElement]. |
| + */ |
| + void _addProposal_createFunction_method(ClassElement targetClassElement, |
| + FunctionType functionType) { |
| + String name = (node as SimpleIdentifier).name; |
| + // prepare environment |
| + String eol = utils.endOfLine; |
|
Paul Berry
2014/07/25 00:28:45
Suggestion: rather than force the caller to look u
scheglov
2014/07/25 03:20:50
Done.
|
| + Source targetSource = targetClassElement.source; |
| + String targetFile = targetSource.fullName; |
| + // prepare insert offset |
| + ClassDeclaration targetClassNode = targetClassElement.node; |
| + int insertOffset = targetClassNode.end - 1; |
| + // prepare prefix |
| + String prefix = " "; |
| + String sourcePrefix; |
| + if (targetClassNode.members.isEmpty) { |
| + sourcePrefix = ""; |
| + } else { |
| + sourcePrefix = "${prefix}${eol}"; |
|
Paul Berry
2014/07/25 00:28:45
This will just insert a blank line containing whit
scheglov
2014/07/25 03:20:51
Done.
|
| + } |
| + String sourceSuffix = eol; |
| + _addProposal_createFunction( |
| + functionType, |
| + name, |
| + targetSource, |
| + insertOffset, |
| + _inStaticMemberContext(), |
| + eol, |
| + prefix, |
| + sourcePrefix, |
| + sourceSuffix); |
| + // add proposal |
| + _addFix(FixKind.CREATE_METHOD, [name], fixFile: targetFile); |
| + } |
| + |
| + /** |
| * Adds a new [Edit] to [edits]. |
| */ |
| void _addRemoveEdit(SourceRange range) { |
| @@ -1587,15 +1741,13 @@ class FixProcessor { |
| sb.write(")"); |
| } |
| -// void _addLinkedPositionProposal(String group, |
| -// LinkedPositionProposal proposal) { |
| -// List<LinkedPositionProposal> nodeProposals = linkedPositionProposals[group]; |
| -// if (nodeProposals == null) { |
| -// nodeProposals = <LinkedPositionProposal>[]; |
| -// linkedPositionProposals[group] = nodeProposals; |
| -// } |
| -// nodeProposals.add(proposal); |
| -// } |
| + void _appendType(StringBuffer sb, DartType type) { |
| + if (type != null && !type.isDynamic) { |
| + String typeSource = utils.getTypeSource(type); |
| + sb.write(typeSource); |
| + sb.write(' '); |
| + } |
| + } |
| /** |
| * @return the string to display as the name of the given constructor in a proposal name. |
| @@ -1616,6 +1768,78 @@ class FixProcessor { |
| } |
| /** |
| + * Returns the [Type] with given name from the `dart:core` library. |
| + */ |
| + DartType _getCoreType(String name) { |
| + List<LibraryElement> libraries = unitLibraryElement.importedLibraries; |
| + for (LibraryElement library in libraries) { |
| + if (library.isDartCore) { |
| + ClassElement classElement = library.getType(name); |
| + if (classElement != null) { |
| + return classElement.type; |
| + } |
| + return null; |
| + } |
| + } |
| + return null; |
| + } |
| + |
| + Map<ParameterElement, String> |
| + _getDefaultValueMap(List<ParameterElement> parameters) { |
| + Map<ParameterElement, String> defaultSourceMap = {}; |
| + Map<Source, String> sourceContentMap = {}; |
| + for (ParameterElement parameter in parameters) { |
| + SourceRange valueRange = parameter.defaultValueRange; |
| + if (valueRange != null) { |
| + Source source = parameter.source; |
| + String sourceContent = sourceContentMap[source]; |
| + if (sourceContent == null) { |
| + sourceContent = getSourceContent(parameter.context, source); |
| + sourceContentMap[source] = sourceContent; |
| + } |
| + String valueSource = |
| + sourceContent.substring(valueRange.offset, valueRange.end); |
| + defaultSourceMap[parameter] = valueSource; |
| + } |
| + } |
| + return defaultSourceMap; |
| + } |
| + |
| + /** |
| + * Returns `true` if [node] if part of a static method or of a field |
| + * initializer. |
| + */ |
| + bool _inStaticMemberContext() { |
|
Paul Berry
2014/07/25 00:28:45
This won't do the right thing if node is in a cons
scheglov
2014/07/25 03:20:50
Added the test and fixed.
|
| + ClassMember member = node.getAncestor((node) => node is ClassMember); |
| + return _inStaticMemberContext2(member); |
|
Paul Berry
2014/07/25 00:28:45
Rather than having two functions and forcing the c
scheglov
2014/07/25 03:20:51
Done.
|
| + } |
| + |
| +// void _addLinkedPositionProposal(String group, |
| +// LinkedPositionProposal proposal) { |
| +// List<LinkedPositionProposal> nodeProposals = linkedPositionProposals[group]; |
| +// if (nodeProposals == null) { |
| +// nodeProposals = <LinkedPositionProposal>[]; |
| +// linkedPositionProposals[group] = nodeProposals; |
| +// } |
| +// nodeProposals.add(proposal); |
| +// } |
| + |
| + /** |
| + * Returns `true` if the given [ClassMember] is a part of a static method or |
| + * a field initializer. |
| + */ |
| + bool _inStaticMemberContext2(ClassMember member) { |
| + if (member is MethodDeclaration) { |
| + return member.isStatic; |
| + } |
| + // field initializer cannot reference "this" |
| + if (member is FieldDeclaration) { |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| + /** |
| * Inserts the given [SourceBuilder] at its offset. |
| */ |
| void _insertBuilder(SourceBuilder builder) { |