/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.icu4j.srcgen; import static com.google.currysrc.api.process.ast.PackageMatcher.getPackageName; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.google.currysrc.api.process.Context; import com.google.currysrc.api.process.Processor; import java.util.List; import java.util.Set; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ImportDeclaration; import org.eclipse.jdt.core.dom.MarkerAnnotation; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.text.edits.TextEditGroup; /** * A {@link Processor} which applies annotations test classes to indicate how they ought to be * sharded. It may also apply annotations to non-test classes in the test package, which will be * ignored (this avoids reproducing the logic to identify test classes). */ class ShardingAnnotator implements Processor { /** * The package in which the annotations to apply live. */ private static final String ANNOTATION_PACKAGE = "android.icu.testsharding"; /** * The simple name of the annotation to apply for test classes not listed in {@link * #CLASS_NAME_TO_ANNOTATION_NAME}. */ private static final String DEFAULT_ANNOTATION_NAME = "MainTestShard"; /** * A map from the fully-qualified names of test classes which need specific annotations to the * simple names of those annotations. */ private static final ImmutableMap CLASS_NAME_TO_ANNOTATION_NAME = // Keys are in alphabetical order. // All annotations must be included in cts/tests/tests/icu/AndroidTest.xml. ImmutableMap.of( "android.icu.dev.test.format.NumberRegressionTests", "HiMemTestShard", "android.icu.dev.test.format.TimeUnitTest", "HiMemTestShard" ); @Override public void process(Context context, CompilationUnit cu) { List types = cu.types(); ASTRewrite rewrite = context.rewrite(); Set imports = Sets.newHashSet(); for (Object type : types) { if (type instanceof TypeDeclaration) { TypeDeclaration declaration = (TypeDeclaration) type; if (needsAnnotation(declaration)) { annotateTestType(cu, rewrite, declaration, imports); } } } } private boolean needsAnnotation(TypeDeclaration declaration) { int modifiers = declaration.getModifiers(); return !declaration.isInterface() && !Modifier.isAbstract(modifiers) && Modifier.isPublic(modifiers); } private void annotateTestType( CompilationUnit cu, ASTRewrite rewrite, TypeDeclaration type, Set imports) { AST ast = cu.getAST(); String className = getPackageName(type) + '.' + type.getName().getIdentifier(); String annotationName = getAnnotationName(className); if (!imports.contains(annotationName)) { appendImport(cu, rewrite, annotationName); imports.add(annotationName); } MarkerAnnotation annotation = ast.newMarkerAnnotation(); annotation.setTypeName(ast.newSimpleName(annotationName)); TextEditGroup editGroup = null; rewrite.getListRewrite(type, type.getModifiersProperty()) .insertFirst(annotation, editGroup); } private String getAnnotationName(String className) { if (CLASS_NAME_TO_ANNOTATION_NAME.containsKey(className)) { return CLASS_NAME_TO_ANNOTATION_NAME.get(className); } else { return DEFAULT_ANNOTATION_NAME; } } private void appendImport(CompilationUnit cu, ASTRewrite rewrite, String annotationName) { AST ast = cu.getAST(); ImportDeclaration importDeclaration = ast.newImportDeclaration(); importDeclaration.setName(ast.newName(ANNOTATION_PACKAGE + '.' + annotationName)); TextEditGroup editGroup = null; rewrite.getListRewrite(cu, CompilationUnit.IMPORTS_PROPERTY) .insertLast(importDeclaration, editGroup); } @Override public String toString() { return "ShardingAnnotator{}"; } }