Code with Finding: |
class JsMessageVisitor {
/**
* Initializes a message builder from a CALL node.
* <p>
* The tree should look something like:
*
* <pre>
* call
* |-- getprop
* | |-- name 'goog'
* | +-- string 'getMsg'
* |
* |-- string 'Hi {$userName}! Welcome to {$product}.'
* +-- objlit
* |-- string 'userName'
* |-- name 'someUserName'
* |-- string 'product'
* +-- call
* +-- name 'getProductName'
* </pre>
*
* @param builder the message builder
* @param node the call node from where we extract the message
* @throws MalformedException if the parsed message is invalid
*/
private void extractFromCallNode(Builder builder,
Node node) throws MalformedException {
// Check the function being called
if (node.getType() != Token.CALL) {
throw new MalformedException(
"Message must be initialized using " + MSG_FUNCTION_NAME +
" function.", node);
}
Node fnNameNode = node.getFirstChild();
if (!MSG_FUNCTION_NAME.equals(fnNameNode.getQualifiedName())) {
throw new MalformedException(
"Message initialized using unrecognized function. " +
"Please use " + MSG_FUNCTION_NAME + "() instead.", fnNameNode);
}
// Get the message string
Node stringLiteralNode = fnNameNode.getNext();
if (stringLiteralNode == null) {
throw new MalformedException("Message string literal expected",
stringLiteralNode);
}
// Parse the message string and append parts to the builder
parseMessageTextNode(builder, stringLiteralNode);
Node objLitNode = stringLiteralNode.getNext();
Set<String> phNames = Sets.newHashSet();
if (objLitNode != null) {
// Register the placeholder names
if (objLitNode.getType() != Token.OBJECTLIT) {
throw new MalformedException("OBJLIT node expected", objLitNode);
}
for (Node aNode = objLitNode.getFirstChild(); aNode != null;
aNode = aNode.getNext()) {
if (aNode.getType() != Token.STRING) {
throw new MalformedException("STRING node expected as OBJLIT key",
aNode);
}
String phName = aNode.getString();
if (!isLowerCamelCaseWithNumericSuffixes(phName)) {
throw new MalformedException(
"Placeholder name not in lowerCamelCase: " + phName, aNode);
}
if (phNames.contains(phName)) {
throw new MalformedException("Duplicate placeholder name: "
+ phName, aNode);
}
phNames.add(phName);
}
}
// Check that all placeholders from the message text have appropriate objlit
// values
Set<String> usedPlaceholders = builder.getPlaceholders();
for (String phName : usedPlaceholders) {
if(!phNames.contains(phName)) {
throw new MalformedException(
"Unrecognized message placeholder referenced: " + phName,
objLitNode);
}
}
// Check that objLiteral have only names that are present in the
// message text
for (String phName : phNames) {
if(!usedPlaceholders.contains(phName)) {
throw new MalformedException(
"Unused message placeholder: " + phName,
objLitNode);
}
}
}
}
|