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 com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import org.mutabilitydetector.checkers.CollectionField;
import org.mutabilitydetector.checkers.CollectionField.GenericType;
import org.mutabilitydetector.checkers.CollectionTypeWrappedInUnmodifiableIdiomChecker.Configuration;
import org.mutabilitydetector.checkers.hint.exceptions.WrappingHintGenerationException;
import org.mutabilitydetector.checkers.info.CopyMethod;
import org.mutabilitydetector.locations.ClassNameConverter;
import org.objectweb.asm.Type;
import static org.mutabilitydetector.checkers.hint.WrappingHint.NO_HINT;
/**
* The class is used to generate {@link WrappingHint}
*/
public final class WrappingHintGenerator {
private Configuration configuration;
private String typeSignature;
private String typeAssignedToField;
private Multimap<String, CopyMethod> userDefinedCopyMethods;
private static final ClassNameConverter CLASS_NAME_CONVERTER = new ClassNameConverter();
public WrappingHintGenerator(Configuration configuration, String typeSignature, Type fieldType,
Multimap<String, CopyMethod> userDefinedCopyMethods) {
this.configuration = configuration;
this.typeSignature = typeSignature;
this.typeAssignedToField = typeToString(fieldType);
this.userDefinedCopyMethods = userDefinedCopyMethods;
}
public WrappingHint generate() {
try {
WrappingHint.Builder builder = WrappingHint.builder();
generateWrappingPart(builder);
generateCopyingPart(builder);
return builder.build();
} catch (WrappingHintGenerationException e) {
return NO_HINT;
}
}
/**
* Pick arbitrary copying method from available configuration and don't forget to
* set generic method type if required.
* @param builder
*/
private void generateCopyingPart(WrappingHint.Builder builder) {
ImmutableCollection<CopyMethod> copyMethods = ImmutableMultimap.<String, CopyMethod>builder()
.putAll(configuration.FIELD_TYPE_TO_COPY_METHODS)
.putAll(userDefinedCopyMethods)
.build()
.get(typeAssignedToField);
if (copyMethods.isEmpty()) {
throw new WrappingHintGenerationException();
}
CopyMethod firstSuitable = copyMethods.iterator().next();
builder.setCopyMethodOwnerName(firstSuitable.owner.toString())
.setCopyMethodName(firstSuitable.name);
if (firstSuitable.isGeneric && typeSignature != null) {
CollectionField withRemovedWildcards = CollectionField.from(typeAssignedToField, typeSignature)
.transformGenericTree(GenericType::withoutWildcard);
builder.setCopyTypeParameterName(formatTypeParameter(withRemovedWildcards.asSimpleString()));
}
}
/**
* Pick arbitrary wrapping method. No generics should be set.
* @param builder
*/
private void generateWrappingPart(WrappingHint.Builder builder) {
builder.setWrappingMethodOwnerName(configuration.UNMODIFIABLE_METHOD_OWNER)
.setWrappingMethodName(configuration.FIELD_TYPE_TO_UNMODIFIABLE_METHOD.get(typeAssignedToField));
}
private static String formatTypeParameter(String typeParameter) {
return typeParameter.substring(typeParameter.indexOf('<'), typeParameter.lastIndexOf('>') + 1);
}
private static String typeToString(Type type) {
return CLASS_NAME_CONVERTER.dotted(type.getInternalName());
}
}