| /* |
| * Copyright (C) 2015 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.google.currysrc.api.process.ast; |
| |
| import com.google.common.base.Splitter; |
| import com.google.common.collect.ImmutableList; |
| |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.jdt.core.dom.BodyDeclaration; |
| import org.eclipse.jdt.core.dom.EnumConstantDeclaration; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| /** |
| * Utility methods associated with {@link BodyDeclarationLocator} and its standard implementations. |
| */ |
| public final class BodyDeclarationLocators { |
| |
| private BodyDeclarationLocators() { |
| } |
| |
| public static List<BodyDeclarationLocator> createLocatorsFromStrings(String[] locatorStrings) { |
| ImmutableList.Builder<BodyDeclarationLocator> locatorListBuilder = ImmutableList.builder(); |
| for (String locatorString : locatorStrings) { |
| BodyDeclarationLocator locator = BodyDeclarationLocators.fromStringForm(locatorString); |
| locatorListBuilder.add(locator); |
| } |
| return locatorListBuilder.build(); |
| } |
| |
| /** |
| * Generates strings that can be used with {@link #fromStringForm(String)} to generate |
| * {@link BodyDeclarationLocator} instances capable of locating the supplied node. Usually returns |
| * a single element, except for fields declarations. |
| */ |
| public static List<String> toLocatorStringForms(BodyDeclaration bodyDeclaration) { |
| List<BodyDeclarationLocator> locators = createLocators(bodyDeclaration); |
| List<String> stringForms = new ArrayList<>(locators.size()); |
| for (BodyDeclarationLocator locator : locators) { |
| stringForms.add(locator.getStringFormType() + ":" + locator.getStringFormTarget()); |
| } |
| return stringForms; |
| } |
| |
| /** |
| * Creates {@link BodyDeclarationLocator} objects that can find the supplied |
| * {@link BodyDeclaration}. Usually returns a single element, except for fields declarations. |
| */ |
| public static List<BodyDeclarationLocator> createLocators(BodyDeclaration bodyDeclaration) { |
| AbstractTypeDeclaration typeDeclaration = TypeLocator.findTypeDeclarationNode(bodyDeclaration); |
| if (typeDeclaration == null) { |
| throw new AssertionError("Unable to find type declaration for " + typeDeclaration); |
| } |
| TypeLocator typeLocator = new TypeLocator(typeDeclaration); |
| |
| int nodeType = bodyDeclaration.getNodeType(); |
| switch (nodeType) { |
| case ASTNode.FIELD_DECLARATION: |
| List<String> fieldNames = FieldLocator.getFieldNames((FieldDeclaration) bodyDeclaration); |
| List<BodyDeclarationLocator> fieldLocators = new ArrayList<>(fieldNames.size()); |
| for (String fieldName : fieldNames) { |
| fieldLocators.add(new FieldLocator(typeLocator, fieldName)); |
| } |
| return fieldLocators; |
| case ASTNode.METHOD_DECLARATION: |
| MethodDeclaration methodDeclaration = (MethodDeclaration) bodyDeclaration; |
| List<String> parameterTypeNames = ParameterMatcher.getParameterTypeNames(methodDeclaration); |
| return ImmutableList.<BodyDeclarationLocator>of( |
| new MethodLocator(typeLocator, methodDeclaration.getName().getIdentifier(), |
| parameterTypeNames)); |
| case ASTNode.TYPE_DECLARATION: |
| case ASTNode.ENUM_DECLARATION: |
| return ImmutableList.<BodyDeclarationLocator>of(typeLocator); |
| case ASTNode.ENUM_CONSTANT_DECLARATION: |
| EnumConstantDeclaration enumConstantDeclaration = (EnumConstantDeclaration) bodyDeclaration; |
| String constantName = enumConstantDeclaration.getName().getIdentifier(); |
| return ImmutableList.<BodyDeclarationLocator>of( |
| new EnumConstantLocator(typeLocator, constantName)); |
| default: |
| throw new IllegalArgumentException("Unsupported node type: " + nodeType); |
| } |
| } |
| |
| /** |
| * Creates a {@link BodyDeclarationLocator} from a string form of a body declaration. |
| * See {@link #toLocatorStringForms(BodyDeclaration)}. |
| */ |
| public static BodyDeclarationLocator fromStringForm(String stringForm) { |
| List<String> components = splitInTwo(stringForm, ":"); |
| String locatorTypeName = components.get(0); |
| String locatorString = components.get(1); |
| switch (locatorTypeName) { |
| case FieldLocator.LOCATOR_TYPE_NAME: |
| List<String> typeAndField = splitInTwo(locatorString, "#"); |
| return new FieldLocator(new TypeLocator(typeAndField.get(0)), typeAndField.get(1)); |
| case MethodLocator.LOCATOR_TYPE_NAME: |
| List<String> typeAndMethod = splitInTwo(locatorString, "#"); |
| String methodNameAndParameters = typeAndMethod.get(1); |
| int parameterStartIndex = methodNameAndParameters.indexOf('('); |
| if (parameterStartIndex == -1) { |
| throw new IllegalArgumentException("No '(' found in " + methodNameAndParameters); |
| } |
| String methodName = methodNameAndParameters.substring(0, parameterStartIndex); |
| String parametersString = methodNameAndParameters.substring(parameterStartIndex); |
| List<String> parameterTypes = extractParameterTypes(parametersString); |
| return new MethodLocator(new TypeLocator(typeAndMethod.get(0)), methodName, parameterTypes); |
| case TypeLocator.LOCATOR_TYPE_NAME: |
| return new TypeLocator(locatorString); |
| case EnumConstantLocator.LOCATOR_TYPE_NAME: |
| List<String> typeAndConstant = splitInTwo(locatorString, "#"); |
| return new EnumConstantLocator( |
| new TypeLocator(typeAndConstant.get(0)), typeAndConstant.get(1)); |
| default: |
| throw new IllegalArgumentException("Unsupported locator type: " + locatorTypeName); |
| } |
| } |
| |
| public static boolean matchesAny(List<BodyDeclarationLocator> locators, BodyDeclaration node) { |
| for (BodyDeclarationLocator locator : locators) { |
| if (locator.matches(node)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Finds the declaration associated with a given node. If the node is not a child of a declaration |
| * {@code null} is returned. |
| */ |
| public static BodyDeclaration findDeclarationNode(ASTNode node) { |
| ASTNode ancestor = node; |
| while (ancestor != null && !(ancestor instanceof BodyDeclaration)) { |
| ancestor = ancestor.getParent(); |
| } |
| |
| return ancestor instanceof BodyDeclaration ? (BodyDeclaration) ancestor : null; |
| } |
| |
| private static List<String> extractParameterTypes(String parametersString) { |
| if (!(parametersString.startsWith("(") && parametersString.endsWith(")"))) { |
| throw new IllegalArgumentException("Expected \"(<types>)\" but was " + parametersString); |
| } |
| parametersString = parametersString.substring(1, parametersString.length() - 1); |
| if (parametersString.isEmpty()) { |
| return Collections.emptyList(); |
| } |
| return Splitter.on(',').splitToList(parametersString); |
| } |
| |
| private static List<String> splitInTwo(String string, String separator) { |
| List<String> components = Splitter.on(separator).splitToList(string); |
| if (components.size() != 2) { |
| throw new IllegalArgumentException("Cannot split " + string + " on " + separator); |
| } |
| return components; |
| } |
| } |