Skip to content
Closed
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
3 changes: 2 additions & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ pipeline {
runMaven(JDK_VERSION,"install:install-file -Dfile=pycharm-pydev.jar -DgroupId=com.jetbrains.pycharm -DartifactId=pycharm-pydev -Dversion=${PYCHARM_VERSION} -Dpackaging=jar")
runMaven(JDK_VERSION,"install:install-file -Dfile=resources_en.jar -DgroupId=com.jetbrains.pycharm -DartifactId=resources_en -Dversion=${PYCHARM_VERSION} -Dpackaging=jar")
runMaven(JDK_VERSION,"install:install-file -Dfile=util.jar -DgroupId=com.jetbrains.pycharm -DartifactId=util -Dversion=${PYCHARM_VERSION} -Dpackaging=jar")
runMaven(JDK_VERSION,"install:install-file -Dfile=jps-model.jar -DgroupId=com.jetbrains.pycharm -DartifactId=jps-model -Dversion=${PYCHARM_VERSION} -Dpackaging=jar")
}
runMaven(JDK_VERSION,"clean install -Dskip.its=true")
runMaven(JDK_VERSION,"clean install -Dskip.its=true -e")
}
}
}
Expand Down
36 changes: 19 additions & 17 deletions its/ruling/src/test/resources/expected/python-S4823.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@
'project:buildbot-0.8.6p1/buildbot/scripts/runner.py':[
1302,
],
'project:buildbot-0.8.6p1/buildbot/scripts/startup.py':[
99,
],
'project:buildbot-0.8.6p1/contrib/bitbucket_buildbot.py':[
150,
],
'project:buildbot-0.8.6p1/contrib/bk_buildbot.py':[
30,
31,
32,
33,
34,
Expand Down Expand Up @@ -59,6 +57,7 @@
],
'project:buildbot-0.8.6p1/contrib/svn_buildbot.py':[
41,
42,
43,
44,
45,
Expand All @@ -76,14 +75,14 @@
548,
],
'project:buildbot-0.8.6p1/setup.py':[
84,
87,
118,
196,
],
'project:buildbot-slave-0.8.6p1/buildslave/scripts/runner.py':[
412,
],
'project:buildbot-slave-0.8.6p1/buildslave/scripts/startup.py':[
112,
],
'project:buildbot-slave-0.8.6p1/buildslave/test/unit/runprocess-scripts.py':[
62,
68,
Expand Down Expand Up @@ -201,46 +200,51 @@
],
'project:numpy-1.16.4/numpy/f2py/f2py2e.py':[
444,
493,
494,
498,
502,
503,
504,
510,
511,
511,
517,
518,
518,
521,
532,
532,
535,
536,
536,
539,
540,
540,
568,
569,
569,
575,
578,
579,
580,
581,
581,
582,
584,
585,
586,
587,
587,
588,
640,
640,
641,
646,
648,
659,
660,
666,
669,
670,
671,
675,
676,
677,
678,
682,
685,
],
Expand All @@ -263,14 +267,14 @@
],
'project:numpy-1.16.4/runtests.py':[
67,
170,
486,
],
'project:numpy-1.16.4/setup.py':[
220,
262,
344,
385,
387,
],
'project:numpy-1.16.4/tools/c_coverage/c_coverage_report.py':[
148,
Expand Down Expand Up @@ -310,16 +314,13 @@
220,
243,
244,
244,
245,
245,
247,
248,
249,
251,
252,
252,
278,
],
'project:tornado-2.3/tornado/options.py':[
117,
Expand Down Expand Up @@ -502,6 +503,7 @@
'project:twisted-12.1.0/twisted/scripts/trial.py':[
98,
369,
370,
375,
],
'project:twisted-12.1.0/twisted/test/_preamble.py':[
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* SonarQube Python Plugin
* Copyright (C) 2011-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* 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 02110-1301, USA.
*/
package org.sonar.python.checks;

import com.intellij.psi.PsiElement;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.PyCallExpression;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyReferenceExpression;
import java.util.Set;
import org.sonar.python.PythonCheck;

public abstract class AbstractCallExpressionBase extends PythonCheck {

protected abstract Set<String> functionsToCheck();

protected abstract String message();

protected boolean isException(PsiElement node) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about having a more useful type for node?
In fact, this method is useless so far since it's never overridden.

return false;
}

@Override
public void initialize(Context context) {
context.registerSyntaxNodeConsumer(PyElementTypes.CALL_EXPRESSION, ctx -> {
PyCallExpression node = (PyCallExpression) ctx.syntaxNode();
PyExpression callee = node.getCallee();
if (callee instanceof PyReferenceExpression) {
PsiElement resolve = ((PyReferenceExpression) callee).getReference().resolve();
if (resolve instanceof PyFunction) {
PyFunction pyFunction = (PyFunction) resolve;
PyClass containingClass = pyFunction.getContainingClass();
if (containingClass != null) {
String qualifiedName = containingClass.getQualifiedName();
if (!isException(node) && functionsToCheck().contains(qualifiedName + "." + pyFunction.getName())) {
ctx.addIssue(node, message());
}
}
}
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,33 @@
*/
package org.sonar.python.checks.hotspots;

import com.sonar.sslr.api.AstNode;
import com.sonar.sslr.api.AstNodeType;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.PyImportElement;
import com.jetbrains.python.psi.PyReferenceExpression;
import com.jetbrains.python.psi.PyTargetExpression;
import java.util.Set;
import org.sonar.check.Rule;
import org.sonar.python.api.PythonGrammar;
import org.sonar.python.checks.AbstractCallExpressionCheck;
import org.sonar.python.semantic.Symbol;
import org.sonar.python.checks.AbstractCallExpressionBase;

@Rule(key = CommandLineArgsCheck.CHECK_KEY)
public class CommandLineArgsCheck extends AbstractCallExpressionCheck {
public static final String CHECK_KEY = "S4823";
@Rule(key = "S4823")
public class CommandLineArgsCheck extends AbstractCallExpressionBase {
private static final String MESSAGE = "Make sure that command line arguments are used safely here.";
private static final Set<String> questionableFunctions = immutableSet("argparse.ArgumentParser", "optparse.OptionParser");
private static final Set<String> questionableFunctions = immutableSet("argparse.ArgumentParser.__init__", "optparse.OptionParser.__init__");

@Override
public Set<AstNodeType> subscribedKinds() {
return immutableSet(PythonGrammar.CALL_EXPR, PythonGrammar.ATTRIBUTE_REF, PythonGrammar.ATOM);
}

@Override
public void visitNode(AstNode node) {
if (node.is(PythonGrammar.ATTRIBUTE_REF, PythonGrammar.ATOM)) {
if (isSysArgvNode(node)) {
addIssue(node, MESSAGE);
public void initialize(Context context) {
super.initialize(context);
context.registerSyntaxNodeConsumer(PyElementTypes.REFERENCE_EXPRESSION, ctx -> {
PyReferenceExpression node = (PyReferenceExpression) ctx.syntaxNode();
if (node.getParent() instanceof PyImportElement) {
return;
}
} else {
super.visitNode(node);
}
}

private boolean isSysArgvNode(AstNode attributeRef) {
Symbol symbol = getContext().symbolTable().getSymbol(attributeRef);
return symbol != null && symbol.qualifiedName().equals("sys.argv");
PsiElement resolve = node.getReference().resolve();
if (resolve instanceof PyTargetExpression && "sys.argv".equals(((PyTargetExpression) resolve).getQualifiedName())) {
ctx.addIssue(node, message());
}
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,15 @@ def builtins():

def optparse_test():
OptionParser() # Noncompliant
optparse.OptionParser() # Noncompliant
optparse.OptionParser() # Noncompliant



def assign_to_argv(original_argv):
sys.argv = original_argv # OK

def calling_list_methods():
sys.argv.index('-d') # Noncompliant
sys.argv.remove('test') # Noncompliant
sys.argv.append('test') # Noncompliant
sys.argv.extend(['config_fc'] + []) # Noncompliant
15 changes: 15 additions & 0 deletions python-frontend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
<artifactId>util</artifactId>
<version>${pycharm.version}</version>
</dependency>
<dependency>
<groupId>com.jetbrains.pycharm</groupId>
<artifactId>jps-model</artifactId>
<version>${pycharm.version}</version>
</dependency>


<dependency>
Expand Down Expand Up @@ -80,6 +85,16 @@
<artifactId>trove4j</artifactId>
<version>1.0.20190514</version>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>one.util</groupId>
<artifactId>streamex</artifactId>
<version>0.6.8</version>
</dependency>

<dependency>
<groupId>junit</groupId>
Expand Down
Loading