au.com.integradev.delphi.symbol.declaration.PropertyNameDeclarationImpl Maven / Gradle / Ivy
The newest version!
/*
* Sonar Delphi Plugin
* Copyright (C) 2019 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.symbol.declaration;
import au.com.integradev.delphi.symbol.SymbolicNode;
import au.com.integradev.delphi.type.parameter.FormalParameter;
import com.google.common.collect.ComparisonChain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.plugins.communitydelphi.api.ast.AttributeListNode;
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
import org.sonar.plugins.communitydelphi.api.ast.NameReferenceNode;
import org.sonar.plugins.communitydelphi.api.ast.PrimaryExpressionNode;
import org.sonar.plugins.communitydelphi.api.ast.PropertyImplementsSpecifierNode;
import org.sonar.plugins.communitydelphi.api.ast.PropertyNode;
import org.sonar.plugins.communitydelphi.api.ast.PropertyReadSpecifierNode;
import org.sonar.plugins.communitydelphi.api.ast.PropertyWriteSpecifierNode;
import org.sonar.plugins.communitydelphi.api.ast.TypeDeclarationNode;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.NameDeclaration;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.PropertyNameDeclaration;
import org.sonar.plugins.communitydelphi.api.type.Parameter;
import org.sonar.plugins.communitydelphi.api.type.Type;
import org.sonar.plugins.communitydelphi.api.type.TypeSpecializationContext;
import org.sonar.plugins.communitydelphi.api.type.Typed;
public final class PropertyNameDeclarationImpl extends NameDeclarationImpl
implements PropertyNameDeclaration {
private final String fullyQualifiedName;
private final List parameters;
private final boolean isClassInvocable;
private final boolean isDefaultProperty;
private final Type type;
private final NameDeclaration readDeclaration;
private final NameDeclaration writeDeclaration;
private final List implementedTypes;
private final VisibilityType visibility;
private final List redeclarations;
private final List attributeTypes;
private int hashCode;
public PropertyNameDeclarationImpl(
PropertyNode node, @Nullable PropertyNameDeclaration concreteDeclaration) {
this(
new SymbolicNode(node.getPropertyName()),
makeQualifiedName(node),
extractParameters(node, concreteDeclaration),
node.isClassProperty(),
node.isDefaultProperty(),
extractType(node, concreteDeclaration),
extractReadDeclaration(node, concreteDeclaration),
extractWriteDeclaration(node, concreteDeclaration),
extractImplementedTypes(node, concreteDeclaration),
node.getVisibility(),
extractAttributeTypes(node));
}
private PropertyNameDeclarationImpl(
SymbolicNode location,
String fullyQualifiedName,
List parameters,
boolean isClassInvocable,
boolean isDefaultProperty,
Type type,
NameDeclaration readDeclaration,
NameDeclaration writeDeclaration,
List implementedTypes,
VisibilityType visibility,
List attributeTypes) {
super(location);
this.fullyQualifiedName = fullyQualifiedName;
this.parameters = parameters;
this.isClassInvocable = isClassInvocable;
this.isDefaultProperty = isDefaultProperty;
this.type = type;
this.readDeclaration = readDeclaration;
this.writeDeclaration = writeDeclaration;
this.implementedTypes = implementedTypes;
this.visibility = visibility;
this.attributeTypes = attributeTypes;
this.redeclarations = new ArrayList<>();
}
private static String makeQualifiedName(PropertyNode propertyNode) {
return propertyNode.getFirstParentOfType(TypeDeclarationNode.class).fullyQualifiedName()
+ "."
+ propertyNode.getPropertyName().getImage();
}
private static List extractParameters(
PropertyNode node, @Nullable PropertyNameDeclaration concreteDeclaration) {
if (concreteDeclaration != null) {
return concreteDeclaration.getParameters();
}
return node.getParameters().stream()
.map(FormalParameter::create)
.collect(Collectors.toUnmodifiableList());
}
private static Type extractType(
PropertyNode node, @Nullable PropertyNameDeclaration concreteDeclaration) {
if (concreteDeclaration != null) {
return concreteDeclaration.getType();
}
return node.getType();
}
private static NameDeclaration extractReadDeclaration(
PropertyNode node, @Nullable PropertyNameDeclaration concreteDeclaration) {
if (concreteDeclaration != null) {
return concreteDeclaration.getReadDeclaration();
}
PropertyReadSpecifierNode readSpecifier = node.getReadSpecifier();
if (readSpecifier != null) {
return extractSpecifierDeclaration(readSpecifier.getExpression());
}
return null;
}
private static NameDeclaration extractWriteDeclaration(
PropertyNode node, @Nullable PropertyNameDeclaration concreteDeclaration) {
if (concreteDeclaration != null) {
return concreteDeclaration.getWriteDeclaration();
}
PropertyWriteSpecifierNode writeSpecifier = node.getWriteSpecifier();
if (writeSpecifier != null) {
return extractSpecifierDeclaration(writeSpecifier.getExpression());
}
return null;
}
private static List extractImplementedTypes(
PropertyNode node, @Nullable PropertyNameDeclaration concreteDeclaration) {
if (concreteDeclaration != null) {
return concreteDeclaration.getImplementedTypes();
}
PropertyImplementsSpecifierNode implementsSpecifier = node.getImplementsSpecifier();
if (implementsSpecifier != null) {
return implementsSpecifier.getTypeReferences().stream()
.map(Typed::getType)
.collect(Collectors.toUnmodifiableList());
}
return Collections.emptyList();
}
private static NameDeclaration extractSpecifierDeclaration(PrimaryExpressionNode node) {
NameDeclaration result = null;
for (DelphiNode child : node.getChildren()) {
if (child instanceof NameReferenceNode) {
result = ((NameReferenceNode) child).getLastName().getNameDeclaration();
}
}
return result;
}
private static List extractAttributeTypes(PropertyNode node) {
AttributeListNode attributeList = node.getAttributeList();
if (attributeList != null) {
return node.getAttributeList().getAttributeTypes();
} else {
return Collections.emptyList();
}
}
@Override
public Type getType() {
return type;
}
@Override
public String fullyQualifiedName() {
return fullyQualifiedName;
}
@Override
@Nullable
public NameDeclaration getReadDeclaration() {
return readDeclaration;
}
@Override
@Nullable
public NameDeclaration getWriteDeclaration() {
return writeDeclaration;
}
@Override
public List getImplementedTypes() {
return implementedTypes;
}
@Override
public Type getReturnType() {
return getType();
}
@Override
public List getParameters() {
return parameters;
}
@Override
public boolean isCallable() {
return true;
}
@Override
public boolean isClassInvocable() {
return isClassInvocable;
}
@Override
public VisibilityType getVisibility() {
return visibility;
}
@Override
public boolean isArrayProperty() {
return !parameters.isEmpty();
}
@Override
public boolean isDefaultProperty() {
return isDefaultProperty;
}
@Override
public List getAttributeTypes() {
return attributeTypes;
}
public void addRedeclaration(PropertyNameDeclaration declaration) {
this.redeclarations.add(declaration);
}
@Override
public List getRedeclarations() {
return redeclarations;
}
@Override
protected NameDeclaration doSpecialization(TypeSpecializationContext context) {
return new PropertyNameDeclarationImpl(
node,
fullyQualifiedName,
parameters.stream()
.map(parameter -> parameter.specialize(context))
.collect(Collectors.toUnmodifiableList()),
isClassInvocable,
isDefaultProperty,
type.specialize(context),
specializeIfNotNull(readDeclaration, context),
specializeIfNotNull(writeDeclaration, context),
implementedTypes.stream()
.map(implementedType -> implementedType.specialize(context))
.collect(Collectors.toUnmodifiableList()),
visibility,
attributeTypes);
}
private static NameDeclaration specializeIfNotNull(
NameDeclaration declaration, TypeSpecializationContext context) {
if (declaration != null) {
return declaration.specialize(context);
}
return null;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof PropertyNameDeclarationImpl)) {
return false;
}
PropertyNameDeclarationImpl that = (PropertyNameDeclarationImpl) other;
return that.getNode().getImage().equalsIgnoreCase(getNode().getImage())
&& parameters.equals(that.parameters)
&& type.is(that.type);
}
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = Objects.hash(getNode().getImage().toLowerCase(), parameters);
}
return hashCode;
}
@Override
public int compareTo(NameDeclaration other) {
int result = super.compareTo(other);
if (result == 0) {
PropertyNameDeclarationImpl that = (PropertyNameDeclarationImpl) other;
result =
ComparisonChain.start()
.compare(getParametersCount(), that.getParametersCount())
.compare(getRequiredParametersCount(), that.getRequiredParametersCount())
.compareTrueFirst(isClassInvocable, that.isClassInvocable)
.compare(type.getImage(), that.type.getImage())
.result();
if (result != 0) {
return result;
}
if (!equals(other)) {
result = -1;
}
}
return result;
}
@Override
public String toString() {
return "Property: image = '"
+ getNode().getImage()
+ "', line = "
+ getNode().getBeginLine()
+ ", params = "
+ parameters.size()
+ " <"
+ getNode().getUnitName()
+ ">";
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy