Force LF for basically everything.

This commit is contained in:
Dave Bartolomeo
2018-09-20 11:53:27 -07:00
parent aa267c8302
commit 26abf5d4a2
64 changed files with 2313 additions and 2298 deletions

View File

@@ -1,2 +1,2 @@
[*.{ql,qll,qlref,dbscheme,qhelp,html,js,mjs,ts,json,yml,c,cpp,h,hpp}] [*]
end_of_line = lf end_of_line = lf

13
.gitattributes vendored
View File

@@ -16,12 +16,25 @@
*.dbscheme eol=lf *.dbscheme eol=lf
*.qhelp eol=lf *.qhelp eol=lf
*.html eol=lf *.html eol=lf
*.htm eol=lf
*.xhtml eol=lf
*.xhtm eol=lf
*.js eol=lf *.js eol=lf
*.mjs eol=lf *.mjs eol=lf
*.ts eol=lf *.ts eol=lf
*.json eol=lf *.json eol=lf
*.yml eol=lf *.yml eol=lf
*.yaml eol=lf
*.c eol=lf *.c eol=lf
*.cpp eol=lf *.cpp eol=lf
*.h eol=lf *.h eol=lf
*.hpp eol=lf *.hpp eol=lf
*.md eol=lf
*.stats eol=lf
*.xml eol=lf
*.sh eol=lf
*.pl eol=lf
*.java eol=lf
*.cs eol=lf
*.py eol=lf
*.lua eol=lf

View File

@@ -1,20 +1,20 @@
# Improvements to C/C++ analysis # Improvements to C/C++ analysis
## General improvements ## General improvements
## New queries ## New queries
| **Query** | **Tags** | **Purpose** | | **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------| |-----------------------------|-----------|--------------------------------------------------------------------|
| *@name of query (Query ID)* | *Tags* |*Aim of the new query and whether it is enabled by default or not* | | *@name of query (Query ID)* | *Tags* |*Aim of the new query and whether it is enabled by default or not* |
## Changes to existing queries ## Changes to existing queries
| **Query** | **Expected impact** | **Change** | | **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------| |----------------------------|------------------------|------------------------------------------------------------------|
| Resource not released in destructor | Fewer false positive results | Placement new is now excluded from the query. | | Resource not released in destructor | Fewer false positive results | Placement new is now excluded from the query. |
## Changes to QL libraries ## Changes to QL libraries
* Added a hash consing library for structural comparison of expressions. * Added a hash consing library for structural comparison of expressions.

View File

@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?> <?eclipse version="3.2"?>
<plugin> <plugin>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="semmlecode-cpp-queries"/> <name value="semmlecode-cpp-queries"/>
</extension> </extension>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.cpp.library"/> <name value="com.semmle.code.cpp.library"/>
</extension> </extension>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.cpp.dbscheme"/> <name value="com.semmle.code.cpp.dbscheme"/>
<path value="/semmlecode.cpp.dbscheme"/> <path value="/semmlecode.cpp.dbscheme"/>
</extension> </extension>
</plugin> </plugin>

View File

@@ -1,137 +1,137 @@
import sys import sys
import os.path import os.path
import glob import glob
import re import re
import json import json
BEGIN_TEMPLATE = re.compile(r"^/\*template\s*$") BEGIN_TEMPLATE = re.compile(r"^/\*template\s*$")
END_TEMPLATE = re.compile(r"^\*/\s*$") END_TEMPLATE = re.compile(r"^\*/\s*$")
def expand_template_params(args, param_arg_map): def expand_template_params(args, param_arg_map):
'''Given a list of template arguments that may reference template parameters '''Given a list of template arguments that may reference template parameters
of the current template, return a new list of template arguments with each of the current template, return a new list of template arguments with each
parameter use replaced with the appropriate fully-qualified argument for parameter use replaced with the appropriate fully-qualified argument for
that parameter.''' that parameter.'''
result = [] result = []
for arg in args: for arg in args:
if arg in param_arg_map: if arg in param_arg_map:
result.append(param_arg_map[arg]) result.append(param_arg_map[arg])
else: else:
result.append(arg) result.append(arg)
return result return result
def find_instantiation(module, args, templates): def find_instantiation(module, args, templates):
'''Given a template module and a set of template arguments, find the module '''Given a template module and a set of template arguments, find the module
name of the instantiation of that module with those arguments.''' name of the instantiation of that module with those arguments.'''
template = templates[module] template = templates[module]
for instantiation in template["template_def"]["instantiations"]: for instantiation in template["template_def"]["instantiations"]:
if instantiation["args"] == args: if instantiation["args"] == args:
return instantiation["name"] return instantiation["name"]
return None return None
def instantiate_template(template, instantiation, root, templates): def instantiate_template(template, instantiation, root, templates):
'''Create a single instantiation of a template.''' '''Create a single instantiation of a template.'''
template_def = template["template_def"] template_def = template["template_def"]
output_components = instantiation["name"].split(".") output_components = instantiation["name"].split(".")
output_path = root output_path = root
for component in output_components: for component in output_components:
output_path = os.path.join(output_path, component) output_path = os.path.join(output_path, component)
output_path = output_path + ".qll" output_path = output_path + ".qll"
with open(output_path, "w") as output: with open(output_path, "w") as output:
output.write( output.write(
""" """
/* /*
* THIS FILE IS AUTOMATICALLY GENERATED FROM '%s'. * THIS FILE IS AUTOMATICALLY GENERATED FROM '%s'.
* DO NOT EDIT MANUALLY. * DO NOT EDIT MANUALLY.
*/ */
""" % (template["name"].replace(".", "/") + ".qllt") """ % (template["name"].replace(".", "/") + ".qllt")
) )
param_arg_map = {} param_arg_map = {}
for param_index in range(len(template_def["params"])): for param_index in range(len(template_def["params"])):
param = template_def["params"][param_index] param = template_def["params"][param_index]
arg = instantiation["args"][param_index] arg = instantiation["args"][param_index]
output.write("private import %s as %s // Template parameter\n" % (arg, param)) output.write("private import %s as %s // Template parameter\n" % (arg, param))
param_arg_map[param] = arg param_arg_map[param] = arg
for import_record in template_def["imports"]: for import_record in template_def["imports"]:
if "access" in import_record: if "access" in import_record:
output.write(import_record["access"] + " ") output.write(import_record["access"] + " ")
imported_module = find_instantiation(import_record["module"], imported_module = find_instantiation(import_record["module"],
expand_template_params(import_record["args"], param_arg_map), templates) expand_template_params(import_record["args"], param_arg_map), templates)
output.write("import %s // %s<%s>\n" % output.write("import %s // %s<%s>\n" %
( (
imported_module, imported_module,
import_record["module"], import_record["module"],
", ".join(import_record["args"]) ", ".join(import_record["args"])
) )
) )
output.writelines(template_def["body_lines"]) output.writelines(template_def["body_lines"])
def generate_instantiations(template, root, templates): def generate_instantiations(template, root, templates):
'''Create a .qll source file for each instantiation of the specified template.''' '''Create a .qll source file for each instantiation of the specified template.'''
template_def = template["template_def"] template_def = template["template_def"]
if "instantiations" in template_def: if "instantiations" in template_def:
for instantiation in template_def["instantiations"]: for instantiation in template_def["instantiations"]:
instantiate_template(template, instantiation, root, templates) instantiate_template(template, instantiation, root, templates)
def read_template(template_path, module_name): def read_template(template_path, module_name):
'''Read a .qllt template file from template_path, using module_name as the '''Read a .qllt template file from template_path, using module_name as the
fully qualified name of the module.''' fully qualified name of the module.'''
with open(template_path) as input: with open(template_path) as input:
in_template = False in_template = False
template_text = "" template_text = ""
template_def = None template_def = None
body_lines = [] body_lines = []
for line in iter(input): for line in iter(input):
if in_template: if in_template:
if END_TEMPLATE.match(line): if END_TEMPLATE.match(line):
template_def = json.loads(template_text) template_def = json.loads(template_text)
in_template = False in_template = False
else: else:
template_text += line template_text += line
else: else:
if BEGIN_TEMPLATE.match(line) and not template_def: if BEGIN_TEMPLATE.match(line) and not template_def:
in_template = True in_template = True
else: else:
body_lines.append(line) body_lines.append(line)
if template_def: if template_def:
template_def["body_lines"] = body_lines template_def["body_lines"] = body_lines
result = { "name": module_name } result = { "name": module_name }
if template_def: if template_def:
result["template_def"] = template_def result["template_def"] = template_def
return result return result
def module_name_from_path_impl(path): def module_name_from_path_impl(path):
(head, tail) = os.path.split(path) (head, tail) = os.path.split(path)
if head == "": if head == "":
return tail return tail
else: else:
return module_name_from_path(head) + "." + tail return module_name_from_path(head) + "." + tail
def module_name_from_path(path): def module_name_from_path(path):
'''Compute the fully qualified name of a module from the path of its .qll[t] '''Compute the fully qualified name of a module from the path of its .qll[t]
file. The path should be relative to the library root.''' file. The path should be relative to the library root.'''
(module_root, ext) = os.path.splitext(path) (module_root, ext) = os.path.splitext(path)
return module_name_from_path_impl(module_root) return module_name_from_path_impl(module_root)
def main(): def main():
templates = {} templates = {}
root = sys.argv[1] root = sys.argv[1]
for template_path in glob.glob(os.path.join(root, "**\\*.qllt"), recursive = True): for template_path in glob.glob(os.path.join(root, "**\\*.qllt"), recursive = True):
print(template_path) print(template_path)
module_name = module_name_from_path(os.path.relpath(template_path, root)) module_name = module_name_from_path(os.path.relpath(template_path, root))
print(module_name) print(module_name)
template = read_template(template_path, module_name) template = read_template(template_path, module_name)
templates[template["name"]] = template templates[template["name"]] = template
for name, template in templates.items(): for name, template in templates.items():
if "template_def" in template: if "template_def" in template:
generate_instantiations(template, root, templates) generate_instantiations(template, root, templates)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?> <?eclipse version="3.2"?>
<plugin> <plugin>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="semmlecode-csharp-queries"/> <name value="semmlecode-csharp-queries"/>
</extension> </extension>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.csharp.library"/> <name value="com.semmle.code.csharp.library"/>
</extension> </extension>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.csharp.dbscheme"/> <name value="com.semmle.code.csharp.dbscheme"/>
<path value="/semmlecode.csharp.dbscheme"/> <path value="/semmlecode.csharp.dbscheme"/>
</extension> </extension>
</plugin> </plugin>

View File

@@ -1,14 +1,14 @@
// semmle-extractor-options: --standalone // semmle-extractor-options: --standalone
using System; using System;
class Cfg class Cfg
{ {
void F() void F()
{ {
var v = new InvalidType(); var v = new InvalidType();
Debug.Assert(v.a.b, "This is true"); Debug.Assert(v.a.b, "This is true");
new CounterCreationData() { CounterHelp = string.Empty, CounterType = v.Type }; new CounterCreationData() { CounterHelp = string.Empty, CounterType = v.Type };
} }
} }

View File

