104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller/* 204b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * Copyright (C) 2015 The Android Open Source Project 304b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * 404b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 504b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * you may not use this file except in compliance with the License. 604b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * You may obtain a copy of the License at 704b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * 804b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 904b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * 1004b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * Unless required by applicable law or agreed to in writing, software 1104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 1204b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1304b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * See the License for the specific language governing permissions and 1404b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller * limitations under the License. 1504b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller */ 16ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fullerpackage com.google.currysrc.api.process.ast; 1704b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 1804b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport com.google.common.base.Splitter; 19cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fullerimport com.google.common.collect.ImmutableList; 2004b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 2104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport org.eclipse.jdt.core.dom.ASTNode; 2204b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 2304b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport org.eclipse.jdt.core.dom.BodyDeclaration; 2404b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport org.eclipse.jdt.core.dom.EnumConstantDeclaration; 2504b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport org.eclipse.jdt.core.dom.FieldDeclaration; 2604b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport org.eclipse.jdt.core.dom.MethodDeclaration; 2704b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 2893cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fullerimport java.util.ArrayList; 2904b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport java.util.Collections; 3004b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fullerimport java.util.List; 3104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 3204b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller/** 33ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller * Utility methods associated with {@link BodyDeclarationLocator} and its standard implementations. 3404b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller */ 35ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fullerpublic final class BodyDeclarationLocators { 3604b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 37ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller private BodyDeclarationLocators() { 3804b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 3904b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 40ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller public static List<BodyDeclarationLocator> createLocatorsFromStrings(String[] locatorStrings) { 41ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller ImmutableList.Builder<BodyDeclarationLocator> locatorListBuilder = ImmutableList.builder(); 42ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller for (String locatorString : locatorStrings) { 43ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller BodyDeclarationLocator locator = BodyDeclarationLocators.fromStringForm(locatorString); 44ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller locatorListBuilder.add(locator); 45cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller } 46ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return locatorListBuilder.build(); 47cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller } 48cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller 4904b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller /** 5093cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * Generates strings that can be used with {@link #fromStringForm(String)} to generate 51ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller * {@link BodyDeclarationLocator} instances capable of locating the supplied node. Usually returns 5293cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * a single element, except for fields declarations. 5304b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller */ 54ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller public static List<String> toLocatorStringForms(BodyDeclaration bodyDeclaration) { 55ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller List<BodyDeclarationLocator> locators = createLocators(bodyDeclaration); 56ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller List<String> stringForms = new ArrayList<>(locators.size()); 57ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller for (BodyDeclarationLocator locator : locators) { 58ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller stringForms.add(locator.getStringFormType() + ":" + locator.getStringFormTarget()); 5993cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller } 6093cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller return stringForms; 6193cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller } 6293cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller 6393cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller /** 64ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller * Creates {@link BodyDeclarationLocator} objects that can find the supplied 6593cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * {@link BodyDeclaration}. Usually returns a single element, except for fields declarations. 6693cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller */ 67ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller public static List<BodyDeclarationLocator> createLocators(BodyDeclaration bodyDeclaration) { 68ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller AbstractTypeDeclaration typeDeclaration = TypeLocator.findTypeDeclarationNode(bodyDeclaration); 6993cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller if (typeDeclaration == null) { 7093cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller throw new AssertionError("Unable to find type declaration for " + typeDeclaration); 7193cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller } 72ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller TypeLocator typeLocator = new TypeLocator(typeDeclaration); 7393cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller 7493cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller int nodeType = bodyDeclaration.getNodeType(); 7593cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller switch (nodeType) { 7693cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller case ASTNode.FIELD_DECLARATION: 77ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller List<String> fieldNames = FieldLocator.getFieldNames((FieldDeclaration) bodyDeclaration); 78ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller List<BodyDeclarationLocator> fieldLocators = new ArrayList<>(fieldNames.size()); 7993cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller for (String fieldName : fieldNames) { 80ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller fieldLocators.add(new FieldLocator(typeLocator, fieldName)); 8193cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller } 82ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return fieldLocators; 8393cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller case ASTNode.METHOD_DECLARATION: 8493cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller MethodDeclaration methodDeclaration = (MethodDeclaration) bodyDeclaration; 8593cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller List<String> parameterTypeNames = ParameterMatcher.getParameterTypeNames(methodDeclaration); 86ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return ImmutableList.<BodyDeclarationLocator>of( 87ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller new MethodLocator(typeLocator, methodDeclaration.getName().getIdentifier(), 8893cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller parameterTypeNames)); 8993cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller case ASTNode.TYPE_DECLARATION: 9093cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller case ASTNode.ENUM_DECLARATION: 91ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return ImmutableList.<BodyDeclarationLocator>of(typeLocator); 9293cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller case ASTNode.ENUM_CONSTANT_DECLARATION: 9393cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller EnumConstantDeclaration enumConstantDeclaration = (EnumConstantDeclaration) bodyDeclaration; 9493cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller String constantName = enumConstantDeclaration.getName().getIdentifier(); 95ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return ImmutableList.<BodyDeclarationLocator>of( 96ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller new EnumConstantLocator(typeLocator, constantName)); 9793cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller default: 9893cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller throw new IllegalArgumentException("Unsupported node type: " + nodeType); 9993cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller } 10004b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 10104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 10204b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller /** 103ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller * Creates a {@link BodyDeclarationLocator} from a string form of a body declaration. 104ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller * See {@link #toLocatorStringForms(BodyDeclaration)}. 10504b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller */ 106ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller public static BodyDeclarationLocator fromStringForm(String stringForm) { 10704b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller List<String> components = splitInTwo(stringForm, ":"); 108ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller String locatorTypeName = components.get(0); 109ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller String locatorString = components.get(1); 110ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller switch (locatorTypeName) { 111ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller case FieldLocator.LOCATOR_TYPE_NAME: 112ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller List<String> typeAndField = splitInTwo(locatorString, "#"); 113ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return new FieldLocator(new TypeLocator(typeAndField.get(0)), typeAndField.get(1)); 114ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller case MethodLocator.LOCATOR_TYPE_NAME: 115ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller List<String> typeAndMethod = splitInTwo(locatorString, "#"); 11604b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller String methodNameAndParameters = typeAndMethod.get(1); 11704b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller int parameterStartIndex = methodNameAndParameters.indexOf('('); 11804b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller if (parameterStartIndex == -1) { 11904b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller throw new IllegalArgumentException("No '(' found in " + methodNameAndParameters); 12004b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 12104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller String methodName = methodNameAndParameters.substring(0, parameterStartIndex); 12204b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller String parametersString = methodNameAndParameters.substring(parameterStartIndex); 12304b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller List<String> parameterTypes = extractParameterTypes(parametersString); 124ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return new MethodLocator(new TypeLocator(typeAndMethod.get(0)), methodName, parameterTypes); 125ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller case TypeLocator.LOCATOR_TYPE_NAME: 126ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return new TypeLocator(locatorString); 127ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller case EnumConstantLocator.LOCATOR_TYPE_NAME: 128ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller List<String> typeAndConstant = splitInTwo(locatorString, "#"); 129ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller return new EnumConstantLocator( 130ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller new TypeLocator(typeAndConstant.get(0)), typeAndConstant.get(1)); 13104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller default: 132ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller throw new IllegalArgumentException("Unsupported locator type: " + locatorTypeName); 13304b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 13404b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 13504b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 136ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller public static boolean matchesAny(List<BodyDeclarationLocator> locators, BodyDeclaration node) { 137ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller for (BodyDeclarationLocator locator : locators) { 138ac1c676b1256aaa85c5cc22494ea56bd2d276b9fNeil Fuller if (locator.matches(node)) { 139cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller return true; 140cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller } 141cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller } 142cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller return false; 143cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller } 144cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller 145cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller /** 146cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller * Finds the declaration associated with a given node. If the node is not a child of a declaration 147cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller * {@code null} is returned. 148cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller */ 149cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller public static BodyDeclaration findDeclarationNode(ASTNode node) { 150cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller ASTNode ancestor = node; 151cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller while (ancestor != null && !(ancestor instanceof BodyDeclaration)) { 152cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller ancestor = ancestor.getParent(); 153cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller } 154cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller 155cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller return ancestor instanceof BodyDeclaration ? (BodyDeclaration) ancestor : null; 156cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller } 157cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller 15804b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller private static List<String> extractParameterTypes(String parametersString) { 15904b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller if (!(parametersString.startsWith("(") && parametersString.endsWith(")"))) { 16004b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller throw new IllegalArgumentException("Expected \"(<types>)\" but was " + parametersString); 16104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 16204b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller parametersString = parametersString.substring(1, parametersString.length() - 1); 16304b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller if (parametersString.isEmpty()) { 16404b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller return Collections.emptyList(); 16504b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 16604b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller return Splitter.on(',').splitToList(parametersString); 16704b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 16804b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller 16904b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller private static List<String> splitInTwo(String string, String separator) { 17004b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller List<String> components = Splitter.on(separator).splitToList(string); 17104b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller if (components.size() != 2) { 17204b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller throw new IllegalArgumentException("Cannot split " + string + " on " + separator); 17304b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 17404b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller return components; 17504b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller } 17604b228542fa91e91551c6ea4e6a2bac1d55ca1afNeil Fuller} 177