1 /* 2 * Copyright (C) 2007-2010 Júlio Vilmar Gesser. 3 * Copyright (C) 2011, 2013-2017 The JavaParser Team. 4 * 5 * This file is part of JavaParser. 6 * 7 * JavaParser can be used either under the terms of 8 * a) the GNU Lesser General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * b) the terms of the Apache License 12 * 13 * You should have received a copy of both licenses in LICENCE.LGPL and 14 * LICENCE.APACHE. Please refer to those files for details. 15 * 16 * JavaParser is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU Lesser General Public License for more details. 20 */ 21 package com.github.javaparser.ast.body; 22 23 import com.github.javaparser.TokenRange; 24 import com.github.javaparser.ast.AllFieldsConstructor; 25 import com.github.javaparser.ast.Modifier; 26 import com.github.javaparser.ast.Node; 27 import com.github.javaparser.ast.NodeList; 28 import com.github.javaparser.ast.expr.AnnotationExpr; 29 import com.github.javaparser.ast.expr.SimpleName; 30 import com.github.javaparser.ast.nodeTypes.*; 31 import com.github.javaparser.ast.nodeTypes.modifiers.*; 32 import com.github.javaparser.ast.observer.ObservableProperty; 33 import com.github.javaparser.ast.type.ArrayType; 34 import com.github.javaparser.ast.type.ReferenceType; 35 import com.github.javaparser.ast.type.Type; 36 import com.github.javaparser.ast.type.TypeParameter; 37 import com.github.javaparser.ast.visitor.CloneVisitor; 38 import com.github.javaparser.metamodel.CallableDeclarationMetaModel; 39 import com.github.javaparser.metamodel.JavaParserMetaModel; 40 import com.github.javaparser.metamodel.OptionalProperty; 41 import com.github.javaparser.ast.Generated; 42 import java.util.List; 43 import static com.github.javaparser.utils.Utils.assertNotNull; 44 import static java.util.stream.Collectors.joining; 45 import static java.util.stream.Collectors.toList; 46 import java.util.Optional; 47 import java.util.function.Consumer; 48 49 /** 50 * Represents a declaration which is callable eg. a method or a constructor. 51 */ 52 public abstract class CallableDeclaration<T extends CallableDeclaration<?>> extends BodyDeclaration<T> implements NodeWithAccessModifiers<T>, NodeWithDeclaration, NodeWithSimpleName<T>, NodeWithParameters<T>, NodeWithThrownExceptions<T>, NodeWithTypeParameters<T>, NodeWithJavadoc<T>, NodeWithAbstractModifier<T>, NodeWithStaticModifier<T>, NodeWithFinalModifier<T>, NodeWithStrictfpModifier<T> { 53 54 private NodeList<Modifier> modifiers; 55 56 private NodeList<TypeParameter> typeParameters; 57 58 private SimpleName name; 59 60 private NodeList<Parameter> parameters; 61 62 private NodeList<ReferenceType> thrownExceptions; 63 64 @OptionalProperty 65 private ReceiverParameter receiverParameter; 66 67 @AllFieldsConstructor CallableDeclaration(NodeList<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, ReceiverParameter receiverParameter)68 CallableDeclaration(NodeList<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, ReceiverParameter receiverParameter) { 69 this(null, modifiers, annotations, typeParameters, name, parameters, thrownExceptions, receiverParameter); 70 } 71 72 /** 73 * This constructor is used by the parser and is considered private. 74 */ 75 @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator") CallableDeclaration(TokenRange tokenRange, NodeList<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, ReceiverParameter receiverParameter)76 public CallableDeclaration(TokenRange tokenRange, NodeList<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, ReceiverParameter receiverParameter) { 77 super(tokenRange, annotations); 78 setModifiers(modifiers); 79 setTypeParameters(typeParameters); 80 setName(name); 81 setParameters(parameters); 82 setThrownExceptions(thrownExceptions); 83 setReceiverParameter(receiverParameter); 84 customInitialization(); 85 } 86 87 /** 88 * Return the modifiers of this member declaration. 89 * 90 * @return modifiers 91 * @see Modifier 92 */ 93 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") getModifiers()94 public NodeList<Modifier> getModifiers() { 95 return modifiers; 96 } 97 98 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") 99 @SuppressWarnings("unchecked") setModifiers(final NodeList<Modifier> modifiers)100 public T setModifiers(final NodeList<Modifier> modifiers) { 101 assertNotNull(modifiers); 102 if (modifiers == this.modifiers) { 103 return (T) this; 104 } 105 notifyPropertyChange(ObservableProperty.MODIFIERS, this.modifiers, modifiers); 106 if (this.modifiers != null) 107 this.modifiers.setParentNode(null); 108 this.modifiers = modifiers; 109 setAsParentNodeOf(modifiers); 110 return (T) this; 111 } 112 113 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") getName()114 public SimpleName getName() { 115 return name; 116 } 117 118 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") 119 @SuppressWarnings("unchecked") setName(final SimpleName name)120 public T setName(final SimpleName name) { 121 assertNotNull(name); 122 if (name == this.name) { 123 return (T) this; 124 } 125 notifyPropertyChange(ObservableProperty.NAME, this.name, name); 126 if (this.name != null) 127 this.name.setParentNode(null); 128 this.name = name; 129 setAsParentNodeOf(name); 130 return (T) this; 131 } 132 133 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") getParameters()134 public NodeList<Parameter> getParameters() { 135 return parameters; 136 } 137 138 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") 139 @SuppressWarnings("unchecked") setParameters(final NodeList<Parameter> parameters)140 public T setParameters(final NodeList<Parameter> parameters) { 141 assertNotNull(parameters); 142 if (parameters == this.parameters) { 143 return (T) this; 144 } 145 notifyPropertyChange(ObservableProperty.PARAMETERS, this.parameters, parameters); 146 if (this.parameters != null) 147 this.parameters.setParentNode(null); 148 this.parameters = parameters; 149 setAsParentNodeOf(parameters); 150 return (T) this; 151 } 152 153 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") getThrownExceptions()154 public NodeList<ReferenceType> getThrownExceptions() { 155 return thrownExceptions; 156 } 157 158 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") 159 @SuppressWarnings("unchecked") setThrownExceptions(final NodeList<ReferenceType> thrownExceptions)160 public T setThrownExceptions(final NodeList<ReferenceType> thrownExceptions) { 161 assertNotNull(thrownExceptions); 162 if (thrownExceptions == this.thrownExceptions) { 163 return (T) this; 164 } 165 notifyPropertyChange(ObservableProperty.THROWN_EXCEPTIONS, this.thrownExceptions, thrownExceptions); 166 if (this.thrownExceptions != null) 167 this.thrownExceptions.setParentNode(null); 168 this.thrownExceptions = thrownExceptions; 169 setAsParentNodeOf(thrownExceptions); 170 return (T) this; 171 } 172 173 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") getTypeParameters()174 public NodeList<TypeParameter> getTypeParameters() { 175 return typeParameters; 176 } 177 178 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") 179 @SuppressWarnings("unchecked") setTypeParameters(final NodeList<TypeParameter> typeParameters)180 public T setTypeParameters(final NodeList<TypeParameter> typeParameters) { 181 assertNotNull(typeParameters); 182 if (typeParameters == this.typeParameters) { 183 return (T) this; 184 } 185 notifyPropertyChange(ObservableProperty.TYPE_PARAMETERS, this.typeParameters, typeParameters); 186 if (this.typeParameters != null) 187 this.typeParameters.setParentNode(null); 188 this.typeParameters = typeParameters; 189 setAsParentNodeOf(typeParameters); 190 return (T) this; 191 } 192 appendThrowsIfRequested(boolean includingThrows)193 protected String appendThrowsIfRequested(boolean includingThrows) { 194 StringBuilder sb = new StringBuilder(); 195 if (includingThrows) { 196 boolean firstThrow = true; 197 for (ReferenceType thr : getThrownExceptions()) { 198 if (firstThrow) { 199 firstThrow = false; 200 sb.append(" throws "); 201 } else { 202 sb.append(", "); 203 } 204 sb.append(thr.toString(prettyPrinterNoCommentsConfiguration)); 205 } 206 } 207 return sb.toString(); 208 } 209 210 @Override 211 @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator") remove(Node node)212 public boolean remove(Node node) { 213 if (node == null) 214 return false; 215 for (int i = 0; i < modifiers.size(); i++) { 216 if (modifiers.get(i) == node) { 217 modifiers.remove(i); 218 return true; 219 } 220 } 221 for (int i = 0; i < parameters.size(); i++) { 222 if (parameters.get(i) == node) { 223 parameters.remove(i); 224 return true; 225 } 226 } 227 if (receiverParameter != null) { 228 if (node == receiverParameter) { 229 removeReceiverParameter(); 230 return true; 231 } 232 } 233 for (int i = 0; i < thrownExceptions.size(); i++) { 234 if (thrownExceptions.get(i) == node) { 235 thrownExceptions.remove(i); 236 return true; 237 } 238 } 239 for (int i = 0; i < typeParameters.size(); i++) { 240 if (typeParameters.get(i) == node) { 241 typeParameters.remove(i); 242 return true; 243 } 244 } 245 return super.remove(node); 246 } 247 248 /** 249 * A method or constructor signature. 250 * <p/>Note that since JavaParser has no real knowledge of types - only the text found in the source file - using 251 * this will fail in some cases. (java.util.String != String for example, and generics are not taken into account.) 252 */ 253 public static class Signature { 254 255 private final String name; 256 257 private final List<Type> parameterTypes; 258 Signature(String name, List<Type> parameterTypes)259 private Signature(String name, List<Type> parameterTypes) { 260 this.name = name; 261 this.parameterTypes = parameterTypes; 262 } 263 getName()264 public String getName() { 265 return name; 266 } 267 getParameterTypes()268 public List<Type> getParameterTypes() { 269 return parameterTypes; 270 } 271 272 @Override equals(Object o)273 public boolean equals(Object o) { 274 if (this == o) 275 return true; 276 if (o == null || getClass() != o.getClass()) 277 return false; 278 Signature signature = (Signature) o; 279 if (!name.equals(signature.name)) 280 return false; 281 if (!parameterTypes.equals(signature.parameterTypes)) 282 return false; 283 return true; 284 } 285 286 @Override hashCode()287 public int hashCode() { 288 int result = name.hashCode(); 289 result = 31 * result + parameterTypes.hashCode(); 290 return result; 291 } 292 asString()293 public String asString() { 294 return parameterTypes.stream().map(Type::asString).collect(joining(", ", name + "(", ")")); 295 } 296 297 @Override toString()298 public String toString() { 299 return asString(); 300 } 301 } 302 getSignature()303 public Signature getSignature() { 304 return new Signature(getName().getIdentifier(), getParameters().stream().map(this::getTypeWithVarargsAsArray).map(this::stripGenerics).map(this::stripAnnotations).collect(toList())); 305 } 306 stripAnnotations(Type type)307 private Type stripAnnotations(Type type) { 308 if (type instanceof NodeWithAnnotations) { 309 ((NodeWithAnnotations) type).setAnnotations(new NodeList<>()); 310 } 311 return type; 312 } 313 stripGenerics(Type type)314 private Type stripGenerics(Type type) { 315 if (type instanceof NodeWithTypeArguments) { 316 ((NodeWithTypeArguments) type).setTypeArguments((NodeList<Type>) null); 317 } 318 return type; 319 } 320 getTypeWithVarargsAsArray(Parameter p)321 private Type getTypeWithVarargsAsArray(Parameter p) { 322 /* A signature includes the varargs ellipsis. 323 This is a field on parameter which we lose when we only get the type, 324 so we represent it as an additional [] on the type. */ 325 Type t = p.getType().clone(); 326 if (p.isVarArgs()) { 327 t = new ArrayType(t); 328 } 329 return t; 330 } 331 332 @Override 333 @Generated("com.github.javaparser.generator.core.node.CloneGenerator") clone()334 public CallableDeclaration<?> clone() { 335 return (CallableDeclaration<?>) accept(new CloneVisitor(), null); 336 } 337 338 @Override 339 @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator") getMetaModel()340 public CallableDeclarationMetaModel getMetaModel() { 341 return JavaParserMetaModel.callableDeclarationMetaModel; 342 } 343 344 @Override 345 @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator") replace(Node node, Node replacementNode)346 public boolean replace(Node node, Node replacementNode) { 347 if (node == null) 348 return false; 349 for (int i = 0; i < modifiers.size(); i++) { 350 if (modifiers.get(i) == node) { 351 modifiers.set(i, (Modifier) replacementNode); 352 return true; 353 } 354 } 355 if (node == name) { 356 setName((SimpleName) replacementNode); 357 return true; 358 } 359 for (int i = 0; i < parameters.size(); i++) { 360 if (parameters.get(i) == node) { 361 parameters.set(i, (Parameter) replacementNode); 362 return true; 363 } 364 } 365 if (receiverParameter != null) { 366 if (node == receiverParameter) { 367 setReceiverParameter((ReceiverParameter) replacementNode); 368 return true; 369 } 370 } 371 for (int i = 0; i < thrownExceptions.size(); i++) { 372 if (thrownExceptions.get(i) == node) { 373 thrownExceptions.set(i, (ReferenceType) replacementNode); 374 return true; 375 } 376 } 377 for (int i = 0; i < typeParameters.size(); i++) { 378 if (typeParameters.get(i) == node) { 379 typeParameters.set(i, (TypeParameter) replacementNode); 380 return true; 381 } 382 } 383 return super.replace(node, replacementNode); 384 } 385 386 @Override 387 @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator") isCallableDeclaration()388 public boolean isCallableDeclaration() { 389 return true; 390 } 391 392 @Override 393 @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator") asCallableDeclaration()394 public CallableDeclaration asCallableDeclaration() { 395 return this; 396 } 397 398 @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator") ifCallableDeclaration(Consumer<CallableDeclaration> action)399 public void ifCallableDeclaration(Consumer<CallableDeclaration> action) { 400 action.accept(this); 401 } 402 403 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") getReceiverParameter()404 public Optional<ReceiverParameter> getReceiverParameter() { 405 return Optional.ofNullable(receiverParameter); 406 } 407 408 @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") 409 @SuppressWarnings("unchecked") setReceiverParameter(final ReceiverParameter receiverParameter)410 public T setReceiverParameter(final ReceiverParameter receiverParameter) { 411 if (receiverParameter == this.receiverParameter) { 412 return (T) this; 413 } 414 notifyPropertyChange(ObservableProperty.RECEIVER_PARAMETER, this.receiverParameter, receiverParameter); 415 if (this.receiverParameter != null) 416 this.receiverParameter.setParentNode(null); 417 this.receiverParameter = receiverParameter; 418 setAsParentNodeOf(receiverParameter); 419 return (T) this; 420 } 421 422 @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator") removeReceiverParameter()423 public CallableDeclaration removeReceiverParameter() { 424 return setReceiverParameter((ReceiverParameter) null); 425 } 426 427 @Override 428 @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator") toCallableDeclaration()429 public Optional<CallableDeclaration> toCallableDeclaration() { 430 return Optional.of(this); 431 } 432 } 433