@@ -1,417 +1,417 @@
# QL Style Guide # QL Style Guide
## Introduction ## Introduction
This document describes how to format the QL code you contribute to this repository. It covers aspects such as layout, white-space, naming and documentation. Adhering to consistent standards makes code easier to read and maintain. Of course, these are only guidelines, and can be overridden as the need arises on a case-by-case basis. Where existing code deviates from these guidelines, prefer consistency with the surrounding code. This document describes how to format the QL code you contribute to this repository. It covers aspects such as layout, white-space, naming and documentation. Adhering to consistent standards makes code easier to read and maintain. Of course, these are only guidelines, and can be overridden as the need arises on a case-by-case basis. Where existing code deviates from these guidelines, prefer consistency with the surrounding code.
Words in *italic* are defined in the [Glossary](#glossary). Words in *italic* are defined in the [Glossary](#glossary).
## Indentation ## Indentation
1. *Always* use 2 spaces for indentation. 1. *Always* use 2 spaces for indentation.
1. *Always* indent: 1. *Always* indent:
- The *body* of a module, newtype, class or predicate - The *body* of a module, newtype, class or predicate
- The second and subsequent lines after you use a line break to split a long line - The second and subsequent lines after you use a line break to split a long line
- The *body* of a `from`, `where` or `select` clause where it spans multiple lines - The *body* of a `from`, `where` or `select` clause where it spans multiple lines
- The *body* of a *quantifier* that spans multiple lines - The *body* of a *quantifier* that spans multiple lines
### Examples ### Examples
```ql ```ql
module Helpers { module Helpers {
/** ... */ /** ... */
class X ... { class X ... {
/** ... */ /** ... */
int getNumberOfChildren () { int getNumberOfChildren () {
result = count(int child | result = count(int child |
exists(this.getChild(child)) exists(this.getChild(child))
) )
} }
} }
} }
``` ```
```ql ```ql
from Call c, string reason from Call c, string reason
where isDeprecated(c, reason) where isDeprecated(c, reason)
select c, "This call to '$@' is deprecated because " + reason + ".", select c, "This call to '$@' is deprecated because " + reason + ".",
c.getTarget(), c.getTarget().getName() c.getTarget(), c.getTarget().getName()
``` ```
## Line breaks ## Line breaks
1. Use UNIX line endings. 1. Use UNIX line endings.
1. Lines *must not* exceed 100 characters. 1. Lines *must not* exceed 100 characters.
1. Long lines *should* be split with a line break, and the following lines *must* be indented one level until the next "regular" line break. 1. Long lines *should* be split with a line break, and the following lines *must* be indented one level until the next "regular" line break.
1. There *should* be a single blank line: 1. There *should* be a single blank line:
- Between the file documentation and the first `import` - Between the file documentation and the first `import`
- Before each declaration, except for the first declaration in a *body* - Before each declaration, except for the first declaration in a *body*
- Before the `from`-`where`-`select` section in a query file - Before the `from`-`where`-`select` section in a query file
1. *Avoid* two or more adjacent blank lines. 1. *Avoid* two or more adjacent blank lines.
1. There *must* be a new line after the *annotations* `cached`, `pragma`, `language` and `bindingset`. Other *annotations* do not have a new line. 1. There *must* be a new line after the *annotations* `cached`, `pragma`, `language` and `bindingset`. Other *annotations* do not have a new line.
1. There *should not* be additional blank lines within a predicate. 1. There *should not* be additional blank lines within a predicate.
1. There *may* be a new line: 1. There *may* be a new line:
- Immediately after the `from`, `where` or `select` keywords in a query. - Immediately after the `from`, `where` or `select` keywords in a query.
- Immediately after `if`, `then`, or `else` keywords. The `then` and `else` parts *should* be consistent. - Immediately after `if`, `then`, or `else` keywords. The `then` and `else` parts *should* be consistent.
1. *Avoid* other line breaks in declarations, other than to break long lines. 1. *Avoid* other line breaks in declarations, other than to break long lines.
1. When operands of *binary operators* span two lines, the operator *should* be placed at the end of the first line. 1. When operands of *binary operators* span two lines, the operator *should* be placed at the end of the first line.
### Examples ### Examples
```ql ```ql
cached cached
private int getNumberOfParameters() { private int getNumberOfParameters() {
... ...
} }
``` ```
```ql ```ql
predicate methodStats(string qualifiedName, string name, predicate methodStats(string qualifiedName, string name,
int numberOfParameters, int numberOfStatements, int numberOfExpressions, int numberOfParameters, int numberOfStatements, int numberOfExpressions,
int linesOfCode, int nestingDepth, int numberOfBranches) { int linesOfCode, int nestingDepth, int numberOfBranches) {
... ...
} }
``` ```
```ql ```ql
from Method main from Method main
where main.getName() = "Main" where main.getName() = "Main"
select main, "This is the program entry point." select main, "This is the program entry point."
``` ```
```ql ```ql
from Method main from Method main
where where
main.getName() = "Main" and main.getName() = "Main" and
main.getNumberOfParameters() = 0 main.getNumberOfParameters() = 0
select main, "Main method has no parameters." select main, "Main method has no parameters."
``` ```
```ql ```ql
if x.isPublic() if x.isPublic()
then result = "public" then result = "public"
else result = "private" else result = "private"
``` ```
```ql ```ql
if x.isPublic() then if x.isPublic() then
result = "public" result = "public"
else else
result = "private" result = "private"
``` ```
```ql ```ql
if if
x.isPublic() x.isPublic()
then then
result = "public" result = "public"
else else
result = "private" result = "private"
``` ```
## Braces ## Braces
1. Braces follow [Stroustrup](https://en.wikipedia.org/wiki/Indentation_style#Variant:_Stroustrup) style. The opening `{` *must* be placed at the end of the preceding line. 1. Braces follow [Stroustrup](https://en.wikipedia.org/wiki/Indentation_style#Variant:_Stroustrup) style. The opening `{` *must* be placed at the end of the preceding line.
1. The closing `}` *must* be placed on its own line, indented to the outer level, or be on the same line as the opening `{`. 1. The closing `}` *must* be placed on its own line, indented to the outer level, or be on the same line as the opening `{`.
1. Braces of empty blocks *may* be placed on a single line, with a single space separating the braces. 1. Braces of empty blocks *may* be placed on a single line, with a single space separating the braces.
1. Short predicates, not exceeding the maximum line width, *may* be placed on a single line, with a space following the opening brace and preceding the closing brace. 1. Short predicates, not exceeding the maximum line width, *may* be placed on a single line, with a space following the opening brace and preceding the closing brace.
### Examples ### Examples
```ql ```ql
class ThrowException extends ThrowExpr { class ThrowException extends ThrowExpr {
Foo() { Foo() {
this.getTarget() instanceof ExceptionClass this.getTarget() instanceof ExceptionClass
} }
override string toString() { result = "Throw Exception" } override string toString() { result = "Throw Exception" }
} }
``` ```
## Spaces ## Spaces
1. There *must* be a space or line break: 1. There *must* be a space or line break:
- Surrounding each `=` and `|` - Surrounding each `=` and `|`
- After each `,` - After each `,`
1. There *should* be a space or line break: 1. There *should* be a space or line break:
- Surrounding each *binary operator*, which *must* be balanced - Surrounding each *binary operator*, which *must* be balanced
- Surrounding `..` in a range - Surrounding `..` in a range
- Exceptions to this may be made to save space or to improve readability. - Exceptions to this may be made to save space or to improve readability.
1. *Avoid* other spaces, for example: 1. *Avoid* other spaces, for example:
- After a *quantifier/aggregation* keyword - After a *quantifier/aggregation* keyword
- After the predicate name in a *call* - After the predicate name in a *call*
- Inside brackets used for *calls*, single-line quantifiers, and parenthesised formulas - Inside brackets used for *calls*, single-line quantifiers, and parenthesised formulas
- Surrounding a `.` - Surrounding a `.`
- Inside the opening or closing `[ ]` in a range expression - Inside the opening or closing `[ ]` in a range expression
- Inside casts `a.(X)` - Inside casts `a.(X)`
1. *Avoid* multiple spaces, except for indentation, and *avoid* additional indentation to align formulas, parameters or arguments. 1. *Avoid* multiple spaces, except for indentation, and *avoid* additional indentation to align formulas, parameters or arguments.
1. *Do not* put whitespace on blank lines, or trailing on the end of a line. 1. *Do not* put whitespace on blank lines, or trailing on the end of a line.
1. *Do not* use tabs. 1. *Do not* use tabs.
### Examples ### Examples
```ql ```ql
cached cached
private predicate foo(Expr e, Expr p) { private predicate foo(Expr e, Expr p) {
exists(int n | exists(int n |
n in [0 .. 1] | n in [0 .. 1] |
e = p.getChild(n + 1) e = p.getChild(n + 1)
) )
} }
``` ```
## Naming ## Naming
1. Use [PascalCase](http://wiki.c2.com/?PascalCase) for: 1. Use [PascalCase](http://wiki.c2.com/?PascalCase) for:
- `class` names - `class` names
- `module` names - `module` names
- `newtype` names - `newtype` names
1. Use [camelCase](https://en.wikipedia.org/wiki/Camel_case) for: 1. Use [camelCase](https://en.wikipedia.org/wiki/Camel_case) for:
- Predicate names - Predicate names
- Variable names - Variable names
1. Newtype predicate names *should* begin with `T`. 1. Newtype predicate names *should* begin with `T`.
1. Predicates that have a result *should* be named `get...` 1. Predicates that have a result *should* be named `get...`
1. Predicates that can return multiple results *should* be named `getA...` or `getAn...` 1. Predicates that can return multiple results *should* be named `getA...` or `getAn...`
1. Predicates that don't have a result or parameters *should* be named `is...` or `has...` 1. Predicates that don't have a result or parameters *should* be named `is...` or `has...`
1. *Avoid* underscores in names. 1. *Avoid* underscores in names.
1. *Avoid* short or single-letter names for classes, predicates and fields. 1. *Avoid* short or single-letter names for classes, predicates and fields.
1. Short or single letter names for parameters and *quantifiers* *may* be used provided that they are sufficiently clear. 1. Short or single letter names for parameters and *quantifiers* *may* be used provided that they are sufficiently clear.
1. Use names as they are used in the target-language specification. 1. Use names as they are used in the target-language specification.
1. Use American English. 1. Use American English.
### Examples ### Examples
```ql ```ql
/** ... */ /** ... */
predicate calls(Callable caller, Callable callee) { predicate calls(Callable caller, Callable callee) {
... ...
} }
``` ```
```ql ```ql
/** ... */ /** ... */
class Type extends ... { class Type extends ... {
/** ... */ /** ... */
string getName() { ... } string getName() { ... }
/** ... */ /** ... */
predicate declares(Member m) { ... } predicate declares(Member m) { ... }
/** ... */ /** ... */
predicate isGeneric() { ... } predicate isGeneric() { ... }
/** ... */ /** ... */
Type getTypeParameter(int n) { ... } Type getTypeParameter(int n) { ... }
/** ... */ /** ... */
Type getATypeParameter() { ... } Type getATypeParameter() { ... }
} }
``` ```
## Documentation ## Documentation
General requirements: General requirements:
1. Documentation *must* adhere to the [QLDoc specification](https://help.semmle.com/QL/QLDocSpecification.html). 1. Documentation *must* adhere to the [QLDoc specification](https://help.semmle.com/QL/QLDocSpecification.html).
1. Use `/** ... */` for documentation, even for single line comments. 1. Use `/** ... */` for documentation, even for single line comments.
1. For single-line documentation, the `/**` and `*/` are written on the same line as the comment. 1. For single-line documentation, the `/**` and `*/` are written on the same line as the comment.
1. For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. 1. For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`.
1. Use full sentences, with capital letters and full stops. 1. Use full sentences, with capital letters and full stops.
1. Use American English. 1. Use American English.
1. Documentation comments *should* be appropriate for users of the code. 1. Documentation comments *should* be appropriate for users of the code.
1. Documentation for maintainers of the code *must* use normal comments. 1. Documentation for maintainers of the code *must* use normal comments.
Documentation for specific items: Documentation for specific items:
1. Public declarations *must* be documented. 1. Public declarations *must* be documented.
1. Non-public declarations *should* be documented. 1. Non-public declarations *should* be documented.
1. Declarations in query files *should* be documented. 1. Declarations in query files *should* be documented.
1. Library files (`.qll` files) *should* be have a documentation comment at the top of the file. 1. Library files (`.qll` files) *should* be have a documentation comment at the top of the file.
1. Query files, except for tests, *must* have a QLDoc query documentation comment at the top of the file. 1. Query files, except for tests, *must* have a QLDoc query documentation comment at the top of the file.
1. Predicates that do not have a result *should* be documented `/** Holds if ... */` 1. Predicates that do not have a result *should* be documented `/** Holds if ... */`
1. Predicates that have a result *should* be documented `/** Gets ... */` 1. Predicates that have a result *should* be documented `/** Gets ... */`
1. All predicate parameters *should* be referred to in the predicate documentation. 1. All predicate parameters *should* be referred to in the predicate documentation.
1. Reference names, such as types and parameters, using backticks `` ` ``. 1. Reference names, such as types and parameters, using backticks `` ` ``.
1. Give examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. 1. Give examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``.
1. Classes *should* be documented in the singular, for example `/* An expression. */` 1. Classes *should* be documented in the singular, for example `/* An expression. */`
1. Where a class denotes a generic concept with subclasses, list those subclasses. 1. Where a class denotes a generic concept with subclasses, list those subclasses.
1. Declarations that are deprecated *should* be documented as `DEPRECATED: ...` 1. Declarations that are deprecated *should* be documented as `DEPRECATED: ...`
1. Declarations that are for internal use *should* be documented as `INTERNAL: Do not use`. 1. Declarations that are for internal use *should* be documented as `INTERNAL: Do not use`.
### Examples ### Examples
```ql ```ql
/** Provides logic for determining constant expressions. */ /** Provides logic for determining constant expressions. */
``` ```
```ql ```ql
/** /**
* Holds if the qualifier of this call has type `qualifierType`. * Holds if the qualifier of this call has type `qualifierType`.
* `isExactType` indicates whether the type is exact, that is, whether * `isExactType` indicates whether the type is exact, that is, whether
* the qualifier is guaranteed not to be a subtype of `qualifierType`. * the qualifier is guaranteed not to be a subtype of `qualifierType`.
*/ */
``` ```
```ql ```ql
/** /**
* A delegate declaration, for example * A delegate declaration, for example
* ``` * ```
* delegate void Logger(string text); * delegate void Logger(string text);
* ``` * ```
*/ */
class Delegate extends ... class Delegate extends ...
``` ```
```ql ```ql
/** /**
* An element that can be called. * An element that can be called.
* *
* Either a method (`Method`), a constructor (`Constructor`), a destructor * Either a method (`Method`), a constructor (`Constructor`), a destructor
* (`Destructor`), an operator (`Operator`), an accessor (`Accessor`), * (`Destructor`), an operator (`Operator`), an accessor (`Accessor`),
* an anonymous function (`AnonymousFunctionExpr`), or a local function * an anonymous function (`AnonymousFunctionExpr`), or a local function
* (`LocalFunction`). * (`LocalFunction`).
*/ */
class Callable extends ... class Callable extends ...
``` ```
```ql ```ql
/** DEPRECATED: Use `getAnExpr()` instead. */ /** DEPRECATED: Use `getAnExpr()` instead. */
deprecated Expr getInitializer() deprecated Expr getInitializer()
``` ```
```ql ```ql
/** /**
* INTERNAL: Do not use. * INTERNAL: Do not use.
*/ */
``` ```
## Formulas ## Formulas
1. *Prefer* one *conjunct* per line. 1. *Prefer* one *conjunct* per line.
1. Write the `and` at the end of the line. This also applies in `where` clauses. 1. Write the `and` at the end of the line. This also applies in `where` clauses.
1. *Prefer* to write the `or` keyword on its own line. 1. *Prefer* to write the `or` keyword on its own line.
1. The `or` keyword *may* be written at the end of a line, or within a line, provided that it has no unparenthesised `and` operands. 1. The `or` keyword *may* be written at the end of a line, or within a line, provided that it has no unparenthesised `and` operands.
1. Single-line formulas *may* be used in order to save space or add clarity, particularly in the *body* of a *quantifier/aggregation*. 1. Single-line formulas *may* be used in order to save space or add clarity, particularly in the *body* of a *quantifier/aggregation*.
1. *Always* use brackets to clarify the precedence of: 1. *Always* use brackets to clarify the precedence of:
- `implies` - `implies`
- `if`-`then`-`else` - `if`-`then`-`else`
1. Parenthesised formulas *can* be written: 1. Parenthesised formulas *can* be written:
- Within a single line. There *should not* be an additional space following the opening parenthesis or preceding the closing parenthesis. - Within a single line. There *should not* be an additional space following the opening parenthesis or preceding the closing parenthesis.
- Spanning multiple lines. The opening parenthesis *should* be placed at the end of the preceding line, the body should be indented one level, and the closing bracket should be placed on a new line at the outer indentation. - Spanning multiple lines. The opening parenthesis *should* be placed at the end of the preceding line, the body should be indented one level, and the closing bracket should be placed on a new line at the outer indentation.
1. *Quantifiers/aggregations* *can* be written: 1. *Quantifiers/aggregations* *can* be written:
- Within a single line. In this case, there is no space to the inside of the parentheses, or after the quantifier keyword. - Within a single line. In this case, there is no space to the inside of the parentheses, or after the quantifier keyword.
- Across multiple lines. In this case, type declarations are on the same line as the quantifier, the `|` *may* be at the end of the line, or *may* be on its own line, and the body of the quantifier *must* be indented one level. The closing `)` is written on a new line, at the outer indentation. - Across multiple lines. In this case, type declarations are on the same line as the quantifier, the `|` *may* be at the end of the line, or *may* be on its own line, and the body of the quantifier *must* be indented one level. The closing `)` is written on a new line, at the outer indentation.
1. `if`-`then`-`else` *can* be written: 1. `if`-`then`-`else` *can* be written:
- On a single line - On a single line
- With the *body* after the `if`/`then`/`else` keyword - With the *body* after the `if`/`then`/`else` keyword
- With the *body* indented on the next line - With the *body* indented on the next line
- *Always* parenthesise the `else` part if it is a compound formula. - *Always* parenthesise the `else` part if it is a compound formula.
1. The `and` and `else` keywords *may* be placed on the same line as the closing parenthesis. 1. The `and` and `else` keywords *may* be placed on the same line as the closing parenthesis.
1. The `and` and `else` keywords *may* be "cuddled": `) else (` 1. The `and` and `else` keywords *may* be "cuddled": `) else (`
1. *Always* qualify *calls* to predicates of the same class with `this`. 1. *Always* qualify *calls* to predicates of the same class with `this`.
2. *Prefer* postfix casts `a.(Expr)` to prefix casts `(Expr)a`. 2. *Prefer* postfix casts `a.(Expr)` to prefix casts `(Expr)a`.
### Examples ### Examples
```ql ```ql
argumentType.isImplicitlyConvertibleTo(parameterType) argumentType.isImplicitlyConvertibleTo(parameterType)
or or
argumentType instanceof NullType and argumentType instanceof NullType and
result.getParameter(i).isOut() and result.getParameter(i).isOut() and
parameterType instanceof SimpleType parameterType instanceof SimpleType
or or
reflectionOrDynamicArg(argumentType, parameterType) reflectionOrDynamicArg(argumentType, parameterType)
``` ```
```ql ```ql
this.getName() = "Finalize" and not exists(this.getAParameter()) this.getName() = "Finalize" and not exists(this.getAParameter())
``` ```
```ql ```ql
e1.getType() instanceof BoolType and ( e1.getType() instanceof BoolType and (
b1 = true b1 = true
or or
b1 = false b1 = false
) and ( ) and (
b2 = true b2 = true
or or
b2 = false b2 = false
) )
``` ```
```ql ```ql
if e1 instanceof BitwiseOrExpr or e1 instanceof LogicalOrExpr then ( if e1 instanceof BitwiseOrExpr or e1 instanceof LogicalOrExpr then (
impliesSub(e1.(BinaryOperation).getAnOperand(), e2, b1, b2) and impliesSub(e1.(BinaryOperation).getAnOperand(), e2, b1, b2) and
b1 = false b1 = false
) else ( ) else (
e1.getType() instanceof BoolType and e1.getType() instanceof BoolType and
e1 = e2 and e1 = e2 and
b1 = b2 and b1 = b2 and
(b1 = true or b1 = false) (b1 = true or b1 = false)
) )
``` ```
```ql ```ql
(x instanceof Exception implies x.isPublic()) and y instanceof Exception (x instanceof Exception implies x.isPublic()) and y instanceof Exception
``` ```
```ql ```ql
x instanceof Exception implies (x.isPublic() and y instanceof Exception) x instanceof Exception implies (x.isPublic() and y instanceof Exception)
``` ```
```ql ```ql
exists(Type arg | arg = this.getAChild() | arg instanceof TypeParameter) exists(Type arg | arg = this.getAChild() | arg instanceof TypeParameter)
``` ```
```ql ```ql
exists(Type qualifierType | exists(Type qualifierType |
this.hasNonExactQualifierType(qualifierType) | this.hasNonExactQualifierType(qualifierType) |
result = getANonExactQualifierSubType(qualifierType) result = getANonExactQualifierSubType(qualifierType)
) )
``` ```
```ql ```ql
methods = count(Method m | t = m.getDeclaringType() and not ilc(m)) methods = count(Method m | t = m.getDeclaringType() and not ilc(m))
``` ```
```ql ```ql
if n = 0 then result = 1 else result = n * f(n - 1) if n = 0 then result = 1 else result = n * f(n - 1)
``` ```
```ql ```ql
if n = 0 if n = 0
then result = 1 then result = 1
else result = n * f(n - 1) else result = n * f(n - 1)
``` ```
```ql ```ql
if if
n = 0 n = 0
then then
result = 1 result = 1
else else
result = n * f(n - 1) result = n * f(n - 1)
``` ```
```ql ```ql
if exists(this.getContainingType()) then ( if exists(this.getContainingType()) then (
result = "A nested class" and result = "A nested class" and
parentName = this.getContainingType().getFullyQualifiedName() parentName = this.getContainingType().getFullyQualifiedName()
) else ( ) else (
result = parentName + "." + this.getName() and result = parentName + "." + this.getName() and
parentName = this.getNamespace().getFullyQualifiedName() parentName = this.getNamespace().getFullyQualifiedName()
) )
``` ```
## Glossary ## Glossary
| Phrase | Meaning | | Phrase | Meaning |
|-------------|----------| |-------------|----------|
| *[annotation](https://help.semmle.com/QL/QLLanguageSpecification.html#annotations)* | An additional specifier used to modify a declaration, such as `private`, `override`, `deprecated`, `pragma`, `bindingset`, or `cached`. | | *[annotation](https://help.semmle.com/QL/QLLanguageSpecification.html#annotations)* | An additional specifier used to modify a declaration, such as `private`, `override`, `deprecated`, `pragma`, `bindingset`, or `cached`. |
| *body* | The text inside `{ }`, `( )`, or each section of an `if`-`then`-`else` or `from`-`where`-`select`. | | *body* | The text inside `{ }`, `( )`, or each section of an `if`-`then`-`else` or `from`-`where`-`select`. |
| *binary operator* | An operator with two operands, such as comparison operators, `and`, `or`, `implies`, or arithmetic operators. | | *binary operator* | An operator with two operands, such as comparison operators, `and`, `or`, `implies`, or arithmetic operators. |
| *call* | A *formula* that invokes a predicate, e.g. `this.isStatic()` or `calls(a,b)`. | | *call* | A *formula* that invokes a predicate, e.g. `this.isStatic()` or `calls(a,b)`. |
| *[conjunct](https://help.semmle.com/QL/QLLanguageSpecification.html#conjunctions)* | A formula that is an operand to an `and`. | | *[conjunct](https://help.semmle.com/QL/QLLanguageSpecification.html#conjunctions)* | A formula that is an operand to an `and`. |
| *declaration* | A class, module, predicate, field or newtype. | | *declaration* | A class, module, predicate, field or newtype. |
| *[disjunct](https://help.semmle.com/QL/QLLanguageSpecification.html#disjunctions)* | A formula that is an operand to an `or`. | | *[disjunct](https://help.semmle.com/QL/QLLanguageSpecification.html#disjunctions)* | A formula that is an operand to an `or`. |
| *[formula](https://help.semmle.com/QL/QLLanguageSpecification.html#formulas)* | A logical expression, such as `A = B`, a *call*, a *quantifier*, `and`, `or`, `not`, `in` or `instanceof`. | | *[formula](https://help.semmle.com/QL/QLLanguageSpecification.html#formulas)* | A logical expression, such as `A = B`, a *call*, a *quantifier*, `and`, `or`, `not`, `in` or `instanceof`. |
| *should/should not/avoid/prefer* | Adhere to this rule wherever possible, where it makes sense. | | *should/should not/avoid/prefer* | Adhere to this rule wherever possible, where it makes sense. |
| *may/can* | This is a reasonable alternative, to be used with discretion. | | *may/can* | This is a reasonable alternative, to be used with discretion. |
| *must/always/do not* | Always adhere to this rule. | | *must/always/do not* | Always adhere to this rule. |
| *[quantifier/aggregation](https://help.semmle.com/QL/QLLanguageSpecification.html#aggregations)* | `exists`, `count`, `strictcount`, `any`, `forall`, `forex` and so on. | | *[quantifier/aggregation](https://help.semmle.com/QL/QLLanguageSpecification.html#aggregations)* | `exists`, `count`, `strictcount`, `any`, `forall`, `forex` and so on. |
| *variable* | A parameter to a predicate, a field, a from variable, or a variable introduced by a *quantifier* or *aggregation*. | | *variable* | A parameter to a predicate, a field, a from variable, or a variable introduced by a *quantifier* or *aggregation*. |

View File

@@ -1,28 +1,28 @@
<!--AVOID: 'shippingService' and 'orderService' share several properties with the same values--> <!--AVOID: 'shippingService' and 'orderService' share several properties with the same values-->
<bean id="shippingService" class="documentation.examples.spring.ShippingService"> <bean id="shippingService" class="documentation.examples.spring.ShippingService">
<property name="transactionHelper"> <property name="transactionHelper">
<ref bean="transactionHelper"/> <ref bean="transactionHelper"/>
</property> </property>
<property name="dao"> <property name="dao">
<ref bean="dao"/> <ref bean="dao"/>
</property> </property>
<property name="registry"> <property name="registry">
<ref bean="basicRegistry"/> <ref bean="basicRegistry"/>
</property> </property>
<property name="shippingProvider" value="Federal Parcel Service"/> <property name="shippingProvider" value="Federal Parcel Service"/>
</bean> </bean>
<bean id="orderService" class="documentation.examples.spring.OrderService"> <bean id="orderService" class="documentation.examples.spring.OrderService">
<property name="transactionHelper"> <property name="transactionHelper">
<ref bean="transactionHelper"/> <ref bean="transactionHelper"/>
</property> </property>
<property name="dao"> <property name="dao">
<ref bean="dao"/> <ref bean="dao"/>
</property> </property>
<property name="registry"> <property name="registry">
<ref bean="basicRegistry"/> <ref bean="basicRegistry"/>
</property> </property>
<property name="orderReference" value="8675309"/> <property name="orderReference" value="8675309"/>
</bean> </bean>

View File

@@ -1,8 +1,8 @@
<beans> <beans>
<!--Compose configuration files by using the 'import' element.--> <!--Compose configuration files by using the 'import' element.-->
<import resource="services.xml"/> <import resource="services.xml"/>
<import resource="resources/messageSource.xml"/> <import resource="resources/messageSource.xml"/>
<bean id="bean1" class="..."/> <bean id="bean1" class="..."/>
<bean id="bean2" class="..."/> <bean id="bean2" class="..."/>
</beans> </beans>

View File

@@ -1,6 +1,6 @@
<beans> <beans>
<!-- This bean is referred to, so is live. --> <!-- This bean is referred to, so is live. -->
<bean id="petStore" class="org.sample.PetStoreService"/> <bean id="petStore" class="org.sample.PetStoreService"/>
<!-- This bean is never referred to, so is dead. --> <!-- This bean is never referred to, so is dead. -->
<bean id="clinic" class="org.sample.ClinicService"/> <bean id="clinic" class="org.sample.ClinicService"/>
</beans> </beans>

View File

@@ -1,23 +1,23 @@
<beans> <beans>
<bean id="baseShippingService" abstract="true"> <bean id="baseShippingService" abstract="true">
<property name="transactionHelper"> <property name="transactionHelper">
<ref bean="transactionHelper"/> <ref bean="transactionHelper"/>
</property> </property>
<property name="dao"> <property name="dao">
<ref bean="dao"/> <ref bean="dao"/>
</property> </property>
<property name="registry"> <property name="registry">
<ref bean="basicRegistry"/> <ref bean="basicRegistry"/>
</property> </property>
</bean> </bean>
<bean id="shippingService" <bean id="shippingService"
class="documentation.examples.spring.ShippingService" class="documentation.examples.spring.ShippingService"
parent="baseShippingService"> parent="baseShippingService">
<!--AVOID: This property is already defined with the same value in the parent bean.--> <!--AVOID: This property is already defined with the same value in the parent bean.-->
<property name="registry"> <property name="registry">
<ref bean="basicRegistry"/> <ref bean="basicRegistry"/>
</property> </property>
<property name="shippingProvider" value="Federal Parcel Service"/> <property name="shippingProvider" value="Federal Parcel Service"/>
</bean> </bean>
</beans> </beans>

View File

@@ -1,13 +1,13 @@
<!--AVOID: Using autowiring makes it difficult to see the dependencies of the bean--> <!--AVOID: Using autowiring makes it difficult to see the dependencies of the bean-->
<bean id="autoWiredOrderService" <bean id="autoWiredOrderService"
class="documentation.examples.spring.OrderService" class="documentation.examples.spring.OrderService"
autowire="byName"/> autowire="byName"/>
<!--GOOD: Explicitly specifying the properties of the bean documents its dependencies <!--GOOD: Explicitly specifying the properties of the bean documents its dependencies
and makes the bean configuration easier to maintain--> and makes the bean configuration easier to maintain-->
<bean id="orderService" <bean id="orderService"
class="documentation.examples.spring.OrderService"> class="documentation.examples.spring.OrderService">
<property name="DAO"> <property name="DAO">
<idref bean="dao"/> <idref bean="dao"/>
</property> </property>
</bean> </bean>

View File

@@ -1,13 +1,13 @@
<!--AVOID: Using explicit constructor indices makes the bean configuration <!--AVOID: Using explicit constructor indices makes the bean configuration
vulnerable to changes to the constructor--> vulnerable to changes to the constructor-->
<bean id="billingService1" class="documentation.examples.spring.BillingService"> <bean id="billingService1" class="documentation.examples.spring.BillingService">
<constructor-arg index="0" value="John Doe"/> <constructor-arg index="0" value="John Doe"/>
<constructor-arg index="1" ref="dao"/> <constructor-arg index="1" ref="dao"/>
</bean> </bean>
<!--GOOD: Using type matching makes the bean configuration more robust to changes in <!--GOOD: Using type matching makes the bean configuration more robust to changes in
the constructor--> the constructor-->
<bean id="billingService2" class="documentation.examples.spring.BillingService"> <bean id="billingService2" class="documentation.examples.spring.BillingService">
<constructor-arg ref="dao"/> <constructor-arg ref="dao"/>
<constructor-arg type="java.lang.String" value="Jane Doe"/> <constructor-arg type="java.lang.String" value="Jane Doe"/>
</bean> </bean>

View File

@@ -1,26 +1,26 @@
<beans> <beans>
<import resource="services.xml"/> <import resource="services.xml"/>
<bean id="bean1" class="..."/> <bean id="bean1" class="..."/>
<bean id="bean2" class="..."/> <bean id="bean2" class="..."/>
<!--AVOID: Imports in the middle of a bean configuration make it difficult <!--AVOID: Imports in the middle of a bean configuration make it difficult
to immediately determine the dependencies of the configuration--> to immediately determine the dependencies of the configuration-->
<import resource="resources/messageSource.xml"/> <import resource="resources/messageSource.xml"/>
<bean id="bean3" class="..."/> <bean id="bean3" class="..."/>
<bean id="bean4" class="..."/> <bean id="bean4" class="..."/>
</beans> </beans>
<beans> <beans>
<!--GOOD: Having the imports at the top immediately gives an idea of <!--GOOD: Having the imports at the top immediately gives an idea of
what the dependencies of the configuration are--> what the dependencies of the configuration are-->
<import resource="services.xml"/> <import resource="services.xml"/>
<import resource="resources/messageSource.xml"/> <import resource="resources/messageSource.xml"/>
<bean id="bean1" class="..."/> <bean id="bean1" class="..."/>
<bean id="bean2" class="..."/> <bean id="bean2" class="..."/>
<bean id="bean3" class="..."/> <bean id="bean3" class="..."/>
<bean id="bean4" class="..."/> <bean id="bean4" class="..."/>
</beans> </beans>

View File

@@ -1,27 +1,27 @@
<beans> <beans>
<!--Using a description element makes it easier for tools to pick up <!--Using a description element makes it easier for tools to pick up
documentation of the bean configuration--> documentation of the bean configuration-->
<description> <description>
This file configures the various service beans. This file configures the various service beans.
</description> </description>
<!--You can also put a description element in a bean--> <!--You can also put a description element in a bean-->
<bean id="baseService" abstract="true"> <bean id="baseService" abstract="true">
<description> <description>
This bean defines base properties common to the service beans This bean defines base properties common to the service beans
</description> </description>
... ...
</bean> </bean>
<bean id="shippingService" <bean id="shippingService"
class="documentation.examples.spring.ShippingService" class="documentation.examples.spring.ShippingService"
parent="baseService"> parent="baseService">
... ...
</bean> </bean>
<bean id="orderService" <bean id="orderService"
class="documentation.examples.spring.OrderService" class="documentation.examples.spring.OrderService"
parent="baseService"> parent="baseService">
... ...
</bean> </bean>
</beans> </beans>

View File

@@ -1,16 +1,16 @@
<!--AVOID: Using the 'name' attribute disables checking of bean references at XML parse time--> <!--AVOID: Using the 'name' attribute disables checking of bean references at XML parse time-->
<bean name="dao" class="documentation.examples.spring.DAO"/> <bean name="dao" class="documentation.examples.spring.DAO"/>
<bean id="orderService" class="documentation.examples.spring.OrderService"> <bean id="orderService" class="documentation.examples.spring.OrderService">
<!--The XML parser cannot catch this typo--> <!--The XML parser cannot catch this typo-->
<property name="dao" ref="da0"/> <property name="dao" ref="da0"/>
</bean> </bean>
<!--GOOD: Using the 'id' attribute enables checking of bean references at XML parse time--> <!--GOOD: Using the 'id' attribute enables checking of bean references at XML parse time-->
<bean id="dao" class="documentation.examples.spring.DAO"/> <bean id="dao" class="documentation.examples.spring.DAO"/>
<bean id="orderService" class="documentation.examples.spring.OrderService"> <bean id="orderService" class="documentation.examples.spring.OrderService">
<!--The XML parser can catch this typo--> <!--The XML parser can catch this typo-->
<property name="dao" ref="da0"/> <property name="dao" ref="da0"/>
</bean> </bean>

View File

@@ -1,17 +1,17 @@
<beans> <beans>
<bean id="shippingService" class="documentation.examples.spring.ShippingService"> <bean id="shippingService" class="documentation.examples.spring.ShippingService">
<!--AVOID: This form of reference cannot be checked by the XML parser--> <!--AVOID: This form of reference cannot be checked by the XML parser-->
<property name="dao"> <property name="dao">
<ref bean="dao"/> <ref bean="dao"/>
</property> </property>
</bean> </bean>
<bean id="orderService" class="documentation.examples.spring.OrderService"> <bean id="orderService" class="documentation.examples.spring.OrderService">
<!--GOOD: This form of reference allows the XML parser to find any errors at parse time--> <!--GOOD: This form of reference allows the XML parser to find any errors at parse time-->
<property name="dao"> <property name="dao">
<idref local="dao"/> <idref local="dao"/>
</property> </property>
</bean> </bean>
<bean id="dao" class="documentation.examples.spring.DAO"/> <bean id="dao" class="documentation.examples.spring.DAO"/>
</beans> </beans>

View File

@@ -1,22 +1,22 @@
// Class for bean 'chart1' // Class for bean 'chart1'
public class WrongChartMaker { public class WrongChartMaker {
private AxisRenderer axisRenderer = new DefaultAxisRenderer(); private AxisRenderer axisRenderer = new DefaultAxisRenderer();
private TrendRenderer trendRenderer = new DefaultTrendRenderer(); private TrendRenderer trendRenderer = new DefaultTrendRenderer();
public WrongChartMaker() {} public WrongChartMaker() {}
// Each combination of the optional parameters must be represented by a constructor. // Each combination of the optional parameters must be represented by a constructor.
public WrongChartMaker(AxisRenderer customAxisRenderer) { public WrongChartMaker(AxisRenderer customAxisRenderer) {
this.axisRenderer = customAxisRenderer; this.axisRenderer = customAxisRenderer;
} }
public WrongChartMaker(TrendRenderer customTrendRenderer) { public WrongChartMaker(TrendRenderer customTrendRenderer) {
this.trendRenderer = customTrendRenderer; this.trendRenderer = customTrendRenderer;
} }
public WrongChartMaker(AxisRenderer customAxisRenderer, public WrongChartMaker(AxisRenderer customAxisRenderer,
TrendRenderer customTrendRenderer) { TrendRenderer customTrendRenderer) {
this.axisRenderer = customAxisRenderer; this.axisRenderer = customAxisRenderer;
this.trendRenderer = customTrendRenderer; this.trendRenderer = customTrendRenderer;
} }
} }

View File

@@ -1,38 +1,38 @@
<!--AVOID: Using nested 'value' elements can make the configuration file difficult to read--> <!--AVOID: Using nested 'value' elements can make the configuration file difficult to read-->
<bean id="serviceRegistry" class="documentation.examples.spring.ServiceRegistry"> <bean id="serviceRegistry" class="documentation.examples.spring.ServiceRegistry">
<constructor-arg type="java.lang.String"> <constructor-arg type="java.lang.String">
<value>main_service_registry</value> <value>main_service_registry</value>
</constructor-arg> </constructor-arg>
<property name="description"> <property name="description">
<value>Top-level registry for services</value> <value>Top-level registry for services</value>
</property> </property>
<property name="serviceMap"> <property name="serviceMap">
<map> <map>
<entry> <entry>
<key> <key>
<value>orderService</value> <value>orderService</value>
</key> </key>
<value>com.foo.bar.OrderService</value> <value>com.foo.bar.OrderService</value>
</entry> </entry>
<entry> <entry>
<key> <key>
<value>billingService</value> <value>billingService</value>
</key> </key>
<value>com.foo.bar.BillingService</value> <value>com.foo.bar.BillingService</value>
</entry> </entry>
</map> </map>
</property> </property>
</bean> </bean>
<!--GOOD: Shortcut forms (Spring 1.2) result in more concise bean definitions--> <!--GOOD: Shortcut forms (Spring 1.2) result in more concise bean definitions-->
<bean id="serviceRegistry" class="documentation.examples.spring.ServiceRegistry"> <bean id="serviceRegistry" class="documentation.examples.spring.ServiceRegistry">
<constructor-arg type="java.lang.String" value="main_service_registry"/> <constructor-arg type="java.lang.String" value="main_service_registry"/>
<property name="description" value="Top-level registry for services"/> <property name="description" value="Top-level registry for services"/>
<property name="serviceMap"> <property name="serviceMap">
<map> <map>
<entry key="orderService" value="com.foo.bar.OrderService"/> <entry key="orderService" value="com.foo.bar.OrderService"/>
<entry key="billingService" value="com.foo.bar.BillingService"/> <entry key="billingService" value="com.foo.bar.BillingService"/>
</map> </map>
</property> </property>
</bean> </bean>

View File

@@ -1,9 +1,9 @@
// bean class // bean class
public class ContentService { public class ContentService {
private TransactionHelper helper; private TransactionHelper helper;
// This method does not match the property in the bean file. // This method does not match the property in the bean file.
public void setHelper(TransactionHelper helper) { public void setHelper(TransactionHelper helper) {
this.helper = helper; this.helper = helper;
} }
} }

View File

@@ -1,7 +1,7 @@
<bean id="contentService" class="documentation.examples.spring.ContentService"> <bean id="contentService" class="documentation.examples.spring.ContentService">
<!--BAD: The setter method in the class is 'setHelper', so this property <!--BAD: The setter method in the class is 'setHelper', so this property
does not match the setter method.--> does not match the setter method.-->
<property name="transactionHelper"> <property name="transactionHelper">
<ref bean="transactionHelper"/> <ref bean="transactionHelper"/>
</property> </property>
</bean> </bean>

View File

@@ -1,17 +1,17 @@
public static void main(String args[]) { public static void main(String args[]) {
Random r = new Random(); Random r = new Random();
// BAD: 'mayBeNegativeInt' is negative if // BAD: 'mayBeNegativeInt' is negative if
// 'nextInt()' returns 'Integer.MIN_VALUE'. // 'nextInt()' returns 'Integer.MIN_VALUE'.
int mayBeNegativeInt = Math.abs(r.nextInt()); int mayBeNegativeInt = Math.abs(r.nextInt());
// GOOD: 'nonNegativeInt' is always a value between 0 (inclusive) // GOOD: 'nonNegativeInt' is always a value between 0 (inclusive)
// and Integer.MAX_VALUE (exclusive). // and Integer.MAX_VALUE (exclusive).
int nonNegativeInt = r.nextInt(Integer.MAX_VALUE); int nonNegativeInt = r.nextInt(Integer.MAX_VALUE);
// GOOD: When 'nextInt' returns a negative number increment the returned value. // GOOD: When 'nextInt' returns a negative number increment the returned value.
int nextInt = r.nextInt(); int nextInt = r.nextInt();
if(nextInt < 0) if(nextInt < 0)
nextInt++; nextInt++;
int nonNegativeInt = Math.abs(nextInt); int nonNegativeInt = Math.abs(nextInt);
} }

View File

@@ -1,12 +1,12 @@
public static void main(String args[]) { public static void main(String args[]) {
// BAD: A new 'Random' object is created every time // BAD: A new 'Random' object is created every time
// a pseudo-random integer is required. // a pseudo-random integer is required.
int notReallyRandom = new Random().nextInt(); int notReallyRandom = new Random().nextInt();
int notReallyRandom2 = new Random().nextInt(); int notReallyRandom2 = new Random().nextInt();
// GOOD: The same 'Random' object is used to generate // GOOD: The same 'Random' object is used to generate
// two pseudo-random integers. // two pseudo-random integers.
Random r = new Random(); Random r = new Random();
int random1 = r.nextInt(); int random1 = r.nextInt();
int random2 = r.nextInt(); int random2 = r.nextInt();
} }

View File

@@ -1,30 +1,30 @@
class LocalCache { class LocalCache {
private Collection<NativeResource> localResources; private Collection<NativeResource> localResources;
//... //...
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
for (NativeResource r : localResources) { for (NativeResource r : localResources) {
r.dispose(); r.dispose();
} }
}; };
} }
class WrongCache extends LocalCache { class WrongCache extends LocalCache {
//... //...
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
// BAD: Empty 'finalize', which does not call 'super.finalize'. // BAD: Empty 'finalize', which does not call 'super.finalize'.
// Native resources in LocalCache are not disposed of. // Native resources in LocalCache are not disposed of.
} }
} }
class RightCache extends LocalCache { class RightCache extends LocalCache {
//... //...
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
// GOOD: 'finalize' calls 'super.finalize'. // GOOD: 'finalize' calls 'super.finalize'.
// Native resources in LocalCache are disposed of. // Native resources in LocalCache are disposed of.
super.finalize(); super.finalize();
} }
} }

View File

@@ -1,21 +1,21 @@
public class BadSuiteMethod extends TestCase { public class BadSuiteMethod extends TestCase {
// BAD: JUnit 3.8 does not detect the following method as a 'suite' method. // BAD: JUnit 3.8 does not detect the following method as a 'suite' method.
// The method should be public, static, and return 'junit.framework.Test' // The method should be public, static, and return 'junit.framework.Test'
// or one of its subtypes. // or one of its subtypes.
static Test suite() { static Test suite() {
TestSuite suite = new TestSuite(); TestSuite suite = new TestSuite();
suite.addTest(new MyTests("testEquals")); suite.addTest(new MyTests("testEquals"));
suite.addTest(new MyTests("testNotEquals")); suite.addTest(new MyTests("testNotEquals"));
return suite; return suite;
} }
} }
public class CorrectSuiteMethod extends TestCase { public class CorrectSuiteMethod extends TestCase {
// GOOD: JUnit 3.8 correctly detects the following method as a 'suite' method. // GOOD: JUnit 3.8 correctly detects the following method as a 'suite' method.
public static Test suite() { public static Test suite() {
TestSuite suite = new TestSuite(); TestSuite suite = new TestSuite();
suite.addTest(new MyTests("testEquals")); suite.addTest(new MyTests("testEquals"));
suite.addTest(new MyTests("testNotEquals")); suite.addTest(new MyTests("testNotEquals"));
return suite; return suite;
} }
} }

View File

@@ -1,65 +1,65 @@
// Abstract class that initializes then shuts down the // Abstract class that initializes then shuts down the
// framework after each set of tests // framework after each set of tests
abstract class FrameworkTestCase extends TestCase { abstract class FrameworkTestCase extends TestCase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
Framework.init(); Framework.init();
} }
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
super.tearDown(); super.tearDown();
Framework.shutdown(); Framework.shutdown();
} }
} }
// The following classes extend 'FrameworkTestCase' to reuse the // The following classes extend 'FrameworkTestCase' to reuse the
// 'setUp' and 'tearDown' methods of the framework. // 'setUp' and 'tearDown' methods of the framework.
public class TearDownNoSuper extends FrameworkTestCase { public class TearDownNoSuper extends FrameworkTestCase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
} }
public void testFramework() { public void testFramework() {
//... //...
} }
public void testFramework2() { public void testFramework2() {
//... //...
} }
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
// BAD: Does not call 'super.tearDown'. May cause later tests to fail // BAD: Does not call 'super.tearDown'. May cause later tests to fail
// when they try to re-initialize an already initialized framework. // when they try to re-initialize an already initialized framework.
// Even if the framework allows re-initialization, it may maintain the // Even if the framework allows re-initialization, it may maintain the
// internal state, which could affect the results of succeeding tests. // internal state, which could affect the results of succeeding tests.
System.out.println("Tests complete"); System.out.println("Tests complete");
} }
} }
public class TearDownSuper extends FrameworkTestCase { public class TearDownSuper extends FrameworkTestCase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
} }
public void testFramework() { public void testFramework() {
//... //...
} }
public void testFramework2() { public void testFramework2() {
//... //...
} }
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
// GOOD: Correctly calls 'super.tearDown' to shut down the // GOOD: Correctly calls 'super.tearDown' to shut down the
// framework. // framework.
System.out.println("Tests complete"); System.out.println("Tests complete");
super.tearDown(); super.tearDown();
} }
} }

View File

@@ -1,28 +1,28 @@
// BAD: This test case class does not have any valid JUnit 3.8 test methods. // BAD: This test case class does not have any valid JUnit 3.8 test methods.
public class TestCaseNoTests38 extends TestCase { public class TestCaseNoTests38 extends TestCase {
// This is not a test case because it does not start with 'test'. // This is not a test case because it does not start with 'test'.
public void simpleTest() { public void simpleTest() {
//... //...
} }
// This is not a test case because it takes two parameters. // This is not a test case because it takes two parameters.
public void testNotEquals(int i, int j) { public void testNotEquals(int i, int j) {
assertEquals(i != j, true); assertEquals(i != j, true);
} }
// This is recognized as a test, but causes JUnit to fail // This is recognized as a test, but causes JUnit to fail
// when run because it is not public. // when run because it is not public.
void testEquals() { void testEquals() {
//... //...
} }
} }
// GOOD: This test case class correctly declares test methods. // GOOD: This test case class correctly declares test methods.
public class MyTests extends TestCase { public class MyTests extends TestCase {
public void testEquals() { public void testEquals() {
assertEquals(1, 1); assertEquals(1, 1);
} }
public void testNotEquals() { public void testNotEquals() {
assertFalse(1 == 2); assertFalse(1 == 2);
} }
} }

View File

@@ -1,14 +1,14 @@
public static void main(String args[]) { public static void main(String args[]) {
String phrase = "I miss my home in Mississippi."; String phrase = "I miss my home in Mississippi.";
// AVOID: Calling 'toLowerCase()' or 'toUpperCase()' // AVOID: Calling 'toLowerCase()' or 'toUpperCase()'
// produces different results depending on what the default locale is. // produces different results depending on what the default locale is.
System.out.println(phrase.toUpperCase()); System.out.println(phrase.toUpperCase());
System.out.println(phrase.toLowerCase()); System.out.println(phrase.toLowerCase());
// GOOD: Explicitly setting the locale when calling 'toLowerCase()' or // GOOD: Explicitly setting the locale when calling 'toLowerCase()' or
// 'toUpperCase()' ensures that the resulting string is // 'toUpperCase()' ensures that the resulting string is
// English, regardless of the default locale. // English, regardless of the default locale.
System.out.println(phrase.toLowerCase(Locale.ENGLISH)); System.out.println(phrase.toLowerCase(Locale.ENGLISH));
System.out.println(phrase.toUpperCase(Locale.ENGLISH)); System.out.println(phrase.toUpperCase(Locale.ENGLISH));
} }

View File

@@ -1,11 +1,11 @@
class WrongNote implements Serializable { class WrongNote implements Serializable {
// BAD: serialVersionUID must be static, final, and 'long' // BAD: serialVersionUID must be static, final, and 'long'
private static final int serialVersionUID = 1; private static final int serialVersionUID = 1;
//... //...
} }
class Note implements Serializable { class Note implements Serializable {
// GOOD: serialVersionUID is of the correct type // GOOD: serialVersionUID is of the correct type
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@@ -1,25 +1,25 @@
class WrongNetRequest implements Serializable { class WrongNetRequest implements Serializable {
// BAD: Does not match the exact signature required for a custom // BAD: Does not match the exact signature required for a custom
// deserialization protocol. Will not be called during deserialization. // deserialization protocol. Will not be called during deserialization.
void readObject(ObjectInputStream in) { void readObject(ObjectInputStream in) {
//... //...
} }
// BAD: Does not match the exact signature required for a custom // BAD: Does not match the exact signature required for a custom
// serialization protocol. Will not be called during serialization. // serialization protocol. Will not be called during serialization.
protected void writeObject(ObjectOutputStream out) { protected void writeObject(ObjectOutputStream out) {
//... //...
} }
} }
class NetRequest implements Serializable { class NetRequest implements Serializable {
// GOOD: Signature for a custom deserialization implementation. // GOOD: Signature for a custom deserialization implementation.
private void readObject(ObjectInputStream in) { private void readObject(ObjectInputStream in) {
//... //...
} }
// GOOD: Signature for a custom serialization implementation. // GOOD: Signature for a custom serialization implementation.
private void writeObject(ObjectOutputStream out) { private void writeObject(ObjectOutputStream out) {
//... //...
} }
} }

View File

@@ -1,37 +1,37 @@
class WrongMemo implements Externalizable { class WrongMemo implements Externalizable {
private String memo; private String memo;
// BAD: No public no-argument constructor is defined. Deserializing this object // BAD: No public no-argument constructor is defined. Deserializing this object
// causes an 'InvalidClassException'. // causes an 'InvalidClassException'.
public WrongMemo(String memo) { public WrongMemo(String memo) {
this.memo = memo; this.memo = memo;
} }
public void writeExternal(ObjectOutput arg0) throws IOException { public void writeExternal(ObjectOutput arg0) throws IOException {
//... //...
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//... //...
} }
} }
class Memo implements Externalizable { class Memo implements Externalizable {
private String memo; private String memo;
// GOOD: Declare a public no-argument constructor, which is used by the // GOOD: Declare a public no-argument constructor, which is used by the
// serialization framework when the object is deserialized. // serialization framework when the object is deserialized.
public Memo() { public Memo() {
} }
public Memo(String memo) { public Memo(String memo) {
this.memo = memo; this.memo = memo;
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
//... //...
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//... //...
} }
} }

View File

@@ -1,42 +1,42 @@
class WrongItem { class WrongItem {
private String name; private String name;
// BAD: This class does not have a no-argument constructor, and throws an // BAD: This class does not have a no-argument constructor, and throws an
// 'InvalidClassException' at runtime. // 'InvalidClassException' at runtime.
public WrongItem(String name) { public WrongItem(String name) {
this.name = name; this.name = name;
} }
} }
class WrongSubItem extends WrongItem implements Serializable { class WrongSubItem extends WrongItem implements Serializable {
public WrongSubItem() { public WrongSubItem() {
super(null); super(null);
} }
public WrongSubItem(String name) { public WrongSubItem(String name) {
super(name); super(name);
} }
} }
class Item { class Item {
private String name; private String name;
// GOOD: This class declares a no-argument constructor, which allows serializable // GOOD: This class declares a no-argument constructor, which allows serializable
// subclasses to be deserialized without error. // subclasses to be deserialized without error.
public Item() {} public Item() {}
public Item(String name) { public Item(String name) {
this.name = name; this.name = name;
} }
} }
class SubItem extends Item implements Serializable { class SubItem extends Item implements Serializable {
public SubItem() { public SubItem() {
super(null); super(null);
} }
public SubItem(String name) { public SubItem(String name) {
super(name); super(name);
} }
} }

View File

@@ -1,16 +1,16 @@
// BAD: This is not serializable, and throws a 'java.io.NotSerializableException' // BAD: This is not serializable, and throws a 'java.io.NotSerializableException'
// when used in a serializable sorted collection. // when used in a serializable sorted collection.
class WrongComparator implements Comparator<String> { class WrongComparator implements Comparator<String> {
public int compare(String o1, String o2) { public int compare(String o1, String o2) {
return o1.compareTo(o2); return o1.compareTo(o2);
} }
} }
// GOOD: This is serializable, and can be used in collections that are meant to be serialized. // GOOD: This is serializable, and can be used in collections that are meant to be serialized.
class StringComparator implements Comparator<String>, Serializable { class StringComparator implements Comparator<String>, Serializable {
private static final long serialVersionUID = -5972458403679726498L; private static final long serialVersionUID = -5972458403679726498L;
public int compare(String arg0, String arg1) { public int compare(String arg0, String arg1) {
return arg0.compareTo(arg1); return arg0.compareTo(arg1);
} }
} }

View File

@@ -1,27 +1,27 @@
class DerivedFactors { // Class that contains derived values computed from entries in a class DerivedFactors { // Class that contains derived values computed from entries in a
private Number efficiency; // performance record private Number efficiency; // performance record
private Number costPerItem; private Number costPerItem;
private Number profitPerItem; private Number profitPerItem;
... ...
} }
class WrongPerformanceRecord implements Serializable { class WrongPerformanceRecord implements Serializable {
private String unitId; private String unitId;
private Number dailyThroughput; private Number dailyThroughput;
private Number dailyCost; private Number dailyCost;
private DerivedFactors factors; // BAD: 'DerivedFactors' is not serializable private DerivedFactors factors; // BAD: 'DerivedFactors' is not serializable
// but is in a serializable class. This // but is in a serializable class. This
// causes a 'java.io.NotSerializableException' // causes a 'java.io.NotSerializableException'
// when 'WrongPerformanceRecord' is serialized. // when 'WrongPerformanceRecord' is serialized.
... ...
} }
class PerformanceRecord implements Serializable { class PerformanceRecord implements Serializable {
private String unitId; private String unitId;
private Number dailyThroughput; private Number dailyThroughput;
private Number dailyCost; private Number dailyCost;
transient private DerivedFactors factors; // GOOD: 'DerivedFactors' is declared transient private DerivedFactors factors; // GOOD: 'DerivedFactors' is declared
// 'transient' so it does not contribute to the // 'transient' so it does not contribute to the
// serializable state of 'PerformanceRecord'. // serializable state of 'PerformanceRecord'.
... ...
} }

View File

@@ -1,29 +1,29 @@
class WrongPair<L, R> implements Serializable{ class WrongPair<L, R> implements Serializable{
private final L left; // BAD private final L left; // BAD
private final R right; // BAD: L and R are not guaranteed to be serializable private final R right; // BAD: L and R are not guaranteed to be serializable
public WrongPair(L left, R right){ ... } public WrongPair(L left, R right){ ... }
... ...
} }
class Pair<L extends Serializable, R extends Serializable> implements Serializable{ class Pair<L extends Serializable, R extends Serializable> implements Serializable{
private final L left; // GOOD: L and R must implement Serializable private final L left; // GOOD: L and R must implement Serializable
private final R right; private final R right;
public Pair(L left, R right){ ... } public Pair(L left, R right){ ... }
... ...
} }
class WrongEvent implements Serializable{ class WrongEvent implements Serializable{
private Object eventData; // BAD: Type is too general. private Object eventData; // BAD: Type is too general.
public WrongEvent(Object eventData){ ... } public WrongEvent(Object eventData){ ... }
} }
class Event implements Serializable{ class Event implements Serializable{
private Serializable eventData; // GOOD: Force the user to supply only serializable data private Serializable eventData; // GOOD: Force the user to supply only serializable data
public Event(Serializable eventData){ ... } public Event(Serializable eventData){ ... }
} }

View File

@@ -1,33 +1,33 @@
class NonSerializableServer { class NonSerializableServer {
// BAD: The following class is serializable, but the enclosing class // BAD: The following class is serializable, but the enclosing class
// 'NonSerializableServer' is not. Serializing an instance of 'WrongSession' // 'NonSerializableServer' is not. Serializing an instance of 'WrongSession'
// causes a 'java.io.NotSerializableException'. // causes a 'java.io.NotSerializableException'.
class WrongSession implements Serializable { class WrongSession implements Serializable {
private static final long serialVersionUID = 8970783971992397218L; private static final long serialVersionUID = 8970783971992397218L;
private int id; private int id;
private String user; private String user;
WrongSession(int id, String user) { /*...*/ } WrongSession(int id, String user) { /*...*/ }
} }
public WrongSession getNewSession(String user) { public WrongSession getNewSession(String user) {
return new WrongSession(newId(), user); return new WrongSession(newId(), user);
} }
} }
class Server { class Server {
// GOOD: The following class can be correctly serialized because it is static. // GOOD: The following class can be correctly serialized because it is static.
static class Session implements Serializable { static class Session implements Serializable {
private static final long serialVersionUID = 1065454318648105638L; private static final long serialVersionUID = 1065454318648105638L;
private int id; private int id;
private String user; private String user;
Session(int id, String user) { /*...*/ } Session(int id, String user) { /*...*/ }
} }
public Session getNewSession(String user) { public Session getNewSession(String user) {
return new Session(newId(), user); return new Session(newId(), user);
} }
} }

View File

@@ -1,40 +1,40 @@
class FalseSingleton implements Serializable { class FalseSingleton implements Serializable {
private static final long serialVersionUID = -7480651116825504381L; private static final long serialVersionUID = -7480651116825504381L;
private static FalseSingleton instance; private static FalseSingleton instance;
private FalseSingleton() {} private FalseSingleton() {}
public static FalseSingleton getInstance() { public static FalseSingleton getInstance() {
if (instance == null) { if (instance == null) {
instance = new FalseSingleton(); instance = new FalseSingleton();
} }
return instance; return instance;
} }
// BAD: Signature of 'readResolve' does not match the exact signature that is expected // BAD: Signature of 'readResolve' does not match the exact signature that is expected
// (that is, it does not return 'java.lang.Object'). // (that is, it does not return 'java.lang.Object').
public FalseSingleton readResolve() throws ObjectStreamException { public FalseSingleton readResolve() throws ObjectStreamException {
return FalseSingleton.getInstance(); return FalseSingleton.getInstance();
} }
} }
class Singleton implements Serializable { class Singleton implements Serializable {
private static final long serialVersionUID = -7480651116825504381L; private static final long serialVersionUID = -7480651116825504381L;
private static Singleton instance; private static Singleton instance;
private Singleton() {} private Singleton() {}
public static Singleton getInstance() { public static Singleton getInstance() {
if (instance == null) { if (instance == null) {
instance = new Singleton(); instance = new Singleton();
} }
return instance; return instance;
} }
// GOOD: Signature of 'readResolve' matches the exact signature that is expected. // GOOD: Signature of 'readResolve' matches the exact signature that is expected.
// It replaces the singleton that is read from a stream with an instance of 'Singleton', // It replaces the singleton that is read from a stream with an instance of 'Singleton',
// instead of creating a new singleton. // instead of creating a new singleton.
private Object readResolve() throws ObjectStreamException { private Object readResolve() throws ObjectStreamException {
return Singleton.getInstance(); return Singleton.getInstance();
} }
} }

View File

@@ -1,12 +1,12 @@
class State { class State {
// The 'transient' modifier has no effect here because // The 'transient' modifier has no effect here because
// the 'State' class does not implement 'Serializable'. // the 'State' class does not implement 'Serializable'.
private transient int[] stateData; private transient int[] stateData;
} }
class PersistentState implements Serializable { class PersistentState implements Serializable {
private int[] stateData; private int[] stateData;
// The 'transient' modifier indicates that this field is not part of // The 'transient' modifier indicates that this field is not part of
// the persistent state and should therefore not be serialized. // the persistent state and should therefore not be serialized.
private transient int[] cachedComputedData; private transient int[] cachedComputedData;
} }

View File

@@ -1,14 +1,14 @@
class FinalizedClass { class FinalizedClass {
Object o = new Object(); Object o = new Object();
String s = "abcdefg"; String s = "abcdefg";
Integer i = Integer.valueOf(2); Integer i = Integer.valueOf(2);
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
super.finalize(); super.finalize();
//No need to nullify fields //No need to nullify fields
this.o = null; this.o = null;
this.s = null; this.s = null;
this.i = null; this.i = null;
} }
} }

View File

@@ -1,9 +1,9 @@
synchronized void waitIfAutoSyncScheduled() { synchronized void waitIfAutoSyncScheduled() {
try { try {
while (isAutoSyncScheduled) { while (isAutoSyncScheduled) {
this.wait(1000); this.wait(1000);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
// Expected exception. The file cannot be synchronized yet. // Expected exception. The file cannot be synchronized yet.
} }
} }

View File

@@ -1,10 +1,10 @@
// Exception is passed to 'ignore' method with a comment // Exception is passed to 'ignore' method with a comment
synchronized void waitIfAutoSyncScheduled() { synchronized void waitIfAutoSyncScheduled() {
try { try {
while (isAutoSyncScheduled) { while (isAutoSyncScheduled) {
this.wait(1000); this.wait(1000);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
Exceptions.ignore(e, "Expected exception. The file cannot be synchronized yet."); Exceptions.ignore(e, "Expected exception. The file cannot be synchronized yet.");
} }
} }

View File

@@ -1,5 +1,5 @@
// 'ignore' method. This method does nothing, but can be called // 'ignore' method. This method does nothing, but can be called
// to document the reason why the exception can be ignored. // to document the reason why the exception can be ignored.
public static void ignore(Throwable e, String message) { public static void ignore(Throwable e, String message) {
} }

View File

@@ -1,8 +1,8 @@
void main() { void main() {
// ... // ...
// BAD: Call to 'runFinalizersOnExit' forces execution of all finalizers on termination of // BAD: Call to 'runFinalizersOnExit' forces execution of all finalizers on termination of
// the runtime, which can cause live objects to transition to an invalid state. // the runtime, which can cause live objects to transition to an invalid state.
// Avoid using this method (and finalizers in general). // Avoid using this method (and finalizers in general).
System.runFinalizersOnExit(true); System.runFinalizersOnExit(true);
// ... // ...
} }

View File

@@ -1,9 +1,9 @@
public static void main(String args[]) { public static void main(String args[]) {
String name = "John Doe"; String name = "John Doe";
// BAD: Unnecessary call to 'toString' on 'name' // BAD: Unnecessary call to 'toString' on 'name'
System.out.println("Hi, my name is " + name.toString()); System.out.println("Hi, my name is " + name.toString());
// GOOD: No call to 'toString' on 'name' // GOOD: No call to 'toString' on 'name'
System.out.println("Hi, my name is " + name); System.out.println("Hi, my name is " + name);
} }

View File

@@ -1,21 +1,21 @@
// This class does not have a 'toString' method, so 'java.lang.Object.toString' // This class does not have a 'toString' method, so 'java.lang.Object.toString'
// is used when the class is converted to a string. // is used when the class is converted to a string.
class WrongPerson { class WrongPerson {
private String name; private String name;
private Date birthDate; private Date birthDate;
public WrongPerson(String name, Date birthDate) { public WrongPerson(String name, Date birthDate) {
this.name =name; this.name =name;
this.birthDate = birthDate; this.birthDate = birthDate;
} }
} }
public static void main(String args[]) throws Exception { public static void main(String args[]) throws Exception {
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
WrongPerson wp = new WrongPerson("Robert Van Winkle", dateFormatter.parse("1967-10-31")); WrongPerson wp = new WrongPerson("Robert Van Winkle", dateFormatter.parse("1967-10-31"));
// BAD: The following statement implicitly calls 'Object.toString', // BAD: The following statement implicitly calls 'Object.toString',
// which returns something similar to: // which returns something similar to:
// WrongPerson@4383f74d // WrongPerson@4383f74d
System.out.println(wp); System.out.println(wp);
} }

View File

@@ -1,15 +1,15 @@
class RequestHandler extends Thread { class RequestHandler extends Thread {
private boolean isRunning; private boolean isRunning;
private Connection conn = new Connection(); private Connection conn = new Connection();
public void run() { public void run() {
while (isRunning) { while (isRunning) {
Request req = conn.getRequest(); Request req = conn.getRequest();
// Process the request ... // Process the request ...
System.gc(); // This call may cause a garbage collection after each request. System.gc(); // This call may cause a garbage collection after each request.
// This will likely reduce the throughput of the RequestHandler // This will likely reduce the throughput of the RequestHandler
// because the JVM spends time on unnecessary garbage collection passes. // because the JVM spends time on unnecessary garbage collection passes.
} }
} }
} }

View File

@@ -1,24 +1,24 @@
public static void main(String args[]) { public static void main(String args[]) {
String[] words = {"Who", "is", "John", "Galt"}; String[] words = {"Who", "is", "John", "Galt"};
String[][] wordMatrix = {{"There", "is"}, {"no", "spoon"}}; String[][] wordMatrix = {{"There", "is"}, {"no", "spoon"}};
// BAD: This implicitly uses 'Object.toString' to convert the contents // BAD: This implicitly uses 'Object.toString' to convert the contents
// of 'words[]', and prints out something similar to: // of 'words[]', and prints out something similar to:
// [Ljava.lang.String;@459189e1 // [Ljava.lang.String;@459189e1
System.out.println(words); System.out.println(words);
// GOOD: 'Arrays.toString' calls 'toString' on // GOOD: 'Arrays.toString' calls 'toString' on
// each of the array's elements. The statement prints out: // each of the array's elements. The statement prints out:
// [Who, is, John, Galt] // [Who, is, John, Galt]
System.out.println(Arrays.toString(words)); System.out.println(Arrays.toString(words));
// ALMOST RIGHT: This calls 'toString' on each of the multi-dimensional // ALMOST RIGHT: This calls 'toString' on each of the multi-dimensional
// array's elements. However, because the elements are arrays, the statement // array's elements. However, because the elements are arrays, the statement
// prints out something similar to: // prints out something similar to:
// [[Ljava.lang.String;@55f33675, [Ljava.lang.String;@527c6768]] // [[Ljava.lang.String;@55f33675, [Ljava.lang.String;@527c6768]]
System.out.println(Arrays.toString(wordMatrix)); System.out.println(Arrays.toString(wordMatrix));
// GOOD: This properly prints out the contents of the multi-dimensional array: // GOOD: This properly prints out the contents of the multi-dimensional array:
// [[There, is], [no, spoon]] // [[There, is], [no, spoon]]
System.out.println(Arrays.deepToString(wordMatrix)); System.out.println(Arrays.deepToString(wordMatrix));
} }

View File

@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?> <?eclipse version="3.2"?>
<plugin> <plugin>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="semmlecode-queries"/> <name value="semmlecode-queries"/>
</extension> </extension>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.java.library"/> <name value="com.semmle.code.java.library"/>
</extension> </extension>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.java.dbscheme"/> <name value="com.semmle.code.java.dbscheme"/>
<path value="/config/semmlecode.dbscheme"/> <path value="/config/semmlecode.dbscheme"/>
</extension> </extension>
</plugin> </plugin>

View File

@@ -0,0 +1 @@
TestWindows.java eol=crlf

View File

@@ -1,22 +1,22 @@
/** /**
* A JavaDoc comment * A JavaDoc comment
* with multiple lines. * with multiple lines.
*/ */
class TestWindows { class TestWindows {
/** A JavaDoc comment with a single line. */ /** A JavaDoc comment with a single line. */
void m() { void m() {
// a single-line comment // a single-line comment
// another single-line comment // another single-line comment
} }
/* A block comment /* A block comment
* with multiple lines. * with multiple lines.
*/ */
/* A block comment with a single line. */ /* A block comment with a single line. */
// an end-of-line comment with a spurious trailing comment marker */ // an end-of-line comment with a spurious trailing comment marker */
// an end-of-line comment with trailing whitespace // an end-of-line comment with trailing whitespace
//an end-of-line comment without a leading space //an end-of-line comment without a leading space
void test() {} // an end-of-line comment with preceding code void test() {} // an end-of-line comment with preceding code
} }

View File

@@ -1,25 +1,25 @@
package successors; package successors;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
public class CloseReaderTest { public class CloseReaderTest {
public static String readPassword(File keyFile) public static String readPassword(File keyFile)
{ {
// TODO: use Console.readPassword() when it's available. // TODO: use Console.readPassword() when it's available.
System.out.print("Enter password for " + keyFile System.out.print("Enter password for " + keyFile
+ " (password will not be hidden): "); + " (password will not be hidden): ");
System.out.flush(); System.out.flush();
BufferedReader stdin = new BufferedReader(new InputStreamReader( BufferedReader stdin = new BufferedReader(new InputStreamReader(
System.in)); System.in));
try try
{ {
return stdin.readLine(); return stdin.readLine();
} catch (IOException ex) } catch (IOException ex)
{ {
return null; return null;
} }
} }
} }

View File

@@ -1,16 +1,16 @@
package successors; package successors;
public class LoopVarReadTest { public class LoopVarReadTest {
public static void testLoop() public static void testLoop()
{ {
int x = 2; int x = 2;
for (int y = 0; y < 10; y += x) for (int y = 0; y < 10; y += x)
{ {
System.out.println("Foo"); System.out.println("Foo");
} }
int q = 10; int q = 10;
System.out.println("foo"); System.out.println("foo");
} }
} }

View File

@@ -1,56 +1,56 @@
package successors; package successors;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
public class SaveFileTest { public class SaveFileTest {
public void saveFile(String path, String contentType, public void saveFile(String path, String contentType,
long size, InputStream is) throws FileNotFoundException, long size, InputStream is) throws FileNotFoundException,
IOException IOException
{ {
String savePath = path; String savePath = path;
if (path.startsWith("/")) if (path.startsWith("/"))
{ {
savePath = path.substring(1); savePath = path.substring(1);
} }
// make sure uploads area exists for this weblog // make sure uploads area exists for this weblog
File dirPath = new File("foo"); File dirPath = new File("foo");
File saveFile = new File(dirPath.getAbsolutePath() + File.separator File saveFile = new File(dirPath.getAbsolutePath() + File.separator
+ savePath); + savePath);
byte[] buffer = new byte[8192]; byte[] buffer = new byte[8192];
int bytesRead = 0; int bytesRead = 0;
OutputStream bos = null; OutputStream bos = null;
try try
{ {
bos = new FileOutputStream(saveFile); bos = new FileOutputStream(saveFile);
while ((bytesRead = is.read(buffer, 0, 8192)) != -1) while ((bytesRead = is.read(buffer, 0, 8192)) != -1)
{ {
bos.write(buffer, 0, bytesRead); bos.write(buffer, 0, bytesRead);
} }
System.out.println("The file has been written to [" System.out.println("The file has been written to ["
+ saveFile.getAbsolutePath() + "]"); + saveFile.getAbsolutePath() + "]");
} catch (Exception e) } catch (Exception e)
{ {
throw new IOException("ERROR uploading file", e); throw new IOException("ERROR uploading file", e);
} finally } finally
{ {
try try
{ {
bos.flush(); bos.flush();
bos.close(); bos.close();
} catch (Exception ignored) } catch (Exception ignored)
{ {
} }
} }
} }
} }

View File

@@ -1,86 +1,86 @@
package successors; package successors;
public class TestBreak { public class TestBreak {
public void f() public void f()
{ {
//loop breaks //loop breaks
a: a:
for (;;) for (;;)
{ {
int x = 1; int x = 1;
x = x + 1; x = x + 1;
if (x == 1) if (x == 1)
{ {
break; break;
} else } else
{ {
for (int q : new int[20]) for (int q : new int[20])
{ {
if (q == 1) if (q == 1)
{ {
break; break;
} else } else
{ {
break a; break a;
} }
} }
} }
} }
int y = 12; int y = 12;
while (true) while (true)
{ {
if (y == 1) if (y == 1)
{ {
break; break;
} else } else
{ {
do do
{ {
if (y == 2) if (y == 2)
{ {
break; break;
} }
y = y + 2; y = y + 2;
} while (y == 1); } while (y == 1);
y = 12; y = 12;
} }
} }
y = 13; y = 13;
//switch breaks //switch breaks
int x =12; int x =12;
switch (x) switch (x)
{ {
case 1: case 1:
x = x + 1; x = x + 1;
y = y + 1; y = y + 1;
case 2: case 2:
x = x + 2; x = x + 2;
y = y + 2; y = y + 2;
break; break;
case 3: case 3:
case 4: case 4:
x = x + 3; x = x + 3;
y = y + 4; y = y + 4;
break; break;
case 5: case 5:
case 6: case 6:
x = x + 5; x = x + 5;
y = y + 6; y = y + 6;
default: default:
x = y; x = y;
y = x; y = x;
} }
//no default //no default
switch(x) switch(x)
{ {
case 1: case 1:
x = 1; x = 1;
break; break;
case 2: case 2:
x = 2; x = 2;
break; break;
} }
} }
} }

View File

@@ -1,59 +1,59 @@
package successors; package successors;
public class TestContinue { public class TestContinue {
public void f() public void f()
{ {
//loop breaks //loop breaks
a: a:
for (int p = 0; p < 10;) for (int p = 0; p < 10;)
{ {
int x = 1; int x = 1;
x = x + 1; x = x + 1;
if (x == 1) if (x == 1)
{ {
continue; continue;
} else } else
{ {
for (int q : new int[20]) for (int q : new int[20])
{ {
if (q == 1) if (q == 1)
{ {
continue; continue;
} else if (q == 2) } else if (q == 2)
{ {
continue a; continue a;
} }
q = 12; q = 12;
} }
} }
} }
int y = 12; int y = 12;
while (y != 13) while (y != 13)
{ {
if (y == 1) if (y == 1)
{ {
continue; continue;
} else } else
{ {
do do
{ {
if (y == 2) if (y == 2)
{ {
continue; continue;
} }
y = y + 2; y = y + 2;
} while (y == 1); } while (y == 1);
y = 12; y = 12;
} }
y = 15; y = 15;
} }
y = 13; y = 13;
while (y != 12) while (y != 12)
{ {
if (y != 6) if (y != 6)
continue; continue;
else else
break; break;
} }
} }
} }

View File

@@ -1,150 +1,150 @@
package successors; package successors;
public class TestFinally { public class TestFinally {
public void f() public void f()
{ {
int z = 12; int z = 12;
try try
{ {
try try
{ {
System.out.println("Try1"); System.out.println("Try1");
if (z == 1) if (z == 1)
{ {
return; return;
} }
try try
{ {
System.out.println("Try1"); System.out.println("Try1");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Try2"); System.out.println("Try2");
} catch (Exception ex) } catch (Exception ex)
{ {
System.out.println("Exception"); System.out.println("Exception");
if (z == 1) if (z == 1)
{ {
return; return;
} }
} finally } finally
{ {
System.out.println("Finally"); System.out.println("Finally");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Finally2"); System.out.println("Finally2");
} }
System.out.println("Try2"); System.out.println("Try2");
} catch (Exception ex) } catch (Exception ex)
{ {
System.out.println("Exception"); System.out.println("Exception");
try try
{ {
System.out.println("Try1"); System.out.println("Try1");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Try2"); System.out.println("Try2");
} catch (Exception ex2) } catch (Exception ex2)
{ {
System.out.println("Exception"); System.out.println("Exception");
if (z == 1) if (z == 1)
{ {
return; return;
} }
} finally } finally
{ {
System.out.println("Finally"); System.out.println("Finally");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Finally2"); System.out.println("Finally2");
} }
if (z == 1) if (z == 1)
{ {
return; return;
} }
} finally } finally
{ {
System.out.println("Finally"); System.out.println("Finally");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Finally2"); System.out.println("Finally2");
} }
System.out.println("Foo"); System.out.println("Foo");
int y = 12 + 3; int y = 12 + 3;
System.out.println("Bar"); System.out.println("Bar");
y = y + 1; y = y + 1;
return; return;
} catch (Exception e) } catch (Exception e)
{ {
try try
{ {
System.out.println("Try1"); System.out.println("Try1");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Try2"); System.out.println("Try2");
} catch (Exception ex) } catch (Exception ex)
{ {
System.out.println("Exception"); System.out.println("Exception");
if (z == 1) if (z == 1)
{ {
return; return;
} }
} finally } finally
{ {
System.out.println("Finally"); System.out.println("Finally");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Finally2"); System.out.println("Finally2");
} }
int x = 1; int x = 1;
System.out.println("Error: " + e); System.out.println("Error: " + e);
x = x + 1; x = x + 1;
} finally } finally
{ {
int y = 12; int y = 12;
System.out.println("Finally"); System.out.println("Finally");
y = y + 1; y = y + 1;
} }
z = z + 1; z = z + 1;
try try
{ {
System.out.println("Try1"); System.out.println("Try1");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Try2"); System.out.println("Try2");
} catch (Exception ex) } catch (Exception ex)
{ {
System.out.println("Exception"); System.out.println("Exception");
if (z == 1) if (z == 1)
{ {
return; return;
} }
} finally } finally
{ {
System.out.println("Finally"); System.out.println("Finally");
if (z == 1) if (z == 1)
{ {
return; return;
} }
System.out.println("Finally2"); System.out.println("Finally2");
} }
z = z + 2; z = z + 2;
} }
} }

View File

@@ -1,108 +1,108 @@
package successors; package successors;
public class TestFinallyBreakContinue { public class TestFinallyBreakContinue {
public void f() public void f()
{ {
int x = 1; int x = 1;
a: a:
for (;;) for (;;)
{ {
try try
{ {
if (x == 1) if (x == 1)
{ {
break; break;
} else } else
{ {
continue; continue;
} }
} catch (Exception e) } catch (Exception e)
{ {
if (x == 1) if (x == 1)
{ {
break; break;
} else } else
{ {
continue; continue;
} }
} finally } finally
{ {
System.out.println("finally"); System.out.println("finally");
} }
} }
while (true) while (true)
{ {
try try
{ {
try try
{ {
if (x == 1) if (x == 1)
{ {
break; break;
} else } else
{ {
continue; continue;
} }
} catch (Exception e) } catch (Exception e)
{ {
if (x == 1) if (x == 1)
{ {
break; break;
} else } else
{ {
continue; continue;
} }
} finally } finally
{ {
System.out.println("finally"); System.out.println("finally");
} }
} catch (Exception e) } catch (Exception e)
{ {
System.out.println("Exception"); System.out.println("Exception");
} finally } finally
{ {
System.out.println("finally"); System.out.println("finally");
} }
} }
b: b:
do do
{ {
try try
{ {
for (int i : new int[20]) for (int i : new int[20])
{ {
try try
{ {
if (x == 1) if (x == 1)
{ {
break; break;
} else } else
{ {
continue; continue;
} }
} catch (Exception e) } catch (Exception e)
{ {
if (x == 1) if (x == 1)
{ {
break b; break b;
} else } else
{ {
continue b; continue b;
} }
} finally } finally
{ {
System.out.println("finally"); System.out.println("finally");
} }
} }
} catch (Exception e) } catch (Exception e)
{ {
System.out.println("Exception"); System.out.println("Exception");
} finally } finally
{ {
System.out.println("finally"); System.out.println("finally");
} }
} while (true); } while (true);
} }
} }

View File

@@ -1,120 +1,120 @@
package successors; package successors;
public class TestLoopBranch { public class TestLoopBranch {
int xx = 12; int xx = 12;
int yy = 13; int yy = 13;
public void f() public void f()
{ {
int x = 1; int x = 1;
int y = 2; int y = 2;
System.out.println("foo"); System.out.println("foo");
do do
{ {
System.out.println("bar"); System.out.println("bar");
System.out.println("foobar"); System.out.println("foobar");
} while (x == 2); } while (x == 2);
{ {
System.out.println("shazam"); System.out.println("shazam");
System.out.println("boogie"); System.out.println("boogie");
} }
while (x == 1) while (x == 1)
{ {
System.out.println("wonderland"); System.out.println("wonderland");
System.out.println("shodan"); System.out.println("shodan");
x = x + 1; x = x + 1;
} }
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
System.out.println("rapture"); System.out.println("rapture");
y = x - 2; y = x - 2;
} }
; ;
; ;
for (int j : new int[20]) for (int j : new int[20])
{ {
System.out.println("Zero : " + j); System.out.println("Zero : " + j);
j = j + x; j = j + x;
} }
if (y == -1) if (y == -1)
{ {
System.out.println("i squared"); System.out.println("i squared");
} }
if (x == 42) if (x == 42)
{ {
System.out.println("rat"); System.out.println("rat");
x = 6 * 9; x = 6 * 9;
} else } else
{ {
System.out.println("arr"); System.out.println("arr");
x = y * x; x = y * x;
return; return;
} }
switch (x) switch (x)
{ {
case 1: case 1:
x = x + 1; x = x + 1;
y = y + 1; y = y + 1;
case 2: case 2:
x = x + 2; x = x + 2;
y = y + 2; y = y + 2;
break; break;
case 3: case 3:
case 4: case 4:
x = x + 3; x = x + 3;
y = y + 4; y = y + 4;
break; break;
case 5: case 5:
case 6: case 6:
x = x + 5; x = x + 5;
y = y + 6; y = y + 6;
default: default:
x = y; x = y;
y = x; y = x;
} }
//no default //no default
switch(x) switch(x)
{ {
case 1: case 1:
x = 1; x = 1;
break; break;
case 2: case 2:
x = 2; x = 2;
break; break;
} }
Comparable<String> b = new Comparable<String>() { Comparable<String> b = new Comparable<String>() {
@Override @Override
public int compareTo(String o) public int compareTo(String o)
{ {
return 0; return 0;
} }
}; };
b.compareTo("Foo"); b.compareTo("Foo");
x = x + y; x = x + y;
return; return;
} }
public TestLoopBranch() public TestLoopBranch()
{ {
xx = 33; xx = 33;
yy = 44; yy = 44;
} }
public TestLoopBranch(int i) public TestLoopBranch(int i)
{ {
xx = i; xx = i;
yy = i; yy = i;
} }
} }

View File

@@ -1,135 +1,135 @@
package successors; package successors;
import java.io.IOException; import java.io.IOException;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
public class TestThrow { public class TestThrow {
private TestThrow() throws IOException private TestThrow() throws IOException
{ {
} }
private void thrower() throws InvalidParameterException private void thrower() throws InvalidParameterException
{ {
} }
public void f() throws Exception public void f() throws Exception
{ {
int z = 0; int z = 0;
try try
{ {
throw new RuntimeException(); throw new RuntimeException();
} catch (RuntimeException e) } catch (RuntimeException e)
{ {
z = 1; z = 1;
} catch (Exception e) } catch (Exception e)
{ {
z = 2; z = 2;
} }
z = -1; z = -1;
try try
{ {
if (z == 1) if (z == 1)
{ {
throw new RuntimeException(); throw new RuntimeException();
} else if (z == 2) } else if (z == 2)
{ {
throw new Exception(); throw new Exception();
} else if (z == 3) } else if (z == 3)
{ {
new TestThrow(); new TestThrow();
} else } else
{ {
thrower(); thrower();
} }
} catch (RuntimeException e) } catch (RuntimeException e)
{ {
z = 1; z = 1;
} finally } finally
{ {
z = 2; z = 2;
} }
z = -1; z = -1;
try try
{ {
if (z == 1) if (z == 1)
{ {
throw new Exception(); throw new Exception();
} }
else if (z == 2) else if (z == 2)
{ {
new TestThrow(); new TestThrow();
} else } else
{ {
thrower(); thrower();
} }
} catch (RuntimeException e) } catch (RuntimeException e)
{ {
z = 1; z = 1;
} }
z = -1; z = -1;
try try
{ {
if (z == 1) if (z == 1)
throw new Exception(); throw new Exception();
} finally } finally
{ {
z = 1; z = 1;
} }
try try
{ {
try try
{ {
if (z == 1) if (z == 1)
{ {
throw new Exception(); throw new Exception();
} else if (z == 2) } else if (z == 2)
{ {
throw new RuntimeException(); throw new RuntimeException();
} else } else
{ {
throw new IOException("Foo bar", null); throw new IOException("Foo bar", null);
} }
} catch (RuntimeException e) } catch (RuntimeException e)
{ {
z = 1; z = 1;
} }
try try
{ {
z = -2; z = -2;
} finally } finally
{ {
if (z == 1) if (z == 1)
{ {
throw new Exception(); throw new Exception();
} else if (z == 2) } else if (z == 2)
{ {
throw new RuntimeException(); throw new RuntimeException();
} else if (z == 3) } else if (z == 3)
{ {
throw new IOException("Foo bar", null); throw new IOException("Foo bar", null);
} }
} }
} catch (IOException e) } catch (IOException e)
{ {
z = 2; z = 2;
} }
finally finally
{ {
z = 3; z = 3;
} }
if (z == 1) if (z == 1)
{ {
throw new Exception(); throw new Exception();
} }
z = -1; z = -1;
} }
} }

View File

@@ -1,44 +1,44 @@
package successors; package successors;
public class TestTryCatch { public class TestTryCatch {
public void f() public void f()
{ {
try try
{ {
System.out.println("Foo"); System.out.println("Foo");
int y = 12 + 3; int y = 12 + 3;
System.out.println("Bar"); System.out.println("Bar");
y = y + 1; y = y + 1;
} catch (Exception e) } catch (Exception e)
{ {
int x = 1; int x = 1;
System.out.println("Error: " + e); System.out.println("Error: " + e);
x = x + 1; x = x + 1;
return; return;
} finally } finally
{ {
int y = 12; int y = 12;
System.out.println("Finally"); System.out.println("Finally");
y = y + 1; y = y + 1;
} }
int z = 12; int z = 12;
z = z + 1; z = z + 1;
for (int q = 0; q < 10; q++) for (int q = 0; q < 10; q++)
{ {
try try
{ {
System.out.println("Foo"); System.out.println("Foo");
int y = 12 + 3; int y = 12 + 3;
System.out.println("Bar"); System.out.println("Bar");
y = y + 1; y = y + 1;
} catch (RuntimeException e) } catch (RuntimeException e)
{ {
int x = 1; int x = 1;
System.out.println("Error: " + e); System.out.println("Error: " + e);
x = x + 1; x = x + 1;
} }
} }
z = z + 2; z = z + 2;
} }
} }

View File

@@ -0,0 +1 @@
TestWindows.java eol=crlf

View File

@@ -1,28 +1,28 @@
class TestWindows {} // lgtm class TestWindows {} // lgtm
// lgtm[java/confusing-method-name] // lgtm[java/confusing-method-name]
// lgtm[java/confusing-method-name, java/non-short-circuit-evaluation] // lgtm[java/confusing-method-name, java/non-short-circuit-evaluation]
// lgtm[@tag:exceptions] // lgtm[@tag:exceptions]
// lgtm[@tag:exceptions,java/confusing-method-name] // lgtm[@tag:exceptions,java/confusing-method-name]
// lgtm[@expires:2017-06-11] // lgtm[@expires:2017-06-11]
// lgtm[java/confusing-method-name] does not seem confusing despite alert by lgtm // lgtm[java/confusing-method-name] does not seem confusing despite alert by lgtm
// lgtm: blah blah // lgtm: blah blah
// lgtm blah blah #falsepositive // lgtm blah blah #falsepositive
//lgtm [java/confusing-method-name] //lgtm [java/confusing-method-name]
/* lgtm */ /* lgtm */
// lgtm[] // lgtm[]
// lgtmfoo // lgtmfoo
//lgtm //lgtm
// lgtm // lgtm
// lgtm [java/confusing-method-name] // lgtm [java/confusing-method-name]
// foolgtm[java/confusing-method-name] // foolgtm[java/confusing-method-name]
// foolgtm // foolgtm
// foo; lgtm // foo; lgtm
// foo; lgtm[java/confusing-method-name] // foo; lgtm[java/confusing-method-name]
// foo lgtm // foo lgtm
// foo lgtm[java/confusing-method-name] // foo lgtm[java/confusing-method-name]
// foo lgtm bar // foo lgtm bar
// foo lgtm[java/confusing-method-name] bar // foo lgtm[java/confusing-method-name] bar
// LGTM! // LGTM!
// LGTM[java/confusing-method-name] // LGTM[java/confusing-method-name]
//lgtm[java/confusing-method-name] and lgtm[java/non-short-circuit-evaluation] //lgtm[java/confusing-method-name] and lgtm[java/non-short-circuit-evaluation]
//lgtm[java/confusing-method-name]; lgtm //lgtm[java/confusing-method-name]; lgtm

View File

@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?> <?eclipse version="3.2"?>
<plugin> <plugin>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="semmlecode-javascript-queries"/> <name value="semmlecode-javascript-queries"/>
</extension> </extension>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.javascript.library"/> <name value="com.semmle.code.javascript.library"/>
</extension> </extension>
<extension point="com.semmle.plugin.qdt.ui.resources"> <extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.javascript.dbscheme"/> <name value="com.semmle.code.javascript.dbscheme"/>
<path value="/semmlecode.javascript.dbscheme"/> <path value="/semmlecode.javascript.dbscheme"/>
</extension> </extension>
</plugin> </plugin>