au.com.integradev.delphi.checks.ImplicitDefaultEncodingCheck Maven / Gradle / Ivy
The newest version!
/*
* Sonar Delphi Plugin
* Copyright (C) 2023 Integrated Application Development
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package au.com.integradev.delphi.checks;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.sonar.check.Rule;
import org.sonar.plugins.communitydelphi.api.ast.NameReferenceNode;
import org.sonar.plugins.communitydelphi.api.check.DelphiCheck;
import org.sonar.plugins.communitydelphi.api.check.DelphiCheckContext;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.NameDeclaration;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineNameDeclaration;
import org.sonar.plugins.communitydelphi.api.type.Parameter;
import org.sonar.plugins.communitydelphi.api.type.Type;
@Rule(key = "ImplicitDefaultEncoding")
public class ImplicitDefaultEncodingCheck extends DelphiCheck {
private static final String MESSAGE = "Explicitly pass the encoding to this routine.";
private static final Map FORBIDDEN_SIGNATURES =
createSignatures(
signature(
"Vcl.Outline.TOutlineNode.WriteNode",
List.of("array of System.Byte ", "System.Classes.TStream"),
List.of("System.PWideChar", "System.Classes.TStream")),
signature("Vcl.Outline.TCustomOutline.LoadFromFile", List.of("System.UnicodeString")),
signature("Vcl.Outline.TCustomOutline.LoadFromStream", List.of("System.Classes.TStream")),
signature("Vcl.Outline.TCustomOutline.SaveToFile", List.of("System.UnicodeString")),
signature("Vcl.Outline.TCustomOutline.SaveToStream", List.of("System.Classes.TStream")),
signature("System.Classes.TStrings.LoadFromFile", List.of("System.UnicodeString")),
signature("System.Classes.TStrings.LoadFromStream", List.of("System.Classes.TStream")),
signature("System.Classes.TStrings.SaveToFile", List.of("System.UnicodeString")),
signature("System.Classes.TStrings.SaveToStream", List.of("System.Classes.TStream")),
signature(
"System.Classes.TStringStream.Create",
Collections.emptyList(),
List.of("System.UnicodeString"),
List.of("System.RawByteString"),
List.of("array of System.Byte ")),
signature(
"System.Classes.TStreamReader.Create",
List.of("System.Classes.TStream"),
List.of("System.Classes.TStream", "System.Boolean"),
List.of("System.UnicodeString"),
List.of("System.UnicodeString", "System.Boolean")),
signature(
"System.Classes.TStreamWriter.Create",
List.of("System.Classes.TStream"),
List.of("System.UnicodeString"),
List.of("System.UnicodeString", "System.Boolean")));
@Override
public DelphiCheckContext visit(NameReferenceNode reference, DelphiCheckContext context) {
NameDeclaration declaration = reference.getNameDeclaration();
if (declaration instanceof RoutineNameDeclaration
&& isForbiddenOverload((RoutineNameDeclaration) declaration)) {
reportIssue(context, reference.getIdentifier(), MESSAGE);
}
return super.visit(reference, context);
}
private static boolean isForbiddenOverload(RoutineNameDeclaration routine) {
Signature signature = FORBIDDEN_SIGNATURES.get(routine.fullyQualifiedName());
return signature != null
&& signature.hasParameterTypes(
routine.getParameters().stream()
.map(Parameter::getType)
.collect(Collectors.toUnmodifiableList()));
}
private static Map createSignatures(Signature... signatures) {
TreeMap map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (var signature : signatures) {
map.put(signature.getName(), signature);
}
return Collections.unmodifiableMap(map);
}
@SafeVarargs
@SuppressWarnings("varargs")
private static Signature signature(String name, List... parameterLists) {
return new Signature(name, parameterLists);
}
private static final class Signature {
private final String name;
private final List[] parameterLists;
private Signature(String name, List[] parameterLists) {
this.name = name;
this.parameterLists = parameterLists;
}
public String getName() {
return name;
}
public boolean hasParameterTypes(List types) {
return Arrays.stream(parameterLists)
.anyMatch(typeImages -> typesMatchImages(types, typeImages));
}
private static boolean typesMatchImages(List types, List typeImages) {
if (types.size() != typeImages.size()) {
return false;
}
for (int i = 0; i < types.size(); ++i) {
if (!types.get(i).is(typeImages.get(i))) {
return false;
}
}
return true;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy