QL code and tests for C#/C++/JavaScript.

This commit is contained in:
Pavel Avgustinov
2018-08-02 17:53:23 +01:00
commit b55526aa58
10684 changed files with 581163 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Calling <code>System.Object</code>'s (or <code>System.ValueType</code>'s) <code>ToString</code>
method on a value returns the fully qualified name of the type of that value. In most cases this is
not useful, or what was intended. This rule finds explicit and implicit calls to the default
<code>ToString</code> methods.
</p>
</overview>
<recommendation>
<p>
Override the default <code>ToString</code> method, if possible, or perform bespoke string conversion.
</p>
</recommendation>
<example>
<p>
In the following example, the default <code>ToString</code> method is invoked first on an object
of type <code>Person</code>, and then on an integer array. The output results are
<code>p: Bad+Person</code> and <code>ints: System.Int32[]</code>, respectively.
</p>
<sample src="DefaultToStringBad.cs" />
<p>
In the fixed example, the <code>ToString</code> method is overridden in the class <code>Person</code>,
and <code>string.Join</code> is used to print the elements of the integer array (it is not possible
to override <code>ToString</code> in that case). The output results are
<code>p: Eric Arthur Blair</code> and <code>ints: 1, 2, 3</code>, respectively.
</p>
<sample src="DefaultToStringGood.cs" />
</example>
<references>
<li>MSDN: <a href="http://msdn.microsoft.com/en-us/library/system.object.tostring.aspx">Object.ToString Method</a>, <a href="https://msdn.microsoft.com/en-us/library/wb77sz3h(v=vs.110).aspx">ValueType.ToString Method</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,64 @@
/**
* @name Use of default ToString()
* @description Calling the default implementation of 'ToString' returns a value
* that is unlikely to be what you expect.
* @kind problem
* @problem.severity warning
* @precision very-high
* @id cs/call-to-object-tostring
* @tags reliability
* maintainability
*/
import csharp
import semmle.code.csharp.commons.Strings
import semmle.code.csharp.frameworks.System
/**
* Holds if expression `e`, of type `t`, invokes `ToString()` either explicitly
* or implicitly.
*/
predicate invokesToString(Expr e, ValueOrRefType t) {
// Explicit invocation
exists(MethodCall mc |
mc.getQualifier() = e |
mc.getTarget() instanceof ToStringMethod and
t = mc.getQualifier().getType()
)
or
// Explicit or implicit invocation
e instanceof ImplicitToStringExpr and
t = e.stripCasts().getType()
or
// Implicit invocation via forwarder method
t = e.stripCasts().getType() and
not t instanceof StringType and
exists(AssignableDefinitions::ImplicitParameterDefinition def, Parameter p, ParameterRead pr |
e = p.getAnAssignedArgument() |
def.getParameter() = p and
pr = def.getAReachableRead() and
pr.getAControlFlowNode().postDominates(p.getCallable().getEntryPoint()) and
invokesToString(pr, _)
)
}
/**
* Holds if `t`, or any sub type of `t`, inherits the default `ToString()`
* method from `System.Object` or `System.ValueType`.
*/
predicate alwaysDefaultToString(ValueOrRefType t) {
exists(ToStringMethod m |
t.hasMethod(m) |
m.getDeclaringType() instanceof SystemObjectClass or
m.getDeclaringType() instanceof SystemValueTypeClass
)
and
not exists(RefType overriding |
overriding.getAMethod() instanceof ToStringMethod and
overriding.getABaseType+() = t
)
}
from Expr e, ValueOrRefType t
where invokesToString(e, t)
and alwaysDefaultToString(t)
select e, "Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing.", t, t.getName()

View File

