mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:20:31 +00:00
Macro. Initial support for TypeAnnotationDiagnosticTarget.
Change-Id: I008203e570e64207f010e5c818b7a2e30c2e1001 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349415 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
parent
12841a6e29
commit
996a51c9bb
14 changed files with 1325 additions and 230 deletions
|
@ -74,6 +74,7 @@ class LibraryAnalyzer {
|
|||
|
||||
final Map<FileState, LineInfo> _fileToLineInfo = {};
|
||||
|
||||
final Map<FileState, CompilationUnitImpl> _libraryUnits = {};
|
||||
final Map<FileState, IgnoreInfo> _fileToIgnoreInfo = {};
|
||||
final Map<FileState, RecordingErrorListener> _errorListeners = {};
|
||||
final Map<FileState, ErrorReporter> _errorReporters = {};
|
||||
|
@ -92,6 +93,7 @@ class LibraryAnalyzer {
|
|||
constructorFieldsVerifier: ConstructorFieldsVerifier(
|
||||
typeSystem: _typeSystem,
|
||||
),
|
||||
units: _libraryUnits,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -101,12 +103,12 @@ class LibraryAnalyzer {
|
|||
|
||||
/// Compute analysis results for all units of the library.
|
||||
List<UnitAnalysisResult> analyze() {
|
||||
var units = _parseAndResolve();
|
||||
_computeDiagnostics(units);
|
||||
_parseAndResolve();
|
||||
_computeDiagnostics();
|
||||
|
||||
// Return full results.
|
||||
var results = <UnitAnalysisResult>[];
|
||||
units.forEach((file, unit) {
|
||||
_libraryUnits.forEach((file, unit) {
|
||||
var errors = _getErrorListener(file).errors;
|
||||
errors = _filterIgnoredErrors(file, errors);
|
||||
results.add(UnitAnalysisResult(file, unit, errors));
|
||||
|
@ -186,8 +188,8 @@ class LibraryAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
var units = _parseAndResolve();
|
||||
var unit = units[file]!;
|
||||
_parseAndResolve();
|
||||
var unit = _libraryUnits[file]!;
|
||||
return AnalysisForCompletionResult(
|
||||
parsedUnit: unit,
|
||||
resolvedNodes: [unit],
|
||||
|
@ -268,10 +270,10 @@ class LibraryAnalyzer {
|
|||
);
|
||||
}
|
||||
|
||||
/// Compute diagnostics in [units], including errors and warnings,
|
||||
/// Compute diagnostics in [_libraryUnits], including errors and warnings,
|
||||
/// lints, and a few other cases.
|
||||
void _computeDiagnostics(Map<FileState, CompilationUnitImpl> units) {
|
||||
units.forEach((file, unit) {
|
||||
void _computeDiagnostics() {
|
||||
_libraryUnits.forEach((file, unit) {
|
||||
_computeVerifyErrors(file, unit);
|
||||
});
|
||||
|
||||
|
@ -280,7 +282,7 @@ class LibraryAnalyzer {
|
|||
if (_analysisOptions.warning) {
|
||||
var usedImportedElements = <UsedImportedElements>[];
|
||||
var usedLocalElements = <UsedLocalElements>[];
|
||||
for (var unit in units.values) {
|
||||
for (var unit in _libraryUnits.values) {
|
||||
{
|
||||
var visitor = GatherUsedLocalElementsVisitor(_libraryElement);
|
||||
unit.accept(visitor);
|
||||
|
@ -293,7 +295,7 @@ class LibraryAnalyzer {
|
|||
}
|
||||
}
|
||||
var usedElements = UsedLocalElements.merge(usedLocalElements);
|
||||
units.forEach((file, unit) {
|
||||
_libraryUnits.forEach((file, unit) {
|
||||
_computeWarnings(
|
||||
file,
|
||||
unit,
|
||||
|
@ -306,7 +308,7 @@ class LibraryAnalyzer {
|
|||
if (_analysisOptions.lint) {
|
||||
final allUnits = _library.files
|
||||
.map((file) {
|
||||
final unit = units[file];
|
||||
final unit = _libraryUnits[file];
|
||||
if (unit != null) {
|
||||
return LinterContextUnit2(file, unit);
|
||||
} else {
|
||||
|
@ -321,7 +323,7 @@ class LibraryAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
_checkForInconsistentLanguageVersionOverride(units);
|
||||
_checkForInconsistentLanguageVersionOverride(_libraryUnits);
|
||||
|
||||
// This must happen after all other diagnostics have been computed but
|
||||
// before the list of diagnostics has been filtered.
|
||||
|
@ -576,21 +578,17 @@ class LibraryAnalyzer {
|
|||
}
|
||||
|
||||
/// Parse and resolve all files in [_library].
|
||||
Map<FileState, CompilationUnitImpl> _parseAndResolve() {
|
||||
final units = <FileState, CompilationUnitImpl>{};
|
||||
void _parseAndResolve() {
|
||||
_resolveDirectives(
|
||||
containerKind: _library,
|
||||
containerElement: _libraryElement,
|
||||
units: units,
|
||||
);
|
||||
|
||||
units.forEach((file, unit) {
|
||||
_libraryUnits.forEach((file, unit) {
|
||||
_resolveFile(file, unit);
|
||||
});
|
||||
|
||||
_computeConstants(units.values);
|
||||
|
||||
return units;
|
||||
_computeConstants(_libraryUnits.values);
|
||||
}
|
||||
|
||||
void _resolveAugmentationImportDirective({
|
||||
|
@ -599,7 +597,6 @@ class LibraryAnalyzer {
|
|||
required AugmentationImportState state,
|
||||
required ErrorReporter errorReporter,
|
||||
required Set<AugmentationFileKind> seenAugmentations,
|
||||
required Map<FileState, CompilationUnitImpl> units,
|
||||
}) {
|
||||
directive?.element = element;
|
||||
|
||||
|
@ -655,7 +652,7 @@ class LibraryAnalyzer {
|
|||
|
||||
final augmentationFile = importedAugmentationKind.file;
|
||||
final augmentationUnit = _parse(augmentationFile);
|
||||
units[augmentationFile] = augmentationUnit;
|
||||
_libraryUnits[augmentationFile] = augmentationUnit;
|
||||
|
||||
final importedAugmentation = element.importedAugmentation!;
|
||||
augmentationUnit.declaredElement =
|
||||
|
@ -670,7 +667,6 @@ class LibraryAnalyzer {
|
|||
_resolveDirectives(
|
||||
containerKind: importedAugmentationKind,
|
||||
containerElement: importedAugmentation,
|
||||
units: units,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -679,12 +675,11 @@ class LibraryAnalyzer {
|
|||
void _resolveDirectives({
|
||||
required LibraryOrAugmentationFileKind containerKind,
|
||||
required LibraryOrAugmentationElementImpl containerElement,
|
||||
required Map<FileState, CompilationUnitImpl> units,
|
||||
}) {
|
||||
final containerFile = containerKind.file;
|
||||
final containerUnit = _parse(containerFile);
|
||||
containerUnit.declaredElement = containerElement.definingCompilationUnit;
|
||||
units[containerFile] = containerUnit;
|
||||
_libraryUnits[containerFile] = containerUnit;
|
||||
|
||||
final containerErrorReporter = _getErrorReporter(containerFile);
|
||||
|
||||
|
@ -705,7 +700,6 @@ class LibraryAnalyzer {
|
|||
state: containerKind.augmentationImports[index],
|
||||
errorReporter: containerErrorReporter,
|
||||
seenAugmentations: seenAugmentations,
|
||||
units: units,
|
||||
);
|
||||
} else if (directive is ExportDirectiveImpl) {
|
||||
final index = libraryExportIndex++;
|
||||
|
@ -743,7 +737,6 @@ class LibraryAnalyzer {
|
|||
partElement: containerElement.parts[index],
|
||||
errorReporter: containerErrorReporter,
|
||||
libraryNameNode: libraryNameNode,
|
||||
units: units,
|
||||
seenPartSources: seenPartSources,
|
||||
);
|
||||
}
|
||||
|
@ -762,7 +755,6 @@ class LibraryAnalyzer {
|
|||
state: macroImport,
|
||||
errorReporter: containerErrorReporter,
|
||||
seenAugmentations: seenAugmentations,
|
||||
units: units,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -984,7 +976,6 @@ class LibraryAnalyzer {
|
|||
required PartElement partElement,
|
||||
required ErrorReporter errorReporter,
|
||||
required LibraryIdentifier? libraryNameNode,
|
||||
required Map<FileState, CompilationUnitImpl> units,
|
||||
required Set<Source> seenPartSources,
|
||||
}) {
|
||||
StringLiteral partUri = directive.uri;
|
||||
|
@ -1065,7 +1056,7 @@ class LibraryAnalyzer {
|
|||
}
|
||||
|
||||
final partUnit = _parse(includedFile);
|
||||
units[includedFile] = partUnit;
|
||||
_libraryUnits[includedFile] = partUnit;
|
||||
|
||||
final partElementUri = partElement.uri;
|
||||
if (partElementUri is DirectiveUriWithUnitImpl) {
|
||||
|
|
|
@ -25,6 +25,122 @@ abstract class AnalysisResultImpl implements AnalysisResult {
|
|||
});
|
||||
}
|
||||
|
||||
/// A visitor which locates the [AstNode] which declares [element].
|
||||
class DeclarationByElementLocator extends UnifyingAstVisitor<void> {
|
||||
// TODO(srawlins): This visitor could be further optimized by special casing each static
|
||||
// type of [element]. For example, for library-level elements (classes etc),
|
||||
// we can iterate over the compilation unit's declarations.
|
||||
|
||||
final Element element;
|
||||
final int _nameOffset;
|
||||
AstNode? result;
|
||||
|
||||
DeclarationByElementLocator(this.element) : _nameOffset = element.nameOffset;
|
||||
|
||||
@override
|
||||
void visitNode(AstNode node) {
|
||||
if (result != null) return;
|
||||
|
||||
if (node.endToken.end < _nameOffset || node.offset > _nameOffset) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (element is InterfaceElement) {
|
||||
if (node is ClassDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is ClassTypeAlias) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is EnumDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is MixinDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is ExtensionTypeDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
} else if (element is ConstructorElement) {
|
||||
if (node is ConstructorDeclaration) {
|
||||
if (node.name != null) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else {
|
||||
if (_hasOffset(node.returnType)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (element is ExtensionElement) {
|
||||
if (node is ExtensionDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
} else if (element is FieldElement) {
|
||||
if (node is EnumConstantDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is VariableDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
} else if (element is FunctionElement) {
|
||||
if (node is FunctionDeclaration && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (element is LocalVariableElement) {
|
||||
if (node is VariableDeclaration && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (element is MethodElement) {
|
||||
if (node is MethodDeclaration && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (element is ParameterElement) {
|
||||
if (node is FormalParameter && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (element is PropertyAccessorElement) {
|
||||
if (node is FunctionDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is MethodDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
} else if (element is TopLevelVariableElement) {
|
||||
if (node is VariableDeclaration && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
node.visitChildren(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool _hasOffset(AstNode? node) {
|
||||
return node?.offset == _nameOffset;
|
||||
}
|
||||
|
||||
bool _hasOffset2(Token? token) {
|
||||
return token?.offset == _nameOffset;
|
||||
}
|
||||
}
|
||||
|
||||
class ElementDeclarationResultImpl implements ElementDeclarationResult {
|
||||
@override
|
||||
final Element element;
|
||||
|
@ -175,7 +291,7 @@ class ParsedLibraryResultImpl extends AnalysisResultImpl
|
|||
},
|
||||
);
|
||||
|
||||
var locator = _DeclarationByElementLocator(element);
|
||||
var locator = DeclarationByElementLocator(element);
|
||||
unitResult.unit.accept(locator);
|
||||
var declaration = locator.result;
|
||||
|
||||
|
@ -298,7 +414,7 @@ class ResolvedLibraryResultImpl extends AnalysisResultImpl
|
|||
},
|
||||
);
|
||||
|
||||
var locator = _DeclarationByElementLocator(element);
|
||||
var locator = DeclarationByElementLocator(element);
|
||||
unitResult.unit.accept(locator);
|
||||
var declaration = locator.result;
|
||||
|
||||
|
@ -361,119 +477,3 @@ class UnitElementResultImpl extends FileResultImpl
|
|||
required this.element,
|
||||
});
|
||||
}
|
||||
|
||||
/// A visitor which locates the [AstNode] which declares [element].
|
||||
class _DeclarationByElementLocator extends UnifyingAstVisitor<void> {
|
||||
// TODO(srawlins): This visitor could be further optimized by special casing each static
|
||||
// type of [element]. For example, for library-level elements (classes etc),
|
||||
// we can iterate over the compilation unit's declarations.
|
||||
|
||||
final Element element;
|
||||
final int _nameOffset;
|
||||
AstNode? result;
|
||||
|
||||
_DeclarationByElementLocator(this.element) : _nameOffset = element.nameOffset;
|
||||
|
||||
@override
|
||||
void visitNode(AstNode node) {
|
||||
if (result != null) return;
|
||||
|
||||
if (node.endToken.end < _nameOffset || node.offset > _nameOffset) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (element is InterfaceElement) {
|
||||
if (node is ClassDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is ClassTypeAlias) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is EnumDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is MixinDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is ExtensionTypeDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
} else if (element is ConstructorElement) {
|
||||
if (node is ConstructorDeclaration) {
|
||||
if (node.name != null) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else {
|
||||
if (_hasOffset(node.returnType)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (element is ExtensionElement) {
|
||||
if (node is ExtensionDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
} else if (element is FieldElement) {
|
||||
if (node is EnumConstantDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is VariableDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
} else if (element is FunctionElement) {
|
||||
if (node is FunctionDeclaration && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (element is LocalVariableElement) {
|
||||
if (node is VariableDeclaration && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (element is MethodElement) {
|
||||
if (node is MethodDeclaration && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (element is ParameterElement) {
|
||||
if (node is FormalParameter && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (element is PropertyAccessorElement) {
|
||||
if (node is FunctionDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
} else if (node is MethodDeclaration) {
|
||||
if (_hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
} else if (element is TopLevelVariableElement) {
|
||||
if (node is VariableDeclaration && _hasOffset2(node.name)) {
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
node.visitChildren(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool _hasOffset(AstNode? node) {
|
||||
return node?.offset == _nameOffset;
|
||||
}
|
||||
|
||||
bool _hasOffset2(Token? token) {
|
||||
return token?.offset == _nameOffset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import 'package:analyzer/dart/element/type_provider.dart';
|
|||
import 'package:analyzer/diagnostic/diagnostic.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/error/listener.dart';
|
||||
import 'package:analyzer/src/dart/analysis/file_state.dart';
|
||||
import 'package:analyzer/src/dart/analysis/results.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/ast/extensions.dart';
|
||||
import 'package:analyzer/src/dart/element/class_hierarchy.dart';
|
||||
|
@ -50,8 +52,10 @@ import 'package:analyzer/src/generated/java_core.dart';
|
|||
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
|
||||
import 'package:analyzer/src/generated/this_access_tracker.dart';
|
||||
import 'package:analyzer/src/summary2/macro_application_error.dart';
|
||||
import 'package:analyzer/src/summary2/macro_type_location.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/object.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/string.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
class EnclosingExecutableContext {
|
||||
final ExecutableElement? element;
|
||||
|
@ -848,13 +852,13 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
}
|
||||
|
||||
@override
|
||||
void visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
ExecutableElement functionElement = node.declaredElement!;
|
||||
if (functionElement.enclosingElement is! CompilationUnitElement) {
|
||||
_hiddenElements!.declare(functionElement);
|
||||
void visitFunctionDeclaration(covariant FunctionDeclarationImpl node) {
|
||||
var element = node.declaredElement!;
|
||||
if (element.enclosingElement is! CompilationUnitElement) {
|
||||
_hiddenElements!.declare(element);
|
||||
}
|
||||
|
||||
_withEnclosingExecutable(functionElement, () {
|
||||
_withEnclosingExecutable(element, () {
|
||||
TypeAnnotation? returnType = node.returnType;
|
||||
if (node.isSetter) {
|
||||
FunctionExpression functionExpression = node.functionExpression;
|
||||
|
@ -866,6 +870,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
_returnTypeVerifier.verifyReturnType(returnType);
|
||||
_checkForMainFunction1(node.name, node.declaredElement!);
|
||||
_checkForMainFunction2(node);
|
||||
_reportMacroDiagnostics(element, node.metadata);
|
||||
super.visitFunctionDeclaration(node);
|
||||
});
|
||||
}
|
||||
|
@ -5928,6 +5933,73 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
MacroTargetElement element,
|
||||
List<Annotation> metadata,
|
||||
) {
|
||||
AstNode? locationNode(TypeAnnotationLocation location) {
|
||||
switch (location) {
|
||||
case ElementTypeLocation():
|
||||
var element = location.element;
|
||||
return libraryVerificationContext.declarationByElement(element);
|
||||
case FormalParameterTypeLocation():
|
||||
var node = locationNode(location.parent);
|
||||
switch (node) {
|
||||
case FunctionDeclaration():
|
||||
var parameterList = node.functionExpression.parameters;
|
||||
return parameterList!.parameters[location.index];
|
||||
case MethodDeclaration():
|
||||
var parameterList = node.parameters;
|
||||
return parameterList!.parameters[location.index];
|
||||
default:
|
||||
throw UnimplementedError('${node.runtimeType}');
|
||||
}
|
||||
case ListIndexTypeLocation():
|
||||
var node = locationNode(location.parent);
|
||||
switch (node) {
|
||||
case NamedType():
|
||||
return node.typeArguments?.arguments[location.index];
|
||||
default:
|
||||
throw UnimplementedError('${node.runtimeType}');
|
||||
}
|
||||
case ReturnTypeLocation():
|
||||
var node = locationNode(location.parent);
|
||||
switch (node) {
|
||||
case FunctionDeclaration():
|
||||
return node.returnType;
|
||||
case GenericFunctionType():
|
||||
return node.returnType;
|
||||
case MethodDeclaration():
|
||||
return node.returnType;
|
||||
default:
|
||||
throw UnimplementedError('${node.runtimeType}');
|
||||
}
|
||||
case VariableTypeLocation():
|
||||
var node = locationNode(location.parent);
|
||||
if (node is DefaultFormalParameter) {
|
||||
node = node.parameter;
|
||||
}
|
||||
var parent = node?.parent;
|
||||
switch (node) {
|
||||
case SimpleFormalParameter():
|
||||
return node.type;
|
||||
case VariableDeclaration():
|
||||
if (parent is VariableDeclarationList) {
|
||||
return parent.type;
|
||||
}
|
||||
}
|
||||
throw UnimplementedError(
|
||||
'${node.runtimeType} ${parent.runtimeType}',
|
||||
);
|
||||
case ExtendsClauseTypeLocation():
|
||||
var node = locationNode(location.parent);
|
||||
switch (node) {
|
||||
case ClassDeclaration():
|
||||
return node.extendsClause!.superclass;
|
||||
default:
|
||||
throw UnimplementedError('${node.runtimeType}');
|
||||
}
|
||||
default:
|
||||
throw UnimplementedError('${location.runtimeType}');
|
||||
}
|
||||
}
|
||||
|
||||
DiagnosticMessage convertMessage(MacroDiagnosticMessage object) {
|
||||
final target = object.target;
|
||||
switch (target) {
|
||||
|
@ -5949,6 +6021,9 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
offset: element.nameOffset,
|
||||
url: null,
|
||||
);
|
||||
case TypeAnnotationMacroDiagnosticTarget():
|
||||
// TODO(scheglov): Handle this case.
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6009,6 +6084,14 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
[diagnostic.message.message],
|
||||
diagnostic.contextMessages.map(convertMessage).toList(),
|
||||
);
|
||||
case TypeAnnotationMacroDiagnosticTarget():
|
||||
var errorNode = locationNode(target.location)!;
|
||||
errorReporter.reportErrorForNode(
|
||||
errorCode,
|
||||
errorNode,
|
||||
[diagnostic.message.message],
|
||||
diagnostic.contextMessages.map(convertMessage).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6155,10 +6238,30 @@ class HiddenElements {
|
|||
class LibraryVerificationContext {
|
||||
final duplicationDefinitionContext = DuplicationDefinitionContext();
|
||||
final ConstructorFieldsVerifier constructorFieldsVerifier;
|
||||
final Map<FileState, CompilationUnitImpl> units;
|
||||
|
||||
LibraryVerificationContext({
|
||||
required this.constructorFieldsVerifier,
|
||||
required this.units,
|
||||
});
|
||||
|
||||
AstNode? declarationByElement(Element element) {
|
||||
var uri = element.library?.source.uri;
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var unit = units.entries.firstWhereOrNull((entry) {
|
||||
return entry.key.uri == uri;
|
||||
})?.value;
|
||||
if (unit == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var locator = DeclarationByElementLocator(element);
|
||||
unit.accept(locator);
|
||||
return locator.result;
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively visits a type annotation, looking uninstantiated bounds.
|
||||
|
|
|
@ -135,6 +135,15 @@ class Tag {
|
|||
static const int VoidType = 13;
|
||||
}
|
||||
|
||||
enum TypeAnnotationLocationKind {
|
||||
element,
|
||||
extendsClause,
|
||||
formalParameter,
|
||||
listIndex,
|
||||
returnType,
|
||||
variableType,
|
||||
}
|
||||
|
||||
enum TypeParameterVarianceTag {
|
||||
legacy,
|
||||
unrelated,
|
||||
|
|
|
@ -30,6 +30,7 @@ import 'package:analyzer/src/summary2/export.dart';
|
|||
import 'package:analyzer/src/summary2/informative_data.dart';
|
||||
import 'package:analyzer/src/summary2/linked_element_factory.dart';
|
||||
import 'package:analyzer/src/summary2/macro_application_error.dart';
|
||||
import 'package:analyzer/src/summary2/macro_type_location.dart';
|
||||
import 'package:analyzer/src/summary2/reference.dart';
|
||||
import 'package:analyzer/src/task/inference_error.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/collection.dart';
|
||||
|
@ -471,6 +472,7 @@ class FunctionElementLinkedData extends ElementLinkedData<FunctionElementImpl> {
|
|||
element.metadata = reader._readAnnotationList(
|
||||
unitElement: unitElement,
|
||||
);
|
||||
element.macroDiagnostics = reader.readMacroDiagnostics();
|
||||
_readTypeParameters(reader, element.typeParameters);
|
||||
element.returnType = reader.readRequiredType();
|
||||
_readFormalParameters(reader, element.parameters);
|
||||
|
@ -2367,6 +2369,38 @@ class ResolutionReader {
|
|||
|
||||
MacroDiagnosticMessage _readMacroDiagnosticMessage() {
|
||||
final message = _reader.readStringUtf8();
|
||||
|
||||
TypeAnnotationLocation readTypeAnnotationLocation() {
|
||||
var tag = readByte();
|
||||
var kind = TypeAnnotationLocationKind.values[tag];
|
||||
switch (kind) {
|
||||
case TypeAnnotationLocationKind.element:
|
||||
var element = readElement()!;
|
||||
return ElementTypeLocation(element);
|
||||
case TypeAnnotationLocationKind.extendsClause:
|
||||
var parent = readTypeAnnotationLocation();
|
||||
return ExtendsClauseTypeLocation(parent);
|
||||
case TypeAnnotationLocationKind.formalParameter:
|
||||
return FormalParameterTypeLocation(
|
||||
readTypeAnnotationLocation(),
|
||||
readUInt30(),
|
||||
);
|
||||
case TypeAnnotationLocationKind.listIndex:
|
||||
return ListIndexTypeLocation(
|
||||
readTypeAnnotationLocation(),
|
||||
readUInt30(),
|
||||
);
|
||||
case TypeAnnotationLocationKind.returnType:
|
||||
var parent = readTypeAnnotationLocation();
|
||||
return ReturnTypeLocation(parent);
|
||||
case TypeAnnotationLocationKind.variableType:
|
||||
var parent = readTypeAnnotationLocation();
|
||||
return VariableTypeLocation(parent);
|
||||
default:
|
||||
throw UnimplementedError('kind: $kind');
|
||||
}
|
||||
}
|
||||
|
||||
MacroDiagnosticTarget target;
|
||||
switch (readByte()) {
|
||||
case 0x00:
|
||||
|
@ -2378,6 +2412,9 @@ class ResolutionReader {
|
|||
target = ElementMacroDiagnosticTarget(
|
||||
element: element as ElementImpl,
|
||||
);
|
||||
case 0x02:
|
||||
var location = readTypeAnnotationLocation();
|
||||
target = TypeAnnotationMacroDiagnosticTarget(location: location);
|
||||
case final int tag:
|
||||
throw UnimplementedError('tag: $tag');
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import 'package:analyzer/src/summary2/data_writer.dart';
|
|||
import 'package:analyzer/src/summary2/element_flags.dart';
|
||||
import 'package:analyzer/src/summary2/export.dart';
|
||||
import 'package:analyzer/src/summary2/macro_application_error.dart';
|
||||
import 'package:analyzer/src/summary2/macro_type_location.dart';
|
||||
import 'package:analyzer/src/summary2/reference.dart';
|
||||
import 'package:analyzer/src/task/inference_error.dart';
|
||||
|
||||
|
@ -416,6 +417,7 @@ class BundleWriter {
|
|||
FunctionElementFlags.write(_sink, element);
|
||||
|
||||
_resolutionSink._writeAnnotationList(element.metadata);
|
||||
_resolutionSink.writeMacroDiagnostics(element.macroDiagnostics);
|
||||
|
||||
_writeTypeParameters(element.typeParameters, () {
|
||||
_resolutionSink.writeType(element.returnType);
|
||||
|
@ -978,6 +980,35 @@ class ResolutionSink extends _SummaryDataWriter {
|
|||
|
||||
void _writeMacroDiagnosticMessage(MacroDiagnosticMessage object) {
|
||||
writeStringUtf8(object.message);
|
||||
|
||||
void writeTypeAnnotationLocation(TypeAnnotationLocation location) {
|
||||
switch (location) {
|
||||
case ElementTypeLocation():
|
||||
writeByte(TypeAnnotationLocationKind.element.index);
|
||||
writeElement(location.element);
|
||||
case ExtendsClauseTypeLocation():
|
||||
writeByte(TypeAnnotationLocationKind.extendsClause.index);
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
case FormalParameterTypeLocation():
|
||||
writeByte(TypeAnnotationLocationKind.formalParameter.index);
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
writeUInt30(location.index);
|
||||
case ListIndexTypeLocation():
|
||||
writeByte(TypeAnnotationLocationKind.listIndex.index);
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
writeUInt30(location.index);
|
||||
case ReturnTypeLocation():
|
||||
writeByte(TypeAnnotationLocationKind.returnType.index);
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
case VariableTypeLocation():
|
||||
writeByte(TypeAnnotationLocationKind.variableType.index);
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
default:
|
||||
// TODO(scheglov): Handle this case.
|
||||
throw UnimplementedError('${location.runtimeType}');
|
||||
}
|
||||
}
|
||||
|
||||
final target = object.target;
|
||||
switch (target) {
|
||||
case ApplicationMacroDiagnosticTarget():
|
||||
|
@ -986,6 +1017,9 @@ class ResolutionSink extends _SummaryDataWriter {
|
|||
case ElementMacroDiagnosticTarget():
|
||||
writeByte(0x01);
|
||||
writeElement(target.element);
|
||||
case TypeAnnotationMacroDiagnosticTarget():
|
||||
writeByte(0x02);
|
||||
writeTypeAnnotationLocation(target.location);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -527,7 +527,9 @@ class LibraryMacroApplier {
|
|||
case macro.DeclarationDiagnosticTarget macroTarget:
|
||||
final element = (macroTarget.declaration as HasElement).element;
|
||||
target = ElementMacroDiagnosticTarget(element: element);
|
||||
default:
|
||||
case macro.TypeAnnotationDiagnosticTarget macroTarget:
|
||||
target = _typeAnnotationTarget(application, macroTarget);
|
||||
case null:
|
||||
target = ApplicationMacroDiagnosticTarget(
|
||||
annotationIndex: application.annotationIndex,
|
||||
);
|
||||
|
@ -713,6 +715,23 @@ class LibraryMacroApplier {
|
|||
return null;
|
||||
}
|
||||
|
||||
MacroDiagnosticTarget _typeAnnotationTarget(
|
||||
_MacroApplication application,
|
||||
macro.TypeAnnotationDiagnosticTarget macroTarget,
|
||||
) {
|
||||
switch (macroTarget.typeAnnotation) {
|
||||
case NamedTypeAnnotation typeAnnotation:
|
||||
return TypeAnnotationMacroDiagnosticTarget(
|
||||
location: typeAnnotation.location,
|
||||
);
|
||||
}
|
||||
|
||||
// We don't know anything better.
|
||||
return ApplicationMacroDiagnosticTarget(
|
||||
annotationIndex: application.annotationIndex,
|
||||
);
|
||||
}
|
||||
|
||||
static macro.Arguments _buildArguments({
|
||||
required int annotationIndex,
|
||||
required ConstructorElement constructor,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import 'package:_fe_analyzer_shared/src/macros/api.dart' as macro;
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/summary2/macro_type_location.dart';
|
||||
|
||||
/// Base for all macro related diagnostics.
|
||||
sealed class AnalyzerMacroDiagnostic {}
|
||||
|
@ -100,3 +101,11 @@ final class MacroDiagnosticMessage {
|
|||
}
|
||||
|
||||
sealed class MacroDiagnosticTarget {}
|
||||
|
||||
final class TypeAnnotationMacroDiagnosticTarget extends MacroDiagnosticTarget {
|
||||
final TypeAnnotationLocation location;
|
||||
|
||||
TypeAnnotationMacroDiagnosticTarget({
|
||||
required this.location,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import 'package:analyzer/src/dart/ast/ast.dart' as ast;
|
|||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/generated/utilities_dart.dart';
|
||||
import 'package:analyzer/src/summary2/macro_type_location.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/collection.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/element.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
@ -1040,13 +1041,18 @@ class DeclarationBuilderFromNode {
|
|||
current = nextNode;
|
||||
}
|
||||
|
||||
var classTypeLocation = ElementTypeLocation(element);
|
||||
|
||||
return ClassDeclarationImpl._(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
identifier: _declaredIdentifier(node.name, element),
|
||||
library: library(element),
|
||||
metadata: _buildMetadata(element),
|
||||
typeParameters: _typeParameters(node.typeParameters),
|
||||
interfaces: _namedTypes(interfaceNodes),
|
||||
interfaces: _namedTypes(
|
||||
interfaceNodes,
|
||||
ImplementsClauseTypeLocation(classTypeLocation),
|
||||
),
|
||||
hasAbstract: node.abstractKeyword != null,
|
||||
hasBase: node.baseKeyword != null,
|
||||
hasExternal: false,
|
||||
|
@ -1054,8 +1060,16 @@ class DeclarationBuilderFromNode {
|
|||
hasInterface: node.interfaceKeyword != null,
|
||||
hasMixin: node.mixinKeyword != null,
|
||||
hasSealed: node.sealedKeyword != null,
|
||||
mixins: _namedTypes(mixinNodes),
|
||||
superclass: node.extendsClause?.superclass.mapOrNull(_namedType),
|
||||
mixins: _namedTypes(
|
||||
mixinNodes,
|
||||
WithClauseTypeLocation(classTypeLocation),
|
||||
),
|
||||
superclass: node.extendsClause?.superclass.mapOrNull((type) {
|
||||
return _namedType(
|
||||
type,
|
||||
ExtendsClauseTypeLocation(classTypeLocation),
|
||||
);
|
||||
}),
|
||||
element: element,
|
||||
);
|
||||
}
|
||||
|
@ -1080,13 +1094,18 @@ class DeclarationBuilderFromNode {
|
|||
current = nextNode;
|
||||
}
|
||||
|
||||
var classTypeLocation = ElementTypeLocation(element);
|
||||
|
||||
return ClassDeclarationImpl._(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
identifier: _declaredIdentifier(node.name, element),
|
||||
library: library(element),
|
||||
metadata: _buildMetadata(element),
|
||||
typeParameters: _typeParameters(node.typeParameters),
|
||||
interfaces: _namedTypes(interfaceNodes),
|
||||
interfaces: _namedTypes(
|
||||
interfaceNodes,
|
||||
ImplementsClauseTypeLocation(classTypeLocation),
|
||||
),
|
||||
hasAbstract: node.abstractKeyword != null,
|
||||
hasBase: node.baseKeyword != null,
|
||||
hasExternal: false,
|
||||
|
@ -1094,8 +1113,16 @@ class DeclarationBuilderFromNode {
|
|||
hasInterface: node.interfaceKeyword != null,
|
||||
hasMixin: node.mixinKeyword != null,
|
||||
hasSealed: node.sealedKeyword != null,
|
||||
mixins: _namedTypes(mixinNodes),
|
||||
superclass: node.superclass.mapOrNull(_namedType),
|
||||
mixins: _namedTypes(
|
||||
mixinNodes,
|
||||
WithClauseTypeLocation(classTypeLocation),
|
||||
),
|
||||
superclass: node.superclass.mapOrNull((type) {
|
||||
return _namedType(
|
||||
type,
|
||||
ExtendsClauseTypeLocation(classTypeLocation),
|
||||
);
|
||||
}),
|
||||
element: element,
|
||||
);
|
||||
}
|
||||
|
@ -1106,6 +1133,9 @@ class DeclarationBuilderFromNode {
|
|||
final definingType = _definingType(node);
|
||||
final element = node.declaredElement!;
|
||||
|
||||
var (namedParameters, positionalParameters) =
|
||||
_executableFormalParameters(element, node.parameters);
|
||||
|
||||
return ConstructorDeclarationImpl._(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
definingType: definingType,
|
||||
|
@ -1116,8 +1146,8 @@ class DeclarationBuilderFromNode {
|
|||
hasBody: node.body is! ast.EmptyFunctionBody,
|
||||
hasExternal: node.externalKeyword != null,
|
||||
isFactory: node.factoryKeyword != null,
|
||||
namedParameters: _namedFormalParameters(node.parameters),
|
||||
positionalParameters: _positionalFormalParameters(node.parameters),
|
||||
namedParameters: namedParameters,
|
||||
positionalParameters: positionalParameters,
|
||||
returnType: macro.NamedTypeAnnotationImpl(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
identifier: definingType,
|
||||
|
@ -1177,14 +1207,22 @@ class DeclarationBuilderFromNode {
|
|||
current = nextNode;
|
||||
}
|
||||
|
||||
var enumTypeLocation = ElementTypeLocation(element);
|
||||
|
||||
return EnumDeclarationImpl._(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
identifier: _declaredIdentifier(node.name, element),
|
||||
library: library(element),
|
||||
metadata: _buildMetadata(element),
|
||||
typeParameters: _typeParameters(node.typeParameters),
|
||||
interfaces: _namedTypes(interfaceNodes),
|
||||
mixins: _namedTypes(mixinNodes),
|
||||
interfaces: _namedTypes(
|
||||
interfaceNodes,
|
||||
ImplementsClauseTypeLocation(enumTypeLocation),
|
||||
),
|
||||
mixins: _namedTypes(
|
||||
mixinNodes,
|
||||
WithClauseTypeLocation(enumTypeLocation),
|
||||
),
|
||||
element: element,
|
||||
);
|
||||
}
|
||||
|
@ -1200,7 +1238,10 @@ class DeclarationBuilderFromNode {
|
|||
library: library(element),
|
||||
metadata: _buildMetadata(element),
|
||||
typeParameters: _typeParameters(node.typeParameters),
|
||||
onType: _typeAnnotation(node.extendedType),
|
||||
onType: _typeAnnotation(
|
||||
node.extendedType,
|
||||
ExtensionElementOnTypeLocation(element),
|
||||
),
|
||||
element: element,
|
||||
);
|
||||
}
|
||||
|
@ -1216,7 +1257,10 @@ class DeclarationBuilderFromNode {
|
|||
library: library(element),
|
||||
metadata: _buildMetadata(element),
|
||||
typeParameters: _typeParameters(node.typeParameters),
|
||||
representationType: _typeAnnotation(node.representation.fieldType),
|
||||
representationType: _typeAnnotation(
|
||||
node.representation.fieldType,
|
||||
ExtensionTypeElementRepresentationTypeLocation(element),
|
||||
),
|
||||
element: element,
|
||||
);
|
||||
}
|
||||
|
@ -1227,6 +1271,9 @@ class DeclarationBuilderFromNode {
|
|||
final element = node.declaredElement!;
|
||||
final function = node.functionExpression;
|
||||
|
||||
var (namedParameters, positionalParameters) =
|
||||
_executableFormalParameters(element, function.parameters);
|
||||
|
||||
return FunctionDeclarationImpl._(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
element: element,
|
||||
|
@ -1238,8 +1285,8 @@ class DeclarationBuilderFromNode {
|
|||
isGetter: node.isGetter,
|
||||
isOperator: false,
|
||||
isSetter: node.isSetter,
|
||||
namedParameters: _namedFormalParameters(function.parameters),
|
||||
positionalParameters: _positionalFormalParameters(function.parameters),
|
||||
namedParameters: namedParameters,
|
||||
positionalParameters: positionalParameters,
|
||||
returnType: _typeAnnotationFunctionReturnType(node),
|
||||
typeParameters: _typeParameters(function.typeParameters),
|
||||
);
|
||||
|
@ -1303,6 +1350,8 @@ class DeclarationBuilderFromNode {
|
|||
current = nextNode;
|
||||
}
|
||||
|
||||
var mixinTypeLocation = ElementTypeLocation(element);
|
||||
|
||||
return MixinDeclarationImpl._(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
identifier: _declaredIdentifier(node.name, element),
|
||||
|
@ -1310,8 +1359,14 @@ class DeclarationBuilderFromNode {
|
|||
metadata: _buildMetadata(element),
|
||||
typeParameters: _typeParameters(node.typeParameters),
|
||||
hasBase: node.baseKeyword != null,
|
||||
interfaces: _namedTypes(interfaceNodes),
|
||||
superclassConstraints: _namedTypes(onNodes),
|
||||
interfaces: _namedTypes(
|
||||
interfaceNodes,
|
||||
ImplementsClauseTypeLocation(mixinTypeLocation),
|
||||
),
|
||||
superclassConstraints: _namedTypes(
|
||||
onNodes,
|
||||
OnClauseTypeLocation(mixinTypeLocation),
|
||||
),
|
||||
element: element,
|
||||
);
|
||||
}
|
||||
|
@ -1329,7 +1384,11 @@ class DeclarationBuilderFromNode {
|
|||
hasExternal: false,
|
||||
hasFinal: element.isFinal,
|
||||
hasLate: element.isLate,
|
||||
type: _typeAnnotationVariable(node.fieldType, element),
|
||||
type: _typeAnnotationVariable(
|
||||
node.fieldType,
|
||||
element,
|
||||
ElementTypeLocation(element),
|
||||
),
|
||||
definingType: _definingType(node),
|
||||
isStatic: element.isStatic,
|
||||
element: element,
|
||||
|
@ -1381,7 +1440,11 @@ class DeclarationBuilderFromNode {
|
|||
hasExternal: variablesDeclaration.externalKeyword != null,
|
||||
hasFinal: element.isFinal,
|
||||
hasLate: element.isLate,
|
||||
type: _typeAnnotationVariable(variableList.type, element),
|
||||
type: _typeAnnotationVariable(
|
||||
variableList.type,
|
||||
element,
|
||||
ElementTypeLocation(element),
|
||||
),
|
||||
definingType: _definingType(variablesDeclaration),
|
||||
isStatic: element.isStatic,
|
||||
element: element,
|
||||
|
@ -1396,7 +1459,11 @@ class DeclarationBuilderFromNode {
|
|||
hasExternal: element.isExternal,
|
||||
hasFinal: element.isFinal,
|
||||
hasLate: element.isLate,
|
||||
type: _typeAnnotationVariable(variableList.type, element),
|
||||
type: _typeAnnotationVariable(
|
||||
variableList.type,
|
||||
element,
|
||||
ElementTypeLocation(element),
|
||||
),
|
||||
element: element,
|
||||
);
|
||||
default:
|
||||
|
@ -1471,7 +1538,34 @@ class DeclarationBuilderFromNode {
|
|||
);
|
||||
}
|
||||
|
||||
macro.ParameterDeclarationImpl _formalParameter(ast.FormalParameter node) {
|
||||
(List<macro.ParameterDeclarationImpl>, List<macro.ParameterDeclarationImpl>)
|
||||
_executableFormalParameters(
|
||||
ExecutableElement element,
|
||||
ast.FormalParameterList? node,
|
||||
) {
|
||||
var named = <macro.ParameterDeclarationImpl>[];
|
||||
var positional = <macro.ParameterDeclarationImpl>[];
|
||||
if (node != null) {
|
||||
var elementLocation = ElementTypeLocation(element);
|
||||
for (var (index, node) in node.parameters.indexed) {
|
||||
var formalParameter = _formalParameter(
|
||||
node,
|
||||
FormalParameterTypeLocation(elementLocation, index),
|
||||
);
|
||||
if (node.isNamed) {
|
||||
named.add(formalParameter);
|
||||
} else {
|
||||
positional.add(formalParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (named, positional);
|
||||
}
|
||||
|
||||
macro.ParameterDeclarationImpl _formalParameter(
|
||||
ast.FormalParameter node,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
if (node is ast.DefaultFormalParameter) {
|
||||
node = node.parameter;
|
||||
}
|
||||
|
@ -1481,9 +1575,9 @@ class DeclarationBuilderFromNode {
|
|||
final macro.TypeAnnotationImpl typeAnnotation;
|
||||
switch (node) {
|
||||
case ast.FieldFormalParameter():
|
||||
typeAnnotation = _typeAnnotationVariable(node.type, element);
|
||||
typeAnnotation = _typeAnnotationVariable(node.type, element, location);
|
||||
case ast.SimpleFormalParameter():
|
||||
typeAnnotation = _typeAnnotationVariable(node.type, element);
|
||||
typeAnnotation = _typeAnnotationVariable(node.type, element, location);
|
||||
default:
|
||||
throw UnimplementedError('(${node.runtimeType}) $node');
|
||||
}
|
||||
|
@ -1501,6 +1595,7 @@ class DeclarationBuilderFromNode {
|
|||
|
||||
macro.FunctionTypeParameterImpl _functionTypeFormalParameter(
|
||||
ast.FormalParameter node,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
if (node is ast.DefaultFormalParameter) {
|
||||
node = node.parameter;
|
||||
|
@ -1510,7 +1605,7 @@ class DeclarationBuilderFromNode {
|
|||
|
||||
final macro.TypeAnnotationImpl typeAnnotation;
|
||||
if (node is ast.SimpleFormalParameter) {
|
||||
typeAnnotation = _typeAnnotationOrDynamic(node.type);
|
||||
typeAnnotation = _typeAnnotationOrDynamic(node.type, location);
|
||||
} else {
|
||||
throw UnimplementedError('(${node.runtimeType}) $node');
|
||||
}
|
||||
|
@ -1531,6 +1626,9 @@ class DeclarationBuilderFromNode {
|
|||
final definingType = _definingType(node);
|
||||
final element = node.declaredElement!;
|
||||
|
||||
var (namedParameters, positionalParameters) =
|
||||
_executableFormalParameters(element, node.parameters);
|
||||
|
||||
return MethodDeclarationImpl._(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
definingType: definingType,
|
||||
|
@ -1544,32 +1642,26 @@ class DeclarationBuilderFromNode {
|
|||
isOperator: node.isOperator,
|
||||
isSetter: node.isSetter,
|
||||
isStatic: node.isStatic,
|
||||
namedParameters: _namedFormalParameters(node.parameters),
|
||||
positionalParameters: _positionalFormalParameters(node.parameters),
|
||||
namedParameters: namedParameters,
|
||||
positionalParameters: positionalParameters,
|
||||
returnType: _typeAnnotationMethodReturnType(node),
|
||||
typeParameters: _typeParameters(node.typeParameters),
|
||||
);
|
||||
}
|
||||
|
||||
List<macro.ParameterDeclarationImpl> _namedFormalParameters(
|
||||
ast.FormalParameterList? node,
|
||||
macro.NamedTypeAnnotationImpl _namedType(
|
||||
ast.NamedType node,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
if (node != null) {
|
||||
return node.parameters
|
||||
.where((e) => e.isNamed)
|
||||
.map(_formalParameter)
|
||||
.toList();
|
||||
} else {
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
macro.NamedTypeAnnotationImpl _namedType(ast.NamedType node) {
|
||||
return macro.NamedTypeAnnotationImpl(
|
||||
return NamedTypeAnnotation(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
identifier: _namedTypeIdentifier(node),
|
||||
isNullable: node.question != null,
|
||||
typeArguments: _typeAnnotations(node.typeArguments?.arguments),
|
||||
typeArguments: _typeAnnotations(
|
||||
node.typeArguments?.arguments,
|
||||
location,
|
||||
),
|
||||
location: location,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1587,47 +1679,55 @@ class DeclarationBuilderFromNode {
|
|||
|
||||
List<macro.NamedTypeAnnotationImpl> _namedTypes(
|
||||
List<ast.NamedType>? elements,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
if (elements != null) {
|
||||
return elements.map(_namedType).toList();
|
||||
return elements.indexed.map((pair) {
|
||||
return _namedType(
|
||||
pair.$2,
|
||||
ListIndexTypeLocation(location, pair.$1),
|
||||
);
|
||||
}).toList();
|
||||
} else {
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
List<macro.ParameterDeclarationImpl> _positionalFormalParameters(
|
||||
ast.FormalParameterList? node,
|
||||
macro.TypeAnnotationImpl _typeAnnotation(
|
||||
ast.TypeAnnotation node,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
if (node != null) {
|
||||
return node.parameters
|
||||
.where((e) => e.isPositional)
|
||||
.map(_formalParameter)
|
||||
.toList();
|
||||
} else {
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
macro.TypeAnnotationImpl _typeAnnotation(ast.TypeAnnotation node) {
|
||||
node as ast.TypeAnnotationImpl;
|
||||
switch (node) {
|
||||
case ast.GenericFunctionTypeImpl():
|
||||
var namedParameters = <macro.FunctionTypeParameterImpl>[];
|
||||
var positionalParameters = <macro.FunctionTypeParameterImpl>[];
|
||||
var formalParameters = node.parameters.parameters;
|
||||
for (var (index, node) in formalParameters.indexed) {
|
||||
var formalParameter = _functionTypeFormalParameter(
|
||||
node,
|
||||
FormalParameterTypeLocation(location, index),
|
||||
);
|
||||
if (node.isNamed) {
|
||||
namedParameters.add(formalParameter);
|
||||
} else {
|
||||
positionalParameters.add(formalParameter);
|
||||
}
|
||||
}
|
||||
|
||||
return macro.FunctionTypeAnnotationImpl(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
isNullable: node.question != null,
|
||||
namedParameters: node.parameters.parameters
|
||||
.where((e) => e.isNamed)
|
||||
.map(_functionTypeFormalParameter)
|
||||
.toList(),
|
||||
positionalParameters: node.parameters.parameters
|
||||
.where((e) => e.isPositional)
|
||||
.map(_functionTypeFormalParameter)
|
||||
.toList(),
|
||||
returnType: _typeAnnotationOrDynamic(node.returnType),
|
||||
namedParameters: namedParameters,
|
||||
positionalParameters: positionalParameters,
|
||||
returnType: _typeAnnotationOrDynamic(
|
||||
node.returnType,
|
||||
ReturnTypeLocation(location),
|
||||
),
|
||||
typeParameters: _typeParameters(node.typeParameters),
|
||||
);
|
||||
case ast.NamedTypeImpl():
|
||||
return _namedType(node);
|
||||
return _namedType(node, location);
|
||||
case ast.RecordTypeAnnotationImpl():
|
||||
return _typeAnnotationRecord(node);
|
||||
}
|
||||
|
@ -1636,30 +1736,43 @@ class DeclarationBuilderFromNode {
|
|||
macro.TypeAnnotationImpl _typeAnnotationFunctionReturnType(
|
||||
ast.FunctionDeclaration node,
|
||||
) {
|
||||
final element = node.declaredElement!;
|
||||
final returnType = node.returnType;
|
||||
if (returnType == null) {
|
||||
final element = node.declaredElement!;
|
||||
return _OmittedTypeAnnotationFunctionReturnType(element);
|
||||
}
|
||||
return _typeAnnotation(returnType);
|
||||
return _typeAnnotation(
|
||||
returnType,
|
||||
ReturnTypeLocation(
|
||||
ElementTypeLocation(element),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
macro.TypeAnnotationImpl _typeAnnotationMethodReturnType(
|
||||
ast.MethodDeclaration node,
|
||||
) {
|
||||
final element = node.declaredElement!;
|
||||
final returnType = node.returnType;
|
||||
if (returnType == null) {
|
||||
final element = node.declaredElement!;
|
||||
return _OmittedTypeAnnotationFunctionReturnType(element);
|
||||
}
|
||||
return _typeAnnotation(returnType);
|
||||
return _typeAnnotation(
|
||||
returnType,
|
||||
ReturnTypeLocation(
|
||||
ElementTypeLocation(element),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
macro.TypeAnnotationImpl _typeAnnotationOrDynamic(ast.TypeAnnotation? node) {
|
||||
macro.TypeAnnotationImpl _typeAnnotationOrDynamic(
|
||||
ast.TypeAnnotation? node,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
if (node == null) {
|
||||
return _OmittedTypeAnnotationDynamic();
|
||||
}
|
||||
return _typeAnnotation(node);
|
||||
return _typeAnnotation(node, location);
|
||||
}
|
||||
|
||||
macro.RecordTypeAnnotationImpl _typeAnnotationRecord(
|
||||
|
@ -1671,6 +1784,7 @@ class DeclarationBuilderFromNode {
|
|||
|
||||
macro.RecordFieldDeclarationImpl buildField(
|
||||
ast.RecordTypeAnnotationField field,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
final name = field.name?.lexeme ?? '';
|
||||
return macro.RecordFieldDeclarationImpl(
|
||||
|
@ -1683,24 +1797,40 @@ class DeclarationBuilderFromNode {
|
|||
library: macroLibrary,
|
||||
metadata: const [],
|
||||
name: name,
|
||||
type: _typeAnnotationOrDynamic(field.type),
|
||||
type: _typeAnnotationOrDynamic(field.type, location),
|
||||
);
|
||||
}
|
||||
|
||||
return macro.RecordTypeAnnotationImpl(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
positionalFields: node.positionalFields.map(buildField).toList(),
|
||||
namedFields: node.namedFields?.fields.map(buildField).toList() ?? [],
|
||||
positionalFields: node.positionalFields.indexed.map((pair) {
|
||||
return buildField(
|
||||
pair.$2,
|
||||
RecordPositionalFieldTypeLocation(pair.$1),
|
||||
);
|
||||
}).toList(),
|
||||
namedFields: node.namedFields?.fields.indexed.map((pair) {
|
||||
return buildField(
|
||||
pair.$2,
|
||||
RecordNamedFieldTypeLocation(pair.$1),
|
||||
);
|
||||
}).toList() ??
|
||||
[],
|
||||
isNullable: node.question != null,
|
||||
);
|
||||
}
|
||||
|
||||
List<macro.TypeAnnotationImpl> _typeAnnotations(
|
||||
List<ast.TypeAnnotation>? elements,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
if (elements != null) {
|
||||
return List.generate(
|
||||
elements.length, (i) => _typeAnnotation(elements[i]));
|
||||
return List.generate(elements.length, (index) {
|
||||
return _typeAnnotation(
|
||||
elements[index],
|
||||
ListIndexTypeLocation(location, index),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return const [];
|
||||
}
|
||||
|
@ -1709,11 +1839,15 @@ class DeclarationBuilderFromNode {
|
|||
macro.TypeAnnotationImpl _typeAnnotationVariable(
|
||||
ast.TypeAnnotation? type,
|
||||
VariableElement element,
|
||||
TypeAnnotationLocation location,
|
||||
) {
|
||||
if (type == null) {
|
||||
return _OmittedTypeAnnotationVariable(element);
|
||||
}
|
||||
return _typeAnnotation(type);
|
||||
return _typeAnnotation(
|
||||
type,
|
||||
VariableTypeLocation(location),
|
||||
);
|
||||
}
|
||||
|
||||
macro.TypeParameterDeclarationImpl _typeParameter(
|
||||
|
@ -1725,7 +1859,12 @@ class DeclarationBuilderFromNode {
|
|||
identifier: _declaredIdentifier(node.name, element),
|
||||
library: library(element),
|
||||
metadata: _buildMetadata(element),
|
||||
bound: node.bound.mapOrNull(_typeAnnotation),
|
||||
bound: node.bound.mapOrNull((type) {
|
||||
return _typeAnnotation(
|
||||
type,
|
||||
TypeParameterBoundLocation(),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1955,6 +2094,18 @@ class MixinDeclarationImpl extends macro.MixinDeclarationImpl
|
|||
});
|
||||
}
|
||||
|
||||
class NamedTypeAnnotation extends macro.NamedTypeAnnotationImpl {
|
||||
final TypeAnnotationLocation location;
|
||||
|
||||
NamedTypeAnnotation({
|
||||
required super.id,
|
||||
required super.isNullable,
|
||||
required super.identifier,
|
||||
required super.typeArguments,
|
||||
required this.location,
|
||||
});
|
||||
}
|
||||
|
||||
class VariableDeclarationImpl extends macro.VariableDeclarationImpl
|
||||
implements HasElement {
|
||||
@override
|
||||
|
|
90
pkg/analyzer/lib/src/summary2/macro_type_location.dart
Normal file
90
pkg/analyzer/lib/src/summary2/macro_type_location.dart
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2024, 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.
|
||||
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
|
||||
final class ElementTypeLocation extends TypeAnnotationLocation {
|
||||
final Element element;
|
||||
|
||||
ElementTypeLocation(this.element);
|
||||
}
|
||||
|
||||
final class ExtendsClauseTypeLocation extends TypeAnnotationLocation {
|
||||
final TypeAnnotationLocation parent;
|
||||
|
||||
ExtendsClauseTypeLocation(this.parent);
|
||||
}
|
||||
|
||||
final class ExtensionElementOnTypeLocation extends TypeAnnotationLocation {
|
||||
final ExtensionElement element;
|
||||
|
||||
ExtensionElementOnTypeLocation(this.element);
|
||||
}
|
||||
|
||||
final class ExtensionTypeElementRepresentationTypeLocation
|
||||
extends TypeAnnotationLocation {
|
||||
final ExtensionTypeElement element;
|
||||
|
||||
ExtensionTypeElementRepresentationTypeLocation(this.element);
|
||||
}
|
||||
|
||||
final class FormalParameterTypeLocation extends TypeAnnotationLocation {
|
||||
final TypeAnnotationLocation parent;
|
||||
final int index;
|
||||
|
||||
FormalParameterTypeLocation(this.parent, this.index);
|
||||
}
|
||||
|
||||
final class ImplementsClauseTypeLocation extends TypeAnnotationLocation {
|
||||
final TypeAnnotationLocation parent;
|
||||
|
||||
ImplementsClauseTypeLocation(this.parent);
|
||||
}
|
||||
|
||||
final class ListIndexTypeLocation extends TypeAnnotationLocation {
|
||||
final TypeAnnotationLocation parent;
|
||||
final int index;
|
||||
|
||||
ListIndexTypeLocation(this.parent, this.index);
|
||||
}
|
||||
|
||||
final class OnClauseTypeLocation extends TypeAnnotationLocation {
|
||||
final TypeAnnotationLocation parent;
|
||||
|
||||
OnClauseTypeLocation(this.parent);
|
||||
}
|
||||
|
||||
final class RecordNamedFieldTypeLocation extends TypeAnnotationLocation {
|
||||
final int index;
|
||||
|
||||
RecordNamedFieldTypeLocation(this.index);
|
||||
}
|
||||
|
||||
final class RecordPositionalFieldTypeLocation extends TypeAnnotationLocation {
|
||||
final int index;
|
||||
|
||||
RecordPositionalFieldTypeLocation(this.index);
|
||||
}
|
||||
|
||||
final class ReturnTypeLocation extends TypeAnnotationLocation {
|
||||
final TypeAnnotationLocation parent;
|
||||
|
||||
ReturnTypeLocation(this.parent);
|
||||
}
|
||||
|
||||
sealed class TypeAnnotationLocation {}
|
||||
|
||||
final class TypeParameterBoundLocation extends TypeAnnotationLocation {}
|
||||
|
||||
final class VariableTypeLocation extends TypeAnnotationLocation {
|
||||
final TypeAnnotationLocation parent;
|
||||
|
||||
VariableTypeLocation(this.parent);
|
||||
}
|
||||
|
||||
final class WithClauseTypeLocation extends TypeAnnotationLocation {
|
||||
final TypeAnnotationLocation parent;
|
||||
|
||||
WithClauseTypeLocation(this.parent);
|
||||
}
|
|
@ -388,6 +388,131 @@ class A {
|
|||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_class_extends() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'superclass',
|
||||
])
|
||||
class A extends Object {}
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 88, 6),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_field_type() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
class A {
|
||||
@ReportAtTypeAnnotation([
|
||||
'variableType',
|
||||
])
|
||||
int foo = 0;
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 92, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_function_formalParameter_named() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'namedFormalParameterType 0',
|
||||
])
|
||||
void foo(int a, {String? b, bool? c}) {}
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 105, 7),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_function_formalParameter_positional() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'positionalFormalParameterType 1',
|
||||
])
|
||||
void foo(int a, String b) {}
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 109, 6),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_function_returnType() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'returnType',
|
||||
])
|
||||
int foo() => 0;
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 72, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_functionType_returnType() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'returnType',
|
||||
'returnType',
|
||||
])
|
||||
int Function() foo() => throw 0;
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 88, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_method_formalParameter_positional() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
class A {
|
||||
@ReportAtTypeAnnotation([
|
||||
'positionalFormalParameterType 1',
|
||||
])
|
||||
void foo(int a, String b) {}
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 127, 6),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_method_returnType() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
class A {
|
||||
@ReportAtTypeAnnotation([
|
||||
'returnType',
|
||||
])
|
||||
int foo() => 0;
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 90, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_atTypeAnnotation_namedTypeArgument() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'returnType',
|
||||
'namedTypeArgument 1',
|
||||
])
|
||||
Map<int, String> foo() => throw 0;
|
||||
''', [
|
||||
error(WarningCode.MACRO_WARNING, 106, 6),
|
||||
]);
|
||||
}
|
||||
|
||||
test_diagnostic_report_contextMessages_superClassMethods() async {
|
||||
newFile('$testPackageLibPath/a.dart', r'''
|
||||
class A {
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:analyzer/src/dart/element/element.dart';
|
|||
import 'package:analyzer/src/dart/element/field_name_non_promotability_info.dart';
|
||||
import 'package:analyzer/src/summary2/export.dart';
|
||||
import 'package:analyzer/src/summary2/macro_application_error.dart';
|
||||
import 'package:analyzer/src/summary2/macro_type_location.dart';
|
||||
import 'package:analyzer/src/task/inference_error.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -740,6 +741,40 @@ class _ElementWriter {
|
|||
}
|
||||
|
||||
void _writeMacroDiagnostics(Element e) {
|
||||
void writeTypeAnnotationLocation(TypeAnnotationLocation location) {
|
||||
switch (location) {
|
||||
case ElementTypeLocation():
|
||||
_sink.writelnWithIndent('ElementTypeLocation');
|
||||
_sink.withIndent(() {
|
||||
_elementPrinter.writeNamedElement('element', location.element);
|
||||
});
|
||||
case ExtendsClauseTypeLocation():
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
_sink.writelnWithIndent('ExtendsClauseTypeLocation');
|
||||
case FormalParameterTypeLocation():
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
_sink.writelnWithIndent('FormalParameterTypeLocation');
|
||||
_sink.withIndent(() {
|
||||
_sink.writelnWithIndent('index: ${location.index}');
|
||||
});
|
||||
case ListIndexTypeLocation():
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
_sink.writelnWithIndent('ListIndexTypeLocation');
|
||||
_sink.withIndent(() {
|
||||
_sink.writelnWithIndent('index: ${location.index}');
|
||||
});
|
||||
case ReturnTypeLocation():
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
_sink.writelnWithIndent('ReturnTypeLocation');
|
||||
case VariableTypeLocation():
|
||||
writeTypeAnnotationLocation(location.parent);
|
||||
_sink.writelnWithIndent('VariableTypeLocation');
|
||||
default:
|
||||
// TODO(scheglov): Handle this case.
|
||||
throw UnimplementedError('${location.runtimeType}');
|
||||
}
|
||||
}
|
||||
|
||||
void writeMessage(MacroDiagnosticMessage object) {
|
||||
// Write the message.
|
||||
final validator = configuration.macroDiagnosticMessageValidator;
|
||||
|
@ -776,6 +811,13 @@ class _ElementWriter {
|
|||
_sink.withIndent(() {
|
||||
_elementPrinter.writeNamedElement('element', target.element);
|
||||
});
|
||||
case TypeAnnotationMacroDiagnosticTarget():
|
||||
_sink.writelnWithIndent(
|
||||
'target: TypeAnnotationMacroDiagnosticTarget',
|
||||
);
|
||||
_sink.withIndent(() {
|
||||
writeTypeAnnotationLocation(target.location);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,106 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
|||
}
|
||||
}
|
||||
|
||||
/*macro*/ class ReportAtTypeAnnotation
|
||||
implements
|
||||
ClassDeclarationsMacro,
|
||||
FunctionDeclarationsMacro,
|
||||
FieldDeclarationsMacro,
|
||||
MethodDeclarationsMacro {
|
||||
final List<String> pathList;
|
||||
|
||||
const ReportAtTypeAnnotation(this.pathList);
|
||||
|
||||
@override
|
||||
buildDeclarationsForClass(declaration, builder) {
|
||||
_report(declaration, builder);
|
||||
}
|
||||
|
||||
@override
|
||||
buildDeclarationsForField(declaration, builder) {
|
||||
_report(declaration, builder);
|
||||
}
|
||||
|
||||
@override
|
||||
buildDeclarationsForFunction(declaration, builder) {
|
||||
_report(declaration, builder);
|
||||
}
|
||||
|
||||
@override
|
||||
buildDeclarationsForMethod(declaration, builder) {
|
||||
_report(declaration, builder);
|
||||
}
|
||||
|
||||
TypeAnnotation _getTarget(Declaration declaration) {
|
||||
var current = _nextTarget(declaration, pathList.first);
|
||||
for (var step in pathList.skip(1)) {
|
||||
current = _nextTarget(current, step);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
TypeAnnotation _nextTarget(Object current, String step) {
|
||||
if (current is ClassDeclaration) {
|
||||
if (step == 'superclass') {
|
||||
return current.superclass!;
|
||||
}
|
||||
}
|
||||
|
||||
if (current is FunctionDeclaration) {
|
||||
if (step == 'returnType') {
|
||||
return current.returnType;
|
||||
}
|
||||
if (_verbIndex(step, 'namedFormalParameterType') case var index?) {
|
||||
return current.namedParameters.elementAt(index).type;
|
||||
}
|
||||
if (_verbIndex(step, 'positionalFormalParameterType') case var index?) {
|
||||
return current.positionalParameters.elementAt(index).type;
|
||||
}
|
||||
}
|
||||
|
||||
if (current is FunctionTypeAnnotation) {
|
||||
if (step == 'returnType') {
|
||||
return current.returnType;
|
||||
}
|
||||
}
|
||||
|
||||
if (current is NamedTypeAnnotation) {
|
||||
if (_verbIndex(step, 'namedTypeArgument') case var index?) {
|
||||
return current.typeArguments.elementAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
if (current is VariableDeclaration) {
|
||||
if (step == 'variableType') {
|
||||
return current.type;
|
||||
}
|
||||
}
|
||||
|
||||
throw UnimplementedError('[current: $current][step: $step]');
|
||||
}
|
||||
|
||||
void _report(Declaration declaration, DeclarationBuilder builder) {
|
||||
builder.report(
|
||||
Diagnostic(
|
||||
DiagnosticMessage(
|
||||
'Reported message',
|
||||
target: _getTarget(declaration).asDiagnosticTarget,
|
||||
),
|
||||
Severity.warning,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static int? _verbIndex(String step, String verb) {
|
||||
var prefix = '$verb ';
|
||||
if (step.startsWith(prefix)) {
|
||||
var indexStr = step.substring(prefix.length);
|
||||
return int.parse(indexStr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*macro*/ class ReportErrorAtTargetDeclaration
|
||||
extends ReportAtTargetDeclaration {
|
||||
const ReportErrorAtTargetDeclaration();
|
||||
|
|
|
@ -3755,6 +3755,391 @@ library
|
|||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_class_extends() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'superclass',
|
||||
])
|
||||
class A extends Object {}
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
classes
|
||||
class A @78
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@class::A
|
||||
ExtendsClauseTypeLocation
|
||||
severity: warning
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_field_type() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
class A {
|
||||
@ReportAtTypeAnnotation([
|
||||
'variableType',
|
||||
])
|
||||
final int foo = 0;
|
||||
}
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
classes
|
||||
class A @33
|
||||
fields
|
||||
final foo @102
|
||||
type: int
|
||||
shouldUseTypeForInitializerInference: true
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@class::A::@field::foo
|
||||
VariableTypeLocation
|
||||
severity: warning
|
||||
accessors
|
||||
synthetic get foo @-1
|
||||
returnType: int
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_function_formalParameter_named() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'namedFormalParameterType 0',
|
||||
])
|
||||
void foo(int a, {String? b, bool? c}) {}
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
functions
|
||||
foo @93
|
||||
parameters
|
||||
requiredPositional a @101
|
||||
type: int
|
||||
optionalNamed default b @113
|
||||
type: String?
|
||||
optionalNamed default c @122
|
||||
type: bool?
|
||||
returnType: void
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@function::foo
|
||||
FormalParameterTypeLocation
|
||||
index: 1
|
||||
VariableTypeLocation
|
||||
severity: warning
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_function_formalParameter_positional() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'positionalFormalParameterType 1',
|
||||
])
|
||||
void foo(int a, String b) {}
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
functions
|
||||
foo @98
|
||||
parameters
|
||||
requiredPositional a @106
|
||||
type: int
|
||||
requiredPositional b @116
|
||||
type: String
|
||||
returnType: void
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@function::foo
|
||||
FormalParameterTypeLocation
|
||||
index: 1
|
||||
VariableTypeLocation
|
||||
severity: warning
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_function_returnType() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'returnType',
|
||||
])
|
||||
int foo() => 0;
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
functions
|
||||
foo @76
|
||||
returnType: int
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@function::foo
|
||||
ReturnTypeLocation
|
||||
severity: warning
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_functionType_returnType() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'returnType',
|
||||
'returnType',
|
||||
])
|
||||
int Function() foo() => throw 0;
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
functions
|
||||
foo @103
|
||||
returnType: int Function()
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@function::foo
|
||||
ReturnTypeLocation
|
||||
ReturnTypeLocation
|
||||
severity: warning
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_method_formalParameter_positional() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
class A {
|
||||
@ReportAtTypeAnnotation([
|
||||
'positionalFormalParameterType 1',
|
||||
])
|
||||
void foo(int a, String b) {}
|
||||
}
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
classes
|
||||
class A @33
|
||||
methods
|
||||
foo @116
|
||||
parameters
|
||||
requiredPositional a @124
|
||||
type: int
|
||||
requiredPositional b @134
|
||||
type: String
|
||||
returnType: void
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@class::A::@method::foo
|
||||
FormalParameterTypeLocation
|
||||
index: 1
|
||||
VariableTypeLocation
|
||||
severity: warning
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_method_returnType() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
class A {
|
||||
@ReportAtTypeAnnotation([
|
||||
'returnType',
|
||||
])
|
||||
int foo() => 0;
|
||||
}
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
classes
|
||||
class A @33
|
||||
methods
|
||||
foo @94
|
||||
returnType: int
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@class::A::@method::foo
|
||||
ReturnTypeLocation
|
||||
severity: warning
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_atTypeAnnotation_namedTypeArgument() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
_getMacroCode('diagnostic.dart'),
|
||||
);
|
||||
|
||||
final library = await buildLibrary(r'''
|
||||
import 'diagnostic.dart';
|
||||
|
||||
@ReportAtTypeAnnotation([
|
||||
'returnType',
|
||||
'namedTypeArgument 1',
|
||||
])
|
||||
Map<int, String> foo() {}
|
||||
''');
|
||||
|
||||
configuration
|
||||
..withConstructors = false
|
||||
..withMetadata = false;
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
imports
|
||||
package:test/diagnostic.dart
|
||||
definingUnit
|
||||
functions
|
||||
foo @114
|
||||
returnType: Map<int, String>
|
||||
macroDiagnostics
|
||||
MacroDiagnostic
|
||||
message: MacroDiagnosticMessage
|
||||
message: Reported message
|
||||
target: TypeAnnotationMacroDiagnosticTarget
|
||||
ElementTypeLocation
|
||||
element: self::@function::foo
|
||||
ReturnTypeLocation
|
||||
ListIndexTypeLocation
|
||||
index: 1
|
||||
severity: warning
|
||||
''');
|
||||
}
|
||||
|
||||
test_macroDiagnostics_report_contextMessages() async {
|
||||
newFile(
|
||||
'$testPackageLibPath/diagnostic.dart',
|
||||
|
|
Loading…
Reference in a new issue