Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/checkstyle/checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<!-- Files must contain a copyright header. -->
<module name="RegexpHeader">
<property name="header"
value="/\*\n \* Copyright 20(19|20|21) Amazon\.com, Inc\. or its affiliates\. All Rights Reserved\.\n"/>
value="/\*\n \* Copyright 20\d\d Amazon\.com, Inc\. or its affiliates\. All Rights Reserved\.\n"/>
<property name="fileExtensions" value="java"/>
</module>

Expand Down
22 changes: 18 additions & 4 deletions docs/source/1.0/guides/model-linters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -354,12 +354,13 @@ Example:


.. _StutteredShapeName:
.. _RepeatedShapeName:

StutteredShapeName
==================
RepeatedShapeName
=================

Validators that :ref:`structure` member names and :ref:`union` member
names do not stutter their shape names.
Validates that :ref:`structure` member names and :ref:`union` member
names do not case-insensitively repeat their container shape names.

As an example, if a structure named "Table" contained a member named
"TableName", then this validator would emit a WARNING event.
Expand All @@ -371,6 +372,19 @@ Rationale
Default severity
``WARNING``

Configuration
.. list-table::
:header-rows: 1
:widths: 20 20 60

* - Property
- Type
- Description
* - exactMatch
- ``boolean``
- If set to true, the validator will only warn if the member name
is case-insensitively identical to the containing shape's name.


.. _InputOutputStructureReuse:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.
*/

package software.amazon.smithy.linters;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.node.NodeMapper;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.StructureShape;
import software.amazon.smithy.model.shapes.UnionShape;
import software.amazon.smithy.model.validation.AbstractValidator;
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.model.validation.ValidatorService;

/**
* Validates that structure members and union member names do not
* repeat their shape name as prefixes of their member or tag names.
*/
public final class RepeatedShapeNameValidator extends AbstractValidator {

public static final class Config {
private boolean exactMatch = false;

public boolean getExactMatch() {
return exactMatch;
}

public void setExactMatch(boolean exactMatch) {
this.exactMatch = exactMatch;
}
}

public static final class Provider extends ValidatorService.Provider {
public Provider() {
super(RepeatedShapeNameValidator.class, node -> {
Config config = new NodeMapper().deserialize(node, Config.class);
return new RepeatedShapeNameValidator(config);
});
}
}

private final Config config;

private RepeatedShapeNameValidator(Config config) {
this.config = config;
}

@Override
public List<ValidationEvent> validate(Model model) {
List<ValidationEvent> events = new ArrayList<>();
model.shapes(StructureShape.class)
.forEach(shape -> events.addAll(validateNames(model, shape, shape.getMemberNames())));
model.shapes(UnionShape.class)
.forEach(shape -> events.addAll(validateNames(model, shape, shape.getMemberNames())));
return events;
}

private List<ValidationEvent> validateNames(Model model, Shape shape, Collection<String> memberNames) {
String shapeName = shape.getId().getName();
String lowerCaseShapeName = shapeName.toLowerCase(Locale.US);
return memberNames.stream()
.filter(memberName -> nameConflicts(lowerCaseShapeName, memberName))
.map(memberName -> repeatedMemberName(model, shape, shapeName, memberName))
.collect(Collectors.toList());
}

private boolean nameConflicts(String lowerCaseShapeName, String memberName) {
String lowerCaseMemberName = memberName.toLowerCase(Locale.US);
if (config.getExactMatch()) {
return lowerCaseMemberName.equals(lowerCaseShapeName);
} else {
return lowerCaseMemberName.startsWith(lowerCaseShapeName);
}
}

private ValidationEvent repeatedMemberName(Model model, Shape shape, String shapeName, String memberName) {
Shape member = model.expectShape(shape.getId().withMember(memberName));
if (config.getExactMatch()) {
return warning(member, String.format(
"The `%s` %s shape repeats its name in the member `%s`; %2$s member names should not be "
+ "equal to the %2$s name.", shapeName, shape.getType(), memberName));
} else {
return warning(member, String.format(
"The `%s` %s shape repeats its name in the member `%s`; %2$s member names should not be "
+ "prefixed with the %2$s name.", shapeName, shape.getType(), memberName));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.model.validation.ValidatorService;

/**
* Validates that structure members and union member names do not
* stutter their shape name as prefixes of their member or tag names.
*/
@Deprecated
public final class StutteredShapeNameValidator extends AbstractValidator {

public static final class Provider extends ValidatorService.Provider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ software.amazon.smithy.linters.AbbreviationNameValidator$Provider
software.amazon.smithy.linters.CamelCaseValidator$Provider
software.amazon.smithy.linters.InputOutputStructureReuseValidator$Provider
software.amazon.smithy.linters.MissingPaginatedTraitValidator$Provider
software.amazon.smithy.linters.RepeatedShapeNameValidator$Provider
software.amazon.smithy.linters.ReservedWordsValidator$Provider
software.amazon.smithy.linters.ShouldHaveUsedTimestampValidator$Provider
software.amazon.smithy.linters.StandardOperationVerbValidator$Provider
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[WARNING] smithy.example#RepeatingStructure$repeatingStructure: The `RepeatingStructure` structure shape repeats its name in the member `repeatingStructure`; structure member names should not be equal to the structure name. | RepeatedShapeName
[WARNING] smithy.example#RepeatingUnion$repeatingUnion: The `RepeatingUnion` union shape repeats its name in the member `repeatingUnion`; union member names should not be equal to the union name. | RepeatedShapeName
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
metadata validators = [{
name: "RepeatedShapeName",
configuration: {
exactMatch: true
}
}]

namespace smithy.example

structure RepeatingStructure {
repeatingStructure: String,

// This is fine because it's not an exact match
repeatingStructureMember: String,
}

union RepeatingUnion {
repeatingUnion: String,

// This is fine because it's not an exact match
repeatingUnionMember: String,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[WARNING] ns.foo#Invalid$InvalidBaz: The `Invalid` structure shape repeats its name in the member `InvalidBaz`; structure member names should not be prefixed with the structure name. | RepeatedShapeName
[WARNING] ns.foo#Invalid$invalidBar: The `Invalid` structure shape repeats its name in the member `invalidBar`; structure member names should not be prefixed with the structure name. | RepeatedShapeName
[WARNING] ns.foo#Invalid$invalidFoo: The `Invalid` structure shape repeats its name in the member `invalidFoo`; structure member names should not be prefixed with the structure name. | RepeatedShapeName
[WARNING] ns.foo#Invalid2$Invalid2Baz: The `Invalid2` union shape repeats its name in the member `Invalid2Baz`; union member names should not be prefixed with the union name. | RepeatedShapeName
[WARNING] ns.foo#Invalid2$invalid2Bar: The `Invalid2` union shape repeats its name in the member `invalid2Bar`; union member names should not be prefixed with the union name. | RepeatedShapeName
[WARNING] ns.foo#Invalid2$invalid2Foo: The `Invalid2` union shape repeats its name in the member `invalid2Foo`; union member names should not be prefixed with the union name. | RepeatedShapeName
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"metadata": {
"validators": [
{
"name": "StutteredShapeName"
"name": "RepeatedShapeName"
}
]
}
Expand Down

This file was deleted.