1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/* 2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification 3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * of Java bytecode. 4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 52270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it 8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free 9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option) 10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version. 11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT 13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details. 16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along 18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc., 19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.optimize; 22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.*; 24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.*; 25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.annotation.*; 262270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstromimport proguard.classfile.attribute.visitor.AttributeVisitor; 27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.editor.ConstantPoolEditor; 28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.util.*; 29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.visitor.MemberVisitor; 30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/** 32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This MemberVisitor adds an additional parameter to the duplicate 33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * initialization methods that it visits. 34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class DuplicateInitializerFixer 36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoextends SimplifiedVisitor 37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimplements MemberVisitor, 38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato AttributeVisitor 39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{ 40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static final boolean DEBUG = false; 41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static final char[] TYPES = new char[] 43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 442270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom ClassConstants.TYPE_BYTE, 452270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom ClassConstants.TYPE_CHAR, 462270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom ClassConstants.TYPE_SHORT, 472270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom ClassConstants.TYPE_INT, 482270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom ClassConstants.TYPE_BOOLEAN 49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato }; 50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private final MemberVisitor extraFixedInitializerVisitor; 53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Creates a new DuplicateInitializerFixer. 57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public DuplicateInitializerFixer() 59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this(null); 61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Creates a new DuplicateInitializerFixer with an extra visitor. 66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @param extraFixedInitializerVisitor an optional extra visitor for all 67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * initializers that have been fixed. 68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public DuplicateInitializerFixer(MemberVisitor extraFixedInitializerVisitor) 70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this.extraFixedInitializerVisitor = extraFixedInitializerVisitor; 72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for MemberVisitor. 76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) 78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Is it a class instance initializer? 80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato String name = programMethod.getName(programClass); 812270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom if (name.equals(ClassConstants.METHOD_NAME_INIT)) 82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Is there already another initializer with the same descriptor? 84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato String descriptor = programMethod.getDescriptor(programClass); 85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Method similarMethod = programClass.findMethod(name, descriptor); 86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (!programMethod.equals(similarMethod)) 87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Should this initializer be preserved? 89b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang if (KeepMarker.isKept(programMethod)) 90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Fix the other initializer. 92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programMethod = (ProgramMethod)similarMethod; 93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 952270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom int index = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE); 96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Try to find a new, unique descriptor. 98b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang int typeCounter = 0; 99b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang while (true) 100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 101b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Construct the new descriptor by inserting a new type 102b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // as an additional last argument. 103b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang StringBuffer newDescriptorBuffer = 104b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang new StringBuffer(descriptor.substring(0, index)); 105b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 106b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang for (int arrayDimension = 0; arrayDimension < typeCounter / TYPES.length; arrayDimension++) 107b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 1082270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom newDescriptorBuffer.append(ClassConstants.TYPE_ARRAY); 109b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 110b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 111b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang newDescriptorBuffer.append(TYPES[typeCounter % TYPES.length]); 112b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang newDescriptorBuffer.append(descriptor.substring(index)); 113b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 114b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang String newDescriptor = newDescriptorBuffer.toString(); 115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Is the new initializer descriptor unique? 117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (programClass.findMethod(name, newDescriptor) == null) 118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("DuplicateInitializerFixer:"); 122b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang System.out.println(" ["+programClass.getName()+"."+name+descriptor+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") -> ["+newDescriptor+"]"); 123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Update the descriptor. 126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programMethod.u2descriptorIndex = 127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ConstantPoolEditor(programClass).addUtf8Constant(newDescriptor); 128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Fix the local variable frame size, the method 130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // signature, and the parameter annotations, if 131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // necessary. 132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programMethod.attributesAccept(programClass, 133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this); 134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Visit the initializer, if required. 136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (extraFixedInitializerVisitor != null) 137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato extraFixedInitializerVisitor.visitProgramMethod(programClass, programMethod); 139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // We're done with this constructor. 142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return; 143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 1449f606f95f03a75961498803e24bee6799a7c0885Ying Wang 145b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang typeCounter++; 146b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for AttributeVisitor. 153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The minimum variable size is determined by the arguments. 160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int maxLocals = 161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), 162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method.getAccessFlags()); 163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (codeAttribute.u2maxLocals < maxLocals) 165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute.u2maxLocals = maxLocals; 167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute) 172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato String descriptor = method.getDescriptor(clazz); 1742270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom int descriptorIndex = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE); 1752270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom String signature = signatureAttribute.getSignature(clazz); 1762270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom int signatureIndex = signature.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE); 177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato String newSignature = signature.substring(0, signatureIndex) + 179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptor.charAt(descriptorIndex - 1) + 180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato signature.substring(signatureIndex); 181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Update the signature. 183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato signatureAttribute.u2signatureIndex = 184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature); 185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) 189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Update the number of parameters. 1912270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom int oldParametersCount = parameterAnnotationsAttribute.u1parametersCount++; 192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (parameterAnnotationsAttribute.u2parameterAnnotationsCount == null || 1942270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom parameterAnnotationsAttribute.u2parameterAnnotationsCount.length < parameterAnnotationsAttribute.u1parametersCount) 195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 1962270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom int[] annotationsCounts = new int[parameterAnnotationsAttribute.u1parametersCount]; 1972270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom Annotation[][] annotations = new Annotation[parameterAnnotationsAttribute.u1parametersCount][]; 198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.arraycopy(parameterAnnotationsAttribute.u2parameterAnnotationsCount, 200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 0, 201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato annotationsCounts, 202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 0, 203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato oldParametersCount); 204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.arraycopy(parameterAnnotationsAttribute.parameterAnnotations, 206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 0, 207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato annotations, 208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 0, 209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato oldParametersCount); 210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato parameterAnnotationsAttribute.u2parameterAnnotationsCount = annotationsCounts; 212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato parameterAnnotationsAttribute.parameterAnnotations = annotations; 213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato}