2424import org .sonar .check .Rule ;
2525import org .sonar .plugins .python .api .LocationInFile ;
2626import org .sonar .plugins .python .api .PythonSubscriptionCheck ;
27+ import org .sonar .plugins .python .api .SubscriptionContext ;
2728import org .sonar .plugins .python .api .symbols .Symbol ;
2829import org .sonar .plugins .python .api .tree .Expression ;
2930import org .sonar .plugins .python .api .tree .Name ;
31+ import org .sonar .plugins .python .api .tree .RaiseStatement ;
3032import org .sonar .plugins .python .api .tree .Token ;
3133import org .sonar .plugins .python .api .tree .Tree ;
3234import org .sonar .plugins .python .api .types .InferredType ;
3335import org .sonar .python .types .InferredTypes ;
36+ import org .sonar .python .types .TypeShed ;
3437
3538import static org .sonar .python .types .InferredTypes .containsDeclaredType ;
3639import static org .sonar .python .types .InferredTypes .typeClassLocation ;
40+ import static org .sonar .python .types .InferredTypes .typeName ;
3741
3842@ Rule (key = "S5864" )
3943public class ConfusingTypeCheckingCheck extends PythonSubscriptionCheck {
@@ -43,6 +47,7 @@ public void initialize(Context context) {
4347 new IncompatibleOperandsCheck ().initialize (context );
4448 new ItemOperationsTypeCheck ().initialize (context );
4549 new IterationOnNonIterableCheck ().initialize (context );
50+ context .registerSyntaxNodeConsumer (Tree .Kind .RAISE_STMT , ConfusingTypeCheckingCheck ::checkIncorrectExceptionType );
4651 }
4752
4853 private static class NonCallableCalledCheck extends NonCallableCalled {
@@ -136,12 +141,30 @@ boolean isAsyncIterable(Expression expression) {
136141 // No need to check again if the type contains a declared type
137142 return type .declaresMember ("__aiter__" );
138143 }
144+ }
139145
140- private static String nameFromExpression (Expression expression ) {
141- if (expression .is (Tree .Kind .NAME )) {
142- return ((Name ) expression ).name ();
143- }
144- return null ;
146+ private static void checkIncorrectExceptionType (SubscriptionContext ctx ) {
147+ RaiseStatement raiseStatement = (RaiseStatement ) ctx .syntaxNode ();
148+ if (raiseStatement .expressions ().isEmpty ()) {
149+ return ;
150+ }
151+ Expression raisedExpression = raiseStatement .expressions ().get (0 );
152+ InferredType type = raisedExpression .type ();
153+ if (!containsDeclaredType (type )) {
154+ return ;
155+ }
156+ if (!type .isCompatibleWith (InferredTypes .runtimeType (TypeShed .typeShedClass ("BaseException" )))) {
157+ String expressionName = nameFromExpression (raisedExpression ) != null ? String .format ("\" %s\" " , nameFromExpression (raisedExpression )) : "this expression" ;
158+ String typeName = typeName (type );
159+ ctx .addIssue (raiseStatement , String .format ("Fix this \" raise\" statement; Previous type checks suggest that %s has type \" %s\" and is not an exception." ,
160+ expressionName , typeName ));
161+ }
162+ }
163+
164+ private static String nameFromExpression (Expression expression ) {
165+ if (expression .is (Tree .Kind .NAME )) {
166+ return ((Name ) expression ).name ();
145167 }
168+ return null ;
146169 }
147170}
0 commit comments