@@ -0,0 +1,23 @@
using System;
class Bad
{
static void Main(string[] args)
{
var p = new Person("Eric Arthur Blair");
Console.WriteLine("p: " + p);
var ints = new int[] { 1, 2, 3 };
Console.WriteLine("ints: " + ints);
}
class Person
{
private string Name;
public Person(string name)
{
this.Name = name;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
class Good
{
static void Main(string[] args)
{
var p = new Person("Eric Arthur Blair");
Console.WriteLine("p: " + p);
var ints = new int[] { 1, 2, 3 };
Console.WriteLine("ints: " + string.Join(", ", ints));
}
class Person
{
private string Name;
public Person(string name)
{
this.Name = name;
}
public override string ToString() => Name;
}
}

View File

@@ -0,0 +1,19 @@
class FutileConditional
{
static void Main(string[] args)
{
if (args.Length > 10) ; // BAD
if (args.Length > 8)
{
// BAD
}
if (args.Length > 6)
{
// GOOD: because of else-branch
}
else
{
System.Console.WriteLine("hello");
}
}
}

View File

@@ -0,0 +1,22 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>This rule finds If-statements where the "then" branch is empty and there is no "else" branch. These statements are usually unimplemented skeleton code that should be implemented, or real unused code that should be removed.</p>
</overview>
<recommendation>
<p>There might be missing statements in the then-branch or the If-statement might be able to be removed completely.</p>
</recommendation>
<example>
<sample src="FutileConditional.cs" />
</example>
<references>
<li>MSDN, C# Reference, <a href="http://msdn.microsoft.com/en-us/library/5011f09h(v=vs.110).aspx">if-else</a></li>
</references>
</qhelp>

View File

@@ -0,0 +1,27 @@
/**
* @name Futile conditional
* @description If-statement with an empty then-branch and no else-branch.
* @kind problem
* @problem.severity warning
* @precision very-high
* @id cs/useless-if-statement
* @tags reliability
* readability
*/
import csharp
predicate emptyStmt(Stmt s) {
s instanceof EmptyStmt
or
s = any(BlockStmt bs |
bs.getNumberOfStmts() = 0
or
bs.getNumberOfStmts() = 1 and
emptyStmt(bs.getStmt(0))
)
}
from IfStmt ifstmt
where emptyStmt(ifstmt.getThen())
and (not exists(ifstmt.getElse()) or emptyStmt(ifstmt.getElse()))
select ifstmt, "If-statement with an empty then-branch and no else-branch."

View File

@@ -0,0 +1,4 @@
public override int GetHashCode()
{
return row.GetHashCode() ^ col.GetHashCode();
}

View File

@@ -0,0 +1,41 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
The method <code>GetHashCode()</code> on an integer simply returns the original value of the integer.
This method call is therefore redundant, inefficient, and obscures the logic of the hash function.
Several of the built-in types have this behavior, including <code>int</code>, <code>uint</code>,
<code>short</code>, <code>ushort</code>, <code>long</code>, <code>ulong</code>, <code>byte</code> and <code>sbyte</code>.
</p>
</overview>
<recommendation>
<p>Remove the call to <code>GetHashCode()</code>, and review the hash function.</p>
</recommendation>
<example>
<p>
The following hash function has two problems. Firstly, the calls to <code>GetHashCode()</code> are redundant,
and secondly, the hash function generates too many collisions.
</p>
<sample src="IntGetHashCode.cs" />
<p>
These problems are resolved by removing the redundant calls to <code>GetHashCode()</code>, and
by changing the hash function to generate fewer collisions.
</p>
<sample src="IntGetHashCodeFix.cs" />
</example>
<references>
<li>MSDN, C# Reference, <a href="https://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx">Object.GetHashCode Method</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,19 @@
/**
* @name Useless call to GetHashCode()
* @description Calling 'GetHashCode()' on integer types is redundant because the method always returns
* the original value.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id cs/useless-gethashcode-call
* @tags readability
* useless-code
*/
import csharp
import semmle.code.csharp.frameworks.System
from MethodCall mc, IntegralType t
where mc.getTarget() instanceof GetHashCodeMethod
and t = mc.getQualifier().getType()
select mc, "Calling GetHashCode() on type " + t.toStringWithTypes() + " is redundant."

View File

@@ -0,0 +1,4 @@
public override int GetHashCode()
{
return unchecked(row * 16777619 + col);
}

View File

@@ -0,0 +1,17 @@
class PointlessForwardingMethod
{
public static void Print(string firstName, string lastName)
{
Print(firstName + " " + lastName);
}
public static void Print(string fullName)
{
Console.WriteLine("Pointless forwarding methods are bad, " + fullName + "...");
}
public static void Main(string[] args)
{
Print("John", "Doe");
}
}

View File

@@ -0,0 +1,28 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>If a class contains two distinct methods of the same name such that:</p>
<ul>
<li>one of them is only ever called from the other</li>
<li>and the calling method of the two only makes calls to the callee</li>
<li>and the calling method makes no other calls</li>
</ul>
<p>then the calling method is no more than a forwarding method for the callee.
Forwarding methods are difficult to keep track of and can make public APIs more complicated.</p>
</overview>
<recommendation>
<p>Merge the two methods.</p>
</recommendation>
<example>
<p>In this example the <code>Print(string, string)</code> method is simply a forwarding method.
Since <code>Print(string)</code> is not called anywhere else it serves no purpose.</p>
<sample src="PointlessForwardingMethod.cs" />
<p>This example could be easily improved by merging the two Print methods like so:</p>
<sample src="PointlessForwardingMethodFix.cs" />
</example>
</qhelp>

View File

@@ -0,0 +1,55 @@
/**
* @name Pointless forwarding method
* @description A method forwards calls to another method of the same name that is not called independently.
* @kind problem
* @problem.severity recommendation
* @precision medium
* @id cs/useless-forwarding-method
* @tags maintainability
* useless-code
*/
import csharp
predicate methodInClass(ValueOrRefType t, Method m, string name)
{
m.getDeclaringType() = t
and m.getName() = name
}
predicate callIn(MethodCall mc, Method fromMethod)
{
fromMethod = mc.getEnclosingCallable()
}
predicate callTo(MethodCall mc, Method toMethod)
{
toMethod = mc.getTarget().getSourceDeclaration()
}
predicate candidates(Method forwarder, Method forwardee)
{
exists(ValueOrRefType t, string name |
methodInClass(t, forwarder, name) and methodInClass(t, forwardee, name) |
not ignored(forwarder) and not ignored(forwardee) and forwarder != forwardee
)
}
predicate ignored(Method m)
{
m.isAbstract()
or m.implements()
or m.isOverride()
or m.isVirtual()
or m.getName() = "Dispose"
or not m.fromSource()
}
from Method forwarder, Method forwardee
where
not extractionIsStandalone()
and candidates(forwarder, forwardee)
and forex(MethodCall c | callTo(c, forwardee) | callIn(c, forwarder))
and forex(MethodCall c | callIn(c, forwarder) | callTo(c, forwardee))
select forwarder.getSourceDeclaration(), "This method is a forwarder for $@, which is not called independently - the methods can be merged.",
forwardee.getSourceDeclaration(), forwardee.getName()

View File

@@ -0,0 +1,13 @@
class PointlessForwardingMethodFix
{
public static void Print(string firstName, string lastName)
{
string fullName = firstName + " " + lastName;
Console.WriteLine("Pointless forwarding methods are bad, " + fullName + "...");
}
public static void Main(string[] args)
{
Print("John", "Doe");
}
}

View File

@@ -0,0 +1,37 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
In certain contexts, such as when concatenating a string and an object, calling
<code>ToString</code> explicitly can be omitted.
</p>
</overview>
<recommendation>
<p>
Remove the redundant call to <code>ToString</code>.
</p>
</recommendation>
<example>
<p>
In the following example, <code>ToString</code> is called explicitly on <code>o</code>,
before being passed to <code>string.Format</code>.
</p>
<sample src="RedundantToStringCallBad.cs" />
<p>
In the revised example, the call to <code>ToString</code> is omitted, as
<code>string.Format</code> will invoke <code>ToString</code> implicitly.
</p>
<sample src="RedundantToStringCallGood.cs" />
</example>
<references>
<li>MSDN: <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/addition-operator">+ Operator</a>, <a href="https://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx">String.Format method</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,19 @@
/**
* @name Redundant ToString() call
* @description Explicit calls to `ToString()` can be removed when the call
* appears in a context where an implicit conversion exists.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id cs/useless-tostring-call
* @tags maintainability
* useless-code
*/
import csharp
import semmle.code.csharp.commons.Strings
import semmle.code.csharp.frameworks.System
from MethodCall mc
where mc instanceof ImplicitToStringExpr
and mc.getTarget() instanceof ToStringMethod
select mc, "Redundant call to 'ToString'."

View File

@@ -0,0 +1,9 @@
using System;
class Bad
{
static string Hello(object o)
{
return string.Format("Hello, {0}!", o.ToString());
}
}

View File

@@ -0,0 +1,9 @@
using System;
class Good
{
static string Hello(object o)
{
return string.Format("Hello, {0}!", o);
}
}

View File

@@ -0,0 +1,21 @@
static void Main(string[] args)
{
using (var file = File.Open("values.xml", FileMode.Create))
using (var stream = new StreamWriter(file))
{
stream.WriteLine("<values>");
foreach (var arg in args)
{
uint value;
if (UInt32.TryParse(arg, out value))
stream.WriteLine(" <value>{0}</value>", value);
else
goto Finish; // Should be goto Error
}
goto Finish;
Error: // BAD: Unused label
Console.WriteLine("Error: All arguments must be non-negative integers");
Finish:
stream.WriteLine("</values>");
}
}

View File

@@ -0,0 +1,34 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>An unused label serves no purpose and clutters the source code. It could be an
indication that the code is incomplete, or that the code contains a bug where a
<code>goto</code> statement uses the wrong label.</p>
</overview>
<recommendation>
<p>Ensure that all <code>goto</code> statements use the correct label, and remove the
label if it is no longer needed.</p>
<p>Another solution is to rewrite the code without <code>goto</code> statements, which can
often be much clearer.</p>
</recommendation>
<example>
<p>The following example has an unused label <code>Error</code>, which means that the error message
is never displayed. The code can be fixed by either jumping to the correct label, or by rewriting
the code without <code>goto</code> statements.</p>
<sample src="UnusedLabel.cs"/>
</example>
<references>
<li>MSDN, C# Reference: <a href="https://msdn.microsoft.com/en-us/library/13940fs2.aspx">goto</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,16 @@
/**
* @name Unused label
* @description An unused label serves no purpose and should be removed.
* @kind problem
* @problem.severity warning
* @precision high
* @id cs/unused-label
* @tags maintainability
* useless-code
*/
import csharp
from LabelStmt label
where not exists(GotoLabelStmt goto | label=goto.getTarget())
select label, "This label is not used."