mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
QL code and tests for C#/C++/JavaScript.
This commit is contained in:
43
csharp/ql/src/Useless code/DefaultToString.qhelp
Normal file
43
csharp/ql/src/Useless code/DefaultToString.qhelp
Normal 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>
|
||||
64
csharp/ql/src/Useless code/DefaultToString.ql
Normal file
64
csharp/ql/src/Useless code/DefaultToString.ql
Normal 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()
|
||||
23
csharp/ql/src/Useless code/DefaultToStringBad.cs
Normal file
23
csharp/ql/src/Useless code/DefaultToStringBad.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
csharp/ql/src/Useless code/DefaultToStringGood.cs
Normal file
25
csharp/ql/src/Useless code/DefaultToStringGood.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
19
csharp/ql/src/Useless code/FutileConditional.cs
Normal file
19
csharp/ql/src/Useless code/FutileConditional.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
22
csharp/ql/src/Useless code/FutileConditional.qhelp
Normal file
22
csharp/ql/src/Useless code/FutileConditional.qhelp
Normal 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>
|
||||
27
csharp/ql/src/Useless code/FutileConditional.ql
Normal file
27
csharp/ql/src/Useless code/FutileConditional.ql
Normal 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."
|
||||
4
csharp/ql/src/Useless code/IntGetHashCode.cs
Normal file
4
csharp/ql/src/Useless code/IntGetHashCode.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return row.GetHashCode() ^ col.GetHashCode();
|
||||
}
|
||||
41
csharp/ql/src/Useless code/IntGetHashCode.qhelp
Normal file
41
csharp/ql/src/Useless code/IntGetHashCode.qhelp
Normal 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>
|
||||
19
csharp/ql/src/Useless code/IntGetHashCode.ql
Normal file
19
csharp/ql/src/Useless code/IntGetHashCode.ql
Normal 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."
|
||||
4
csharp/ql/src/Useless code/IntGetHashCodeFix.cs
Normal file
4
csharp/ql/src/Useless code/IntGetHashCodeFix.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return unchecked(row * 16777619 + col);
|
||||
}
|
||||
17
csharp/ql/src/Useless code/PointlessForwardingMethod.cs
Normal file
17
csharp/ql/src/Useless code/PointlessForwardingMethod.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
28
csharp/ql/src/Useless code/PointlessForwardingMethod.qhelp
Normal file
28
csharp/ql/src/Useless code/PointlessForwardingMethod.qhelp
Normal 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>
|
||||
55
csharp/ql/src/Useless code/PointlessForwardingMethod.ql
Normal file
55
csharp/ql/src/Useless code/PointlessForwardingMethod.ql
Normal 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()
|
||||
13
csharp/ql/src/Useless code/PointlessForwardingMethodFix.cs
Normal file
13
csharp/ql/src/Useless code/PointlessForwardingMethodFix.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
37
csharp/ql/src/Useless code/RedundantToStringCall.qhelp
Normal file
37
csharp/ql/src/Useless code/RedundantToStringCall.qhelp
Normal 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>
|
||||
19
csharp/ql/src/Useless code/RedundantToStringCall.ql
Normal file
19
csharp/ql/src/Useless code/RedundantToStringCall.ql
Normal 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'."
|
||||
9
csharp/ql/src/Useless code/RedundantToStringCallBad.cs
Normal file
9
csharp/ql/src/Useless code/RedundantToStringCallBad.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
class Bad
|
||||
{
|
||||
static string Hello(object o)
|
||||
{
|
||||
return string.Format("Hello, {0}!", o.ToString());
|
||||
}
|
||||
}
|
||||
9
csharp/ql/src/Useless code/RedundantToStringCallGood.cs
Normal file
9
csharp/ql/src/Useless code/RedundantToStringCallGood.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
class Good
|
||||
{
|
||||
static string Hello(object o)
|
||||
{
|
||||
return string.Format("Hello, {0}!", o);
|
||||
}
|
||||
}
|
||||
21
csharp/ql/src/Useless code/UnusedLabel.cs
Normal file
21
csharp/ql/src/Useless code/UnusedLabel.cs
Normal 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>");
|
||||
}
|
||||
}
|
||||
34
csharp/ql/src/Useless code/UnusedLabel.qhelp
Normal file
34
csharp/ql/src/Useless code/UnusedLabel.qhelp
Normal 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>
|
||||
16
csharp/ql/src/Useless code/UnusedLabel.ql
Normal file
16
csharp/ql/src/Useless code/UnusedLabel.ql
Normal 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."
|
||||
Reference in New Issue
Block a user