package org.mutabilitydetector.checkers.hint; /* * #%L * MutabilityDetector * %% * Copyright (C) 2008 - 2016 Graham Allan * %% * 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. * #L% */ import org.mutabilitydetector.locations.Dotted; /** * <p> * When collection field of class is initialized, it is common to use * copy-and-wrap idiom to make the collection immutable. * * <p> * For example: * <p> * <code> * this.list = Collections.unmodifiableList(new ArrayList<String>(list)) * </code> * * <p> * When mentioned idiom is not used correctly, or not used at all class * {@code WrappingHint} will represent a hint to help user apply copy-and-wrap * idiom in a correct way. * */ public final class WrappingHint { public static final WrappingHint NO_HINT = WrappingHint.builder().build(); final String copyMethodOwnerName; final String copyMethodName; final String wrappingMethodOwnerName; final String wrappingMethodName; final String copyTypeParameterName; private WrappingHint(String copyMethodOwnerName, String copyMethodName, String wrappingMethodOwnerName, String wrappingMethodName, String copyTypeParameterName) { this.copyMethodOwnerName = copyMethodOwnerName; this.copyMethodName = copyMethodName; this.wrappingMethodOwnerName = wrappingMethodOwnerName; this.wrappingMethodName = wrappingMethodName; this.copyTypeParameterName = copyTypeParameterName; } /** * For given field name get the actual hint message */ public String getWrappingHint(String fieldName) { if (isEmpty()) { return ""; } return String.format(" You can use this expression: %s(%s(%s))", formatMethod(wrappingMethodOwnerName, wrappingMethodName, ""), formatMethod(copyMethodOwnerName, copyMethodName, copyTypeParameterName), fieldName); } private String formatMethod(String typeName, String methodName, String typeParameter) { String simpleTypeName = Dotted.fromSlashedString(typeName).asSimpleString(); if ("<init>".equals(methodName)) { return String.format("new %s%s", simpleTypeName, typeParameter); } return String.format("%s.%s%s", simpleTypeName, typeParameter, methodName); } public boolean isEmpty() { return copyMethodOwnerName.isEmpty() && copyMethodName.isEmpty() && wrappingMethodOwnerName.isEmpty() && wrappingMethodName.isEmpty(); } public static Builder builder() { return new Builder(); } public static class Builder { private String copyMethodOwnerName = ""; private String copyMethodName = ""; private String wrappingMethodOwnerName = ""; private String wrappingMethodName = ""; private String copyTypeParameterName = ""; public Builder setCopyMethodOwnerName(String copyMethodOwnerName) { this.copyMethodOwnerName = copyMethodOwnerName; return this; } public Builder setCopyMethodName(String copyMethodName) { this.copyMethodName = copyMethodName; return this; } public Builder setWrappingMethodOwnerName(String wrappingMethodOwnerName) { this.wrappingMethodOwnerName = wrappingMethodOwnerName; return this; } public Builder setWrappingMethodName(String wrappingMethodName) { this.wrappingMethodName = wrappingMethodName; return this; } public Builder setCopyTypeParameterName(String copyTypeParameterName) { this.copyTypeParameterName = copyTypeParameterName; return this; } public WrappingHint build() { return new WrappingHint(copyMethodOwnerName, copyMethodName, wrappingMethodOwnerName, wrappingMethodName, copyTypeParameterName); } } }