blob: 5a8dd11c19fa6d9a34f052b5cf7209dfcaa6dc47 [file] [log] [blame]
// Copyright (c) 2014, 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.
library docgen.models.annotation;
import '../exports/source_mirrors.dart';
import '../exports/dart2js_mirrors.dart' show ResolvedNode;
import '../library_helpers.dart';
import 'library.dart';
import 'mirror_based.dart';
import 'dart:mirrors';
import 'package:compiler/src/tree/tree.dart';
/// Holds the name of the annotation, and its parameters.
class Annotation extends MirrorBased<ClassMirror> {
/// The class of this annotation.
DeclarationMirror mirror;
Send node;
final Library owningLibrary;
List<String> parameters;
Annotation(ResolvedNode resolvedNode, this.owningLibrary) {
parameters = [];
getMirrorForResolvedNode(resolvedNode, (m, n) { mirror = m; node = n;},
(String param) => parameters.add(param));
}
String getMirrorForResolvedNode(ResolvedNode node, callbackFunc,
paramCallbackFunc) {
ResolvedNodeMirrorFinder finder = new ResolvedNodeMirrorFinder(node,
callbackFunc, paramCallbackFunc);
finder.unparse(node.node);
return finder.result;
}
Map toMap() => {
'name': owningLibrary.packagePrefix +
getDocgenObject(mirror, owningLibrary).docName,
'parameters': parameters
};
}
class ResolvedNodeMirrorFinder extends Unparser {
final ResolvedNode resolvedNode;
final Function annotationMirrorCallback;
final Function parameterValueCallback;
int recursionLevel;
ResolvedNodeMirrorFinder(this.resolvedNode, this.annotationMirrorCallback,
this.parameterValueCallback) : recursionLevel = 0;
visitSend(Send node) {
if (recursionLevel == 0) {
var m = resolvedNode.resolvedMirror(node.selector);
annotationMirrorCallback(m, node);
} else {
Operator op = node.selector.asOperator();
String opString = op != null ? op.source : null;
bool spacesNeeded =
identical(opString, 'is') || identical(opString, 'as');
if (node.isPrefix) visit(node.selector);
unparseSendReceiver(node, spacesNeeded: spacesNeeded);
if (!node.isPrefix && !node.isIndex) visit(node.selector);
if (spacesNeeded) sb.write(' ');
// Also add a space for sequences like x + +1 and y - -y.
// TODO(ahe): remove case for '+' when we drop the support for it.
if (node.argumentsNode != null && (identical(opString, '-')
|| identical(opString, '+'))) {
var beginToken = node.argumentsNode.getBeginToken();
if (beginToken != null &&
identical(beginToken.stringValue, opString)) {
sb.write(' ');
}
}
}
recursionLevel++;
visit(node.argumentsNode);
recursionLevel--;
}
unparseNodeListFrom(NodeList node, var from, {bool spaces: true}) {
if (from.isEmpty) return;
visit(from.head);
for (var link = from.tail; !link.isEmpty; link = link.tail) {
if (recursionLevel >= 2) {
parameterValueCallback(sb.toString());
sb.clear();
}
visit(link.head);
}
if (recursionLevel >= 2) {
parameterValueCallback(sb.toString());
sb.clear();
}
}
visitNodeList(NodeList node) {
addToken(node.beginToken);
if (recursionLevel == 1) sb.clear();
if (node.nodes != null) {
recursionLevel++;
unparseNodeListFrom(node, node.nodes);
recursionLevel--;
}
if (node.endToken != null) write(node.endToken.value);
}
}