Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c4561c9

Browse files
authored
chore(AST): Prevent duplicate-named or modified/scoped method args (#738)
1 parent 9ced678 commit c4561c9

File tree

2 files changed

+146
-20
lines changed

2 files changed

+146
-20
lines changed

src/main/java/com/google/api/generator/engine/ast/MethodDefinition.java

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Collections;
2222
import java.util.LinkedHashSet;
2323
import java.util.List;
24+
import java.util.Set;
2425
import java.util.stream.Collectors;
2526
import javax.annotation.Nullable;
2627

@@ -169,6 +170,8 @@ public Builder setReturnExpr(Expr expr) {
169170
// Private accessors.
170171
abstract String name();
171172

173+
abstract ImmutableList<VariableExpr> arguments();
174+
172175
abstract ImmutableList<CommentStatement> headerCommentStatements();
173176

174177
abstract ImmutableList<AnnotationNode> annotations();
@@ -314,28 +317,66 @@ public MethodDefinition build() {
314317
}
315318
}
316319

317-
for (VariableExpr varExpr : method.arguments()) {
318-
Preconditions.checkState(
319-
varExpr.isDecl(),
320-
String.format(
321-
"Argument %s must be a variable declaration", varExpr.variable().identifier()));
322-
}
323-
324-
for (TypeNode exceptionType : method.throwsExceptions()) {
325-
Preconditions.checkState(
326-
TypeNode.isExceptionType(exceptionType),
327-
String.format("Type %s is not an exception type", exceptionType.reference()));
328-
Preconditions.checkState(
329-
!RUNTIME_EXCEPTION_REFERENCE.isAssignableFrom(exceptionType.reference()),
330-
String.format(
331-
"RuntimeException type %s does not need to be thrown",
332-
exceptionType.reference().name()));
333-
}
320+
performArgumentChecks();
321+
performThrownExceptionChecks();
334322

335323
return method;
336324
}
337325

338-
void performNullChecks() {
326+
private void performArgumentChecks() {
327+
// Must be a declaration.
328+
arguments().stream()
329+
.forEach(
330+
varExpr ->
331+
Preconditions.checkState(
332+
varExpr.isDecl(),
333+
String.format(
334+
"Argument %s must be a variable declaration",
335+
varExpr.variable().identifier())));
336+
// No modifiers allowed.
337+
arguments().stream()
338+
.forEach(
339+
varExpr ->
340+
Preconditions.checkState(
341+
varExpr.scope().equals(ScopeNode.LOCAL)
342+
&& !varExpr.isStatic()
343+
&& !varExpr.isVolatile(),
344+
String.format(
345+
"Argument %s must have local scope, and cannot have \"static\" or"
346+
+ " \"volatile\" modifiers",
347+
varExpr.variable().identifier())));
348+
349+
// Check that there aren't any arguments with duplicate names.
350+
List<String> allArgNames =
351+
arguments().stream()
352+
.map(v -> v.variable().identifier().name())
353+
.collect(Collectors.toList());
354+
Set<String> duplicateArgNames =
355+
allArgNames.stream()
356+
.filter(n -> Collections.frequency(allArgNames, n) > 1)
357+
.collect(Collectors.toSet());
358+
Preconditions.checkState(
359+
duplicateArgNames.isEmpty(),
360+
String.format(
361+
"Lambda arguments cannot have duplicate names: %s", duplicateArgNames.toString()));
362+
}
363+
364+
private void performThrownExceptionChecks() {
365+
throwsExceptions().stream()
366+
.forEach(
367+
exceptionType -> {
368+
Preconditions.checkState(
369+
TypeNode.isExceptionType(exceptionType),
370+
String.format("Type %s is not an exception type", exceptionType.reference()));
371+
Preconditions.checkState(
372+
!RUNTIME_EXCEPTION_REFERENCE.isAssignableFrom(exceptionType.reference()),
373+
String.format(
374+
"RuntimeException type %s does not need to be thrown",
375+
exceptionType.reference().name()));
376+
});
377+
}
378+
379+
private void performNullChecks() {
339380
String contextInfo = String.format("method definition of %s", name());
340381
NodeValidator.checkNoNullElements(headerCommentStatements(), "header comments", contextInfo);
341382
NodeValidator.checkNoNullElements(annotations(), "annotations", contextInfo);

src/test/java/com/google/api/generator/engine/ast/MethodDefinitionTest.java

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ public void validMethodDefinition_basicWithComments() {
3636
// No exception thrown, we're good.
3737
}
3838

39+
@Test
40+
public void validMethodDefinition_emptyBody() {
41+
MethodDefinition.builder()
42+
.setHeaderCommentStatements(createCommentStatements())
43+
.setName("close")
44+
.setScope(ScopeNode.PUBLIC)
45+
.setReturnType(TypeNode.VOID)
46+
.build();
47+
}
48+
3949
@Test
4050
public void validMethodDefinition_repeatedAnnotations() {
4151
MethodDefinition method =
@@ -86,7 +96,6 @@ public void validMethodDefinition_throwInsteadOfReturnType() {
8696
ConcreteReference.withClazz(NullPointerException.class)))
8797
.build())))
8898
.build();
89-
// No exception thrown, we're good.
9099
}
91100

92101
@Test
@@ -105,7 +114,6 @@ public void validMethodDefinition_voidThrowInsteadOfReturnType() {
105114
ConcreteReference.withClazz(NullPointerException.class)))
106115
.build())))
107116
.build();
108-
// No exception thrown, we're good.
109117
}
110118

111119
@Test
@@ -645,6 +653,30 @@ public void invalidMethodDefinition_mismatchedPrimitiveToObjectReturnType() {
645653
});
646654
}
647655

656+
@Test
657+
public void invalidMethodDefinition_repeatedArgumentName() {
658+
ValueExpr returnValueExpr =
659+
ValueExpr.builder()
660+
.setValue(PrimitiveValue.builder().setType(TypeNode.INT).setValue("3").build())
661+
.build();
662+
List<VariableExpr> arguments =
663+
Arrays.asList(
664+
VariableExpr.builder().setVariable(createVariable("x", TypeNode.INT)).build(),
665+
VariableExpr.builder().setVariable(createVariable("x", TypeNode.STRING)).build());
666+
assertThrows(
667+
IllegalStateException.class,
668+
() -> {
669+
MethodDefinition.builder()
670+
.setName("close")
671+
.setScope(ScopeNode.PUBLIC)
672+
.setReturnType(TypeNode.INT)
673+
.setArguments(arguments)
674+
.setReturnExpr(returnValueExpr)
675+
.setBody(Arrays.asList(ExprStatement.withExpr(createAssignmentExpr())))
676+
.build();
677+
});
678+
}
679+
648680
@Test
649681
public void invalidMethodDefinition_nonDeclArguments() {
650682
ValueExpr returnValueExpr =
@@ -669,6 +701,59 @@ public void invalidMethodDefinition_nonDeclArguments() {
669701
});
670702
}
671703

704+
@Test
705+
public void invalidMethodDefinition_argumentsWithModifiers() {
706+
ValueExpr returnValueExpr =
707+
ValueExpr.builder()
708+
.setValue(PrimitiveValue.builder().setType(TypeNode.INT).setValue("3").build())
709+
.build();
710+
List<VariableExpr> arguments =
711+
Arrays.asList(
712+
VariableExpr.builder()
713+
.setVariable(createVariable("x", TypeNode.INT))
714+
.setIsDecl(true)
715+
.setIsStatic(true)
716+
.build(),
717+
VariableExpr.builder().setVariable(createVariable("y", TypeNode.INT)).build());
718+
assertThrows(
719+
IllegalStateException.class,
720+
() -> {
721+
MethodDefinition.builder()
722+
.setName("close")
723+
.setScope(ScopeNode.PUBLIC)
724+
.setReturnType(TypeNode.INT)
725+
.setArguments(arguments)
726+
.setReturnExpr(returnValueExpr)
727+
.build();
728+
});
729+
}
730+
731+
@Test
732+
public void invalidMethodDefinition_argumentsWithScope() {
733+
ValueExpr returnValueExpr =
734+
ValueExpr.builder()
735+
.setValue(PrimitiveValue.builder().setType(TypeNode.INT).setValue("3").build())
736+
.build();
737+
List<VariableExpr> arguments =
738+
Arrays.asList(
739+
VariableExpr.builder().setVariable(createVariable("x", TypeNode.INT)).build(),
740+
VariableExpr.builder()
741+
.setVariable(createVariable("y", TypeNode.INT))
742+
.setScope(ScopeNode.PRIVATE)
743+
.build());
744+
assertThrows(
745+
IllegalStateException.class,
746+
() -> {
747+
MethodDefinition.builder()
748+
.setName("close")
749+
.setScope(ScopeNode.PUBLIC)
750+
.setReturnType(TypeNode.INT)
751+
.setArguments(arguments)
752+
.setReturnExpr(returnValueExpr)
753+
.build();
754+
});
755+
}
756+
672757
@Test
673758
public void invalidMethodDefinition_nullReturnType() {
674759
assertThrows(

0 commit comments

Comments
 (